Merge "Allow sysUI to send a11y events for other package and user" into rvc-dev am: 78b06a4129 am: a71c8667c8 am: 1bb37c6c10
Change-Id: I84d621e34a76465c19540219af6083ef7cb9389c
This commit is contained in:
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(invalidUserId);
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user