Merge "Adds install source checks for accessibility service" into sc-dev

This commit is contained in:
Lucy Chang
2021-04-29 10:17:05 +00:00
committed by Android (Google) Code Review
4 changed files with 156 additions and 30 deletions

View File

@@ -4892,4 +4892,7 @@
<bool name="config_supportsMicToggle">false</bool>
<!-- Whether this device is supporting the camera toggle -->
<bool name="config_supportsCamToggle">false</bool>
<!-- List containing the allowed install sources for accessibility service. -->
<string-array name="config_accessibility_allowed_install_source" translatable="false"/>
</resources>

View File

@@ -4357,6 +4357,8 @@
<java-symbol type="drawable" name="ic_accessibility_24dp" />
<java-symbol type="string" name="view_and_control_notification_title" />
<java-symbol type="string" name="view_and_control_notification_content" />
<java-symbol type="array" name="config_accessibility_allowed_install_source" />
<!-- Translation -->
<java-symbol type="string" name="ui_translation_accessibility_translated_text" />
<java-symbol type="string" name="ui_translation_accessibility_translation_finished" />

View File

@@ -16,6 +16,8 @@
package com.android.server.accessibility;
import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
@@ -24,7 +26,9 @@ import android.app.AppOpsManager;
import android.appwidget.AppWidgetManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
@@ -33,11 +37,13 @@ import android.os.IBinder;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import libcore.util.EmptyArray;
@@ -666,13 +672,66 @@ public class AccessibilitySecurityPolicy {
/**
* Identifies whether the accessibility service is true and designed for accessibility. An
* accessibility service is considered as accessibility category if
* {@link AccessibilityServiceInfo#isAccessibilityTool} is true.
* accessibility service is considered as accessibility category if meets all conditions below:
* <ul>
* <li> {@link AccessibilityServiceInfo#isAccessibilityTool} is true</li>
* <li> is installed from the trusted install source</li>
* </ul>
*
* @param serviceInfo The accessibility service's serviceInfo.
* @return Returns true if it is a true accessibility service.
*/
public boolean isA11yCategoryService(AccessibilityServiceInfo serviceInfo) {
return serviceInfo.isAccessibilityTool();
if (!serviceInfo.isAccessibilityTool()) {
return false;
}
if (!serviceInfo.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
return hasTrustedSystemInstallSource(
serviceInfo.getResolveInfo().serviceInfo.packageName);
}
return true;
}
/** Returns true if the {@code installedPackage} is installed from the trusted install source.
*/
private boolean hasTrustedSystemInstallSource(String installedPackage) {
try {
InstallSourceInfo installSourceInfo = mPackageManager.getInstallSourceInfo(
installedPackage);
if (installSourceInfo == null) {
return false;
}
final String installSourcePackageName = installSourceInfo.getInitiatingPackageName();
if (installSourcePackageName == null || !mPackageManager.getPackageInfo(
installSourcePackageName,
0).applicationInfo.isSystemApp()) {
return false;
}
return isTrustedInstallSource(installSourcePackageName);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(LOG_TAG, "can't find the package's install source:" + installedPackage);
}
return false;
}
/** Returns true if the {@code installerPackage} is a trusted install source. */
private boolean isTrustedInstallSource(String installerPackage) {
final String[] allowedInstallingSources = mContext.getResources().getStringArray(
com.android.internal.R.array
.config_accessibility_allowed_install_source);
if (allowedInstallingSources.length == 0) {
//Filters unwanted default installers if no allowed install sources.
String defaultInstaller = ArrayUtils.firstOrNull(LocalServices.getService(
PackageManagerInternal.class).getKnownPackageNames(PACKAGE_INSTALLER,
mCurrentUserId));
return !TextUtils.equals(defaultInstaller, installerPackage);
}
for (int i = 0; i < allowedInstallingSources.length; i++) {
if (TextUtils.equals(allowedInstallingSources[i], installerPackage)) {
return true;
}
}
return false;
}
}

View File

