summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java11
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java109
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java2
7 files changed, 116 insertions, 18 deletions
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 363c37b9e203..a23277eddf2b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3201,6 +3201,11 @@
<permission android:name="android.permission.MODIFY_ACCESSIBILITY_DATA"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to perform accessibility operations (e.g. send events) on
+ behalf of another package. -->
+ <permission android:name="android.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to change the accessibility volume. -->
<permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME"
android:protectionLevel="signature" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 133d375b8c6e..37900fb13496 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -219,6 +219,7 @@
<!-- accessibility -->
<uses-permission android:name="android.permission.MODIFY_ACCESSIBILITY_DATA" />
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
+ <uses-permission android:name="android.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY" />
<!-- to control accessibility volume -->
<uses-permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" />
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fe5d4533a598..20850af97429 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -603,7 +603,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// Make sure the reported package is one the caller has access to.
event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
- event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId));
+ event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId,
+ getCallingPid()));
// This method does nothing for a background user.
if (resolvedUserId == mCurrentUserId) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index d98e31eadb22..41f32075fb77 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -167,11 +167,12 @@ public class AccessibilitySecurityPolicy {
* @param packageName The package name the app wants to expose
* @param appId The app's id
* @param userId The app's user id
+ * @param pid The app's process pid that requested this
* @return A package name that is valid to report
*/
@Nullable
public String resolveValidReportedPackageLocked(
- @Nullable CharSequence packageName, int appId, int userId) {
+ @Nullable CharSequence packageName, int appId, int userId, int pid) {
// Okay to pass no package
if (packageName == null) {
return null;
@@ -191,6 +192,11 @@ public class AccessibilitySecurityPolicy {
.getHostedWidgetPackages(resolvedUid), packageNameStr)) {
return packageName.toString();
}
+ // If app has the targeted permission to act as another package
+ if (mContext.checkPermission(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY,
+ pid, resolvedUid) == PackageManager.PERMISSION_GRANTED) {
+ return packageName.toString();
+ }
// Otherwise, set the package to the first one in the UID
final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
if (ArrayUtils.isEmpty(packageNames)) {
@@ -403,8 +409,7 @@ public class AccessibilitySecurityPolicy {
|| userId == UserHandle.USER_CURRENT_OR_SELF) {
return currentUserId;
}
- throw new IllegalArgumentException("Calling user can be changed to only "
- + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
+ return resolveProfileParentLocked(userId);
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 5d97d213928f..468e93a8f683 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -955,7 +955,8 @@ public class AccessibilityWindowManager {
// Makes sure the reported package is one the caller has access to.
packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
- packageName, UserHandle.getCallingAppId(), resolvedUserId);
+ packageName, UserHandle.getCallingAppId(), resolvedUserId,
+ Binder.getCallingPid());
windowId = sNextWindowId++;
// If the window is from a process that runs across users such as
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index 5a96347c4ae1..cc8ac86d6b59 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -28,10 +28,12 @@ import static org.junit.Assert.assertThat;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.AppOpsManager;
import android.appwidget.AppWidgetManagerInternal;
@@ -71,6 +73,8 @@ public class AccessibilitySecurityPolicyTest {
private static final int WINDOWID = 0x000a;
private static final int WINDOWID2 = 0x000b;
private static final int APP_UID = 10400;
+ private static final int APP_PID = 2000;
+ private static final int SYSTEM_PID = 558;
private static final String PERMISSION = "test-permission";
private static final String FUNCTION = "test-function-name";
@@ -196,13 +200,13 @@ public class AccessibilitySecurityPolicyTest {
@Test
public void resolveValidReportedPackage_nullPkgName_returnNull() {
assertNull(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
- null, Process.SYSTEM_UID, UserHandle.USER_SYSTEM));
+ null, Process.SYSTEM_UID, UserHandle.USER_SYSTEM, SYSTEM_PID));
}
@Test
public void resolveValidReportedPackage_uidIsSystem_returnPkgName() {
assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
- PACKAGE_NAME, Process.SYSTEM_UID, UserHandle.USER_SYSTEM),
+ PACKAGE_NAME, Process.SYSTEM_UID, UserHandle.USER_SYSTEM, SYSTEM_PID),
PACKAGE_NAME);
}
@@ -213,7 +217,7 @@ public class AccessibilitySecurityPolicyTest {
.thenReturn(APP_UID);
assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
- PACKAGE_NAME, APP_UID, UserHandle.USER_SYSTEM),
+ PACKAGE_NAME, APP_UID, UserHandle.USER_SYSTEM, APP_PID),
PACKAGE_NAME);
}
@@ -221,6 +225,7 @@ public class AccessibilitySecurityPolicyTest {
public void resolveValidReportedPackage_uidIsWidgetHost_pkgNameIsAppWidget_returnPkgName()
throws PackageManager.NameNotFoundException {
final int widgetHostUid = APP_UID;
+ final int widgetHostPid = APP_PID;
final String hostPackageName = PACKAGE_NAME;
final String widgetPackageName = PACKAGE_NAME2;
final ArraySet<String> widgetPackages = new ArraySet<>();
@@ -232,7 +237,7 @@ public class AccessibilitySecurityPolicyTest {
.thenReturn(widgetHostUid);
assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
- widgetPackageName, widgetHostUid, UserHandle.USER_SYSTEM),
+ widgetPackageName, widgetHostUid, UserHandle.USER_SYSTEM, widgetHostPid),
widgetPackageName);
}
@@ -247,10 +252,52 @@ public class AccessibilitySecurityPolicyTest {
.thenThrow(PackageManager.NameNotFoundException.class);
when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
.thenReturn(new ArraySet<>());
+ when(mMockContext.checkPermission(
+ eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
- assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
- invalidPackageName, APP_UID, UserHandle.USER_SYSTEM),
- PACKAGE_NAME);
+ assertEquals(PACKAGE_NAME, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
+ invalidPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
+ }
+
+ @Test
+ public void resolveValidReportedPackage_anotherPkgNameWithActAsPkgPermission_returnPkg()
+ throws PackageManager.NameNotFoundException {
+ final String wantedPackageName = PACKAGE_NAME2;
+ final int wantedUid = APP_UID + 1;
+ final String[] uidPackages = {PACKAGE_NAME};
+ when(mMockPackageManager.getPackagesForUid(APP_UID))
+ .thenReturn(uidPackages);
+ when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, UserHandle.USER_SYSTEM))
+ .thenReturn(wantedUid);
+ when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
+ .thenReturn(new ArraySet<>());
+ when(mMockContext.checkPermission(
+ eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ assertEquals(wantedPackageName, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
+ wantedPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
+ }
+
+ @Test
+ public void resolveValidReportedPackage_anotherPkgNameWithoutActAsPkgPermission_returnUidPkg()
+ throws PackageManager.NameNotFoundException {
+ final String wantedPackageName = PACKAGE_NAME2;
+ final int wantedUid = APP_UID + 1;
+ final String[] uidPackages = {PACKAGE_NAME};
+ when(mMockPackageManager.getPackagesForUid(APP_UID))
+ .thenReturn(uidPackages);
+ when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, UserHandle.USER_SYSTEM))
+ .thenReturn(wantedUid);
+ when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
+ .thenReturn(new ArraySet<>());
+ when(mMockContext.checkPermission(
+ eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ assertEquals(PACKAGE_NAME, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
+ wantedPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
}
@Test
@@ -432,21 +479,59 @@ public class AccessibilitySecurityPolicyTest {
UserHandle.USER_CURRENT_OR_SELF);
}
- @Test(expected = IllegalArgumentException.class)
- public void resolveCallingUserId_callingParentNotCurrentUser_userIdIsInvalid_shouldException() {
+ @Test
+ public void resolveCallingUserId_anotherUserIdWithCrossUserPermission_returnUserId() {
final AccessibilitySecurityPolicy spySecurityPolicy = Mockito.spy(mA11ySecurityPolicy);
final int callingUserId = UserHandle.getUserId(Process.myUid());
final int callingParentId = 20;
final int currentUserId = 30;
- final int invalidUserId = 40;
+ final int wantedUserId = 40;
when(mMockA11yUserManager.getCurrentUserIdLocked())
.thenReturn(currentUserId);
doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
callingUserId);
- when(mMockContext.checkCallingPermission(any()))
+ when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ assertEquals(wantedUserId,
+ spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId));
+ }
+
+ @Test
+ public void resolveCallingUserId_anotherUserIdWithCrossUserFullPermission_returnUserId() {
+ final AccessibilitySecurityPolicy spySecurityPolicy = Mockito.spy(mA11ySecurityPolicy);
+ final int callingUserId = UserHandle.getUserId(Process.myUid());
+ final int callingParentId = 20;
+ final int currentUserId = 30;
+ final int wantedUserId = 40;
+ when(mMockA11yUserManager.getCurrentUserIdLocked())
+ .thenReturn(currentUserId);
+ doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
+ callingUserId);
+ when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(invalidUserId);
+ assertEquals(wantedUserId,
+ spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId));
+ }
+
+ @Test(expected = SecurityException.class)
+ public void resolveCallingUserId_anotherUserIdWithoutCrossUserPermission_shouldException() {
+ final AccessibilitySecurityPolicy spySecurityPolicy = Mockito.spy(mA11ySecurityPolicy);
+ final int callingUserId = UserHandle.getUserId(Process.myUid());
+ final int callingParentId = 20;
+ final int currentUserId = 30;
+ final int wantedUserId = 40;
+ when(mMockA11yUserManager.getCurrentUserIdLocked())
+ .thenReturn(currentUserId);
+ doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
+ callingUserId);
+ when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 10a86f9ea527..e4d51e4374a7 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -134,7 +134,7 @@ public class AccessibilityWindowManagerTest {
when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
- anyString(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
+ anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
mMockWindowManagerInternal,