Exempt mgmt role holder from quiet mode suspension

This is accomplished via two changes:
1. SuspendPackageHelper now filter mgmt role holder out from the list of
   packages to suspend for quiet mode.
2. When "Keep profiles running" feature is enabled,
   ActivityStartInterceptor checks suspended state in addition to quiet
   mode, so if package is not suspended, its activities can be launched.

Bug: 284108214
Test: atest SuspendPackageHelperTest
Test: atest WmTests:ActivityStartInterceptorTest
Test: atest CtsDevicePolicyTestCases:android.devicepolicy.cts.QuietModeTest
Change-Id: I9b70a548db8dd5d3e1ade66464a5d05e2118025a
This commit is contained in:
Pavel Grafov
2023-05-24 15:21:32 +01:00
parent 91e4b9de52
commit 95a97c2647
6 changed files with 62 additions and 9 deletions

View File

@@ -3409,7 +3409,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Nullable
private String getDevicePolicyManagementRoleHolderPackageName(int userId) {
public String getDevicePolicyManagementRoleHolderPackageName(int userId) {
return Binder.withCleanCallingIdentity(() -> {
RoleManager roleManager = mContext.getSystemService(RoleManager.class);
List<String> roleHolders =

View File

@@ -724,6 +724,10 @@ public final class SuspendPackageHelper {
for (PackageInfo info : pkgInfos) {
result.add(info.packageName);
}
// Role holder may be null, but ArraySet handles it correctly.
result.remove(mPm.getDevicePolicyManagementRoleHolderPackageName(userId));
return result;
}

View File

@@ -280,6 +280,10 @@ class ActivityStartInterceptor {
return false;
}
if (isKeepProfilesRunningEnabled() && !isPackageSuspended()) {
return false;
}
IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
@@ -322,8 +326,7 @@ class ActivityStartInterceptor {
private boolean interceptSuspendedPackageIfNeeded() {
// Do not intercept if the package is not suspended
if (mAInfo == null || mAInfo.applicationInfo == null ||
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
if (!isPackageSuspended()) {
return false;
}
final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
@@ -467,6 +470,17 @@ class ActivityStartInterceptor {
return true;
}
private boolean isPackageSuspended() {
return mAInfo != null && mAInfo.applicationInfo != null
&& (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) != 0;
}
private static boolean isKeepProfilesRunningEnabled() {
DevicePolicyManagerInternal dpmi =
LocalServices.getService(DevicePolicyManagerInternal.class);
return dpmi == null || dpmi.isKeepProfilesRunningEnabled();
}
/**
* Called when an activity is successfully launched.
*/

View File

@@ -48,6 +48,7 @@ open class PackageHelperTestBase {
const val UNINSTALLER_PACKAGE = "com.android.test.known.uninstaller"
const val VERIFIER_PACKAGE = "com.android.test.known.verifier"
const val PERMISSION_CONTROLLER_PACKAGE = "com.android.test.known.permission"
const val MGMT_ROLE_HOLDER_PACKAGE = "com.android.test.know.device_management"
const val TEST_USER_ID = 0
}
@@ -119,6 +120,8 @@ open class PackageHelperTestBase {
Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
.getKnownPackageNamesInternal(any(),
eq(KnownPackages.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
Mockito.doReturn(MGMT_ROLE_HOLDER_PACKAGE).`when`(pms)
.getDevicePolicyManagementRoleHolderPackageName(eq(TEST_USER_ID))
}
private fun createPackageManagerService(vararg stageExistingPackages: String):

View File

@@ -128,13 +128,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_forQuietMode() {
val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE,
PERMISSION_CONTROLLER_PACKAGE)
PERMISSION_CONTROLLER_PACKAGE, MGMT_ROLE_HOLDER_PACKAGE)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
knownPackages, true /* suspended */, null /* appExtras */,
null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, true /* forQuietMode */)!!
assertThat(failedNames.size).isEqualTo(0)
assertThat(failedNames.size).isEqualTo(1)
assertThat(failedNames[0]).isEqualTo(MGMT_ROLE_HOLDER_PACKAGE)
}
@Test

View File

@@ -250,9 +250,22 @@ public class ActivityStartInterceptorTest {
}
@Test
public void testInterceptQuietProfile() {
// GIVEN that the user the activity is starting as is currently in quiet mode
public void testInterceptQuietProfile_keepProfilesRunningEnabled() {
// GIVEN that the user the activity is starting as is currently in quiet mode and
// profiles are kept running when in quiet mode.
when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
// THEN calling intercept returns false because package also has to be suspended.
assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
}
@Test
public void testInterceptQuietProfile_keepProfilesRunningDisabled() {
// GIVEN that the user the activity is starting as is currently in quiet mode and
// profiles are stopped when in quiet mode (pre-U behavior, no profile app suspension).
when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
@@ -263,10 +276,28 @@ public class ActivityStartInterceptorTest {
}
@Test
public void testInterceptQuietProfileWhenPackageSuspended() {
public void testInterceptQuietProfileWhenPackageSuspended_keepProfilesRunningEnabled() {
// GIVEN that the user the activity is starting as is currently in quiet mode,
// the package is suspended and profiles are kept running while in quiet mode.
suspendPackage("com.test.suspending.package");
// GIVEN that the user the activity is starting as is currently in quiet mode
when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
// THEN the returned intent is the quiet mode intent
assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
.filterEquals(mInterceptor.mIntent));
}
@Test
public void testInterceptQuietProfileWhenPackageSuspended_keepProfilesRunningDisabled() {
// GIVEN that the user the activity is starting as is currently in quiet mode,
// the package is suspended and profiles are stopped while in quiet mode.
suspendPackage("com.test.suspending.package");
when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));