@@ -43,9 +43,12 @@ import android.appwidget.AppWidgetManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SigningInfo;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -81,8 +84,10 @@ public class AccessibilitySecurityPolicyTest {
private static final int APP_PID = 2000;
private static final int SYSTEM_PID = 558;
private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
private static final String TEST_PACKAGE_NAME = "com.android.server.accessibility";
private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
"com.android.server.accessibility", "AccessibilitySecurityPolicyTest");
TEST_PACKAGE_NAME, "AccessibilitySecurityPolicyTest");
private static final String ALLOWED_INSTALL_PACKAGE_NAME = "com.allowed.install.package";
private static final int[] ALWAYS_DISPATCH_EVENTS = {
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
@@ -142,19 +147,40 @@ public class AccessibilitySecurityPolicyTest {
@Mock
private AccessibilityServiceInfo mMockA11yServiceInfo;
@Mock
private ResolveInfo mMockResolveInfo;
@Mock
private ServiceInfo mMockServiceInfo;
@Mock
private ApplicationInfo mMockApplicationInfo;
@Mock
private ApplicationInfo mMockSourceApplicationInfo;
@Mock
private PackageInfo mMockSourcePackageInfo;
@Mock
private PolicyWarningUIController mPolicyWarningUIController;
@Before
public void setUp() {
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext.setMockPackageManager(mMockPackageManager);
mContext.addMockSystemService(Context.USER_SERVICE, mMockUserManager);
mContext.addMockSystemService(Context.APP_OPS_SERVICE, mMockAppOpsManager);
mContext.getOrCreateTestableResources().addOverride(
R.dimen.accessibility_focus_highlight_stroke_width, 1);
mContext.getOrCreateTestableResources().addOverride(R.array
.config_accessibility_allowed_install_source,
new String[]{ALLOWED_INSTALL_PACKAGE_NAME});
when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
when(mMockA11yServiceConnection.getServiceInfo()).thenReturn(mMockA11yServiceInfo);
when(mMockPackageManager.getPackageInfo(ALLOWED_INSTALL_PACKAGE_NAME, 0)).thenReturn(
mMockSourcePackageInfo);
mMockResolveInfo.serviceInfo = mMockServiceInfo;
mMockServiceInfo.applicationInfo = mMockApplicationInfo;
mMockServiceInfo.packageName = TEST_PACKAGE_NAME;
mMockSourcePackageInfo.applicationInfo = mMockSourceApplicationInfo;
mA11ySecurityPolicy = new AccessibilitySecurityPolicy(
mPolicyWarningUIController, mContext, mMockA11yUserManager);
@@ -595,28 +621,7 @@ public class AccessibilitySecurityPolicyTest {
}
@Test
public void onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction() {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
}
@Test
public void onBoundServicesChanged_unbindA11yCategoryService_noUIControllerAction() {
onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction();
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
any());
}
@Test
public void onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction() {
public void onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction() {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false);
@@ -628,8 +633,8 @@ public class AccessibilitySecurityPolicyTest {
}
@Test
public void onBoundServicesChanged_unbindNonA11yCategoryService_activateUIControllerAction() {
onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction();
public void onBoundServicesChanged_unbindNonA11yToolService_activateUIControllerAction() {
onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction();
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
@@ -637,9 +642,66 @@ public class AccessibilitySecurityPolicyTest {
eq(TEST_COMPONENT_NAME));
}
@Test
public void onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction() {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
when(mMockApplicationInfo.isSystemApp()).thenReturn(true);
when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
}
@Test
public void onBoundServicesChanged_unbindSystemA11yToolService_noUIControllerAction() {
onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction();
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
any());
}
@Test
public void onBoundServicesChanged_bindAllowedSourceA11yToolService_noUIControllerAction()
throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
when(mMockApplicationInfo.isSystemApp()).thenReturn(false);
final InstallSourceInfo installSourceInfo = new InstallSourceInfo(
ALLOWED_INSTALL_PACKAGE_NAME, new SigningInfo(), null,
ALLOWED_INSTALL_PACKAGE_NAME);
when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn(
installSourceInfo);
when(mMockSourceApplicationInfo.isSystemApp()).thenReturn(true);
when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
}
@Test
public void onBoundServicesChanged_bindUnknownSourceA11yToolService_activateUIControllerAction()
throws PackageManager.NameNotFoundException {
final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
boundServices.add(mMockA11yServiceConnection);
when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
final InstallSourceInfo installSourceInfo = new InstallSourceInfo(null, null, null, null);
when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn(
installSourceInfo);
mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID),
eq(TEST_COMPONENT_NAME));
}
@Test
public void onSwitchUser_differentUser_activateUIControllerAction() {
onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction();
onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction();
mA11ySecurityPolicy.onSwitchUserLocked(2, new HashSet<>());