Update DPMS to push active admins info to UsageStatsService.
Bug: 71710099
Test: atest services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
Test: atest services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Change-Id: Ia46be9008470b0228978306b9992560fc4f2c586
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 58ac7d2..57030e4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -44,6 +44,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
@@ -90,6 +91,7 @@
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
+import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -182,6 +184,7 @@
initializeDpms();
+ Mockito.reset(getServices().usageStatsManagerInternal);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -207,6 +210,7 @@
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
+ dpms.handleStart();
dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
@@ -278,6 +282,32 @@
assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
}
+ public void testHandleStart() throws Exception {
+ // Device owner in SYSTEM_USER
+ setDeviceOwner();
+ // Profile owner in CALLER_USER_HANDLE
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
+ setAsProfileOwner(admin2);
+ // Active admin in CALLER_USER_HANDLE
+ final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 1306);
+ setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
+ dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false,
+ DpmMockContext.CALLER_USER_HANDLE);
+ assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage,
+ DpmMockContext.CALLER_USER_HANDLE));
+
+ initializeDpms();
+
+ // Verify
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ MockUtils.checkAdminApps(admin1.getPackageName()),
+ eq(UserHandle.USER_SYSTEM));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ MockUtils.checkAdminApps(admin2.getPackageName(),
+ adminAnotherPackage.getPackageName()),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
/**
* Caller doesn't have proper permissions.
*/
@@ -330,6 +360,9 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
anyString());
+ verify(getServices().usageStatsManagerInternal).onActiveAdminAdded(
+ admin1.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+
// TODO Verify other calls too.
// Make sure it's active admin1.
@@ -369,6 +402,11 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
anyString());
+ // times(2) because it was previously called for admin1 which is in the same package
+ // as admin2.
+ verify(getServices().usageStatsManagerInternal, times(2)).onActiveAdminAdded(
+ admin2.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+
// 4. Add the same admin1 again without replace, which should throw.
assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
() -> dpm.setActiveAdmin(admin1, /* replace =*/ false));
@@ -384,6 +422,10 @@
assertEquals(admin1, admins.get(0));
assertEquals(admin2, admins.get(1));
+ // There shouldn't be any callback to UsageStatsManagerInternal when the admin is being
+ // replaced
+ verifyNoMoreInteractions(getServices().usageStatsManagerInternal);
+
// Another user has no admins.
mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
@@ -516,6 +558,8 @@
() -> dpm.removeActiveAdmin(admin1));
assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
// 2. User unlocked.
when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
@@ -523,6 +567,8 @@
dpm.removeActiveAdmin(admin1);
assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
}
/**
@@ -547,6 +593,8 @@
dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
// TODO DO Still can't be removed in this case.
}
@@ -588,6 +636,8 @@
isNull(Bundle.class));
assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
// Again broadcast from saveSettingsLocked().
verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
@@ -598,6 +648,86 @@
// TODO Check other internal calls.
}
+ public void testRemoveActiveAdmin_multipleAdminsInUser() {
+ // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later.
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin1.
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Add admin2.
+ dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin2));
+ assertFalse(dpm.isRemovingAdmin(admin2, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Broadcast from saveSettingsLocked().
+ verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Remove. No permissions, but same user, so it'll work.
+ mContext.callerPermissions.clear();
+ dpm.removeActiveAdmin(admin1);
+
+ verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ isNull(String.class),
+ any(BroadcastReceiver.class),
+ eq(dpms.mHandler),
+ eq(Activity.RESULT_OK),
+ isNull(String.class),
+ isNull(Bundle.class));
+
+ assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ MockUtils.checkAdminApps(admin2.getPackageName()),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Again broadcast from saveSettingsLocked().
+ verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+ */
+ public void testForceRemoveActiveAdmin() throws Exception {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin.
+ setupPackageInPackageManager(admin1.getPackageName(),
+ /* userId= */ DpmMockContext.CALLER_USER_HANDLE,
+ /* appId= */ 10138,
+ /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ assertTrue(dpm.isAdminActive(admin1));
+
+ // Calling from a non-shell uid should fail with a SecurityException
+ mContext.binder.callingUid = 123456;
+ assertExpectException(SecurityException.class,
+ /* messageRegex =*/ "Non-shell user attempted to call",
+ () -> dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ mContext.binder.callingUid = Process.SHELL_UID;
+ dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ // Verify
+ assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
+ }
+
/**
* Test for: @{link DevicePolicyManager#setActivePasswordState}
*
@@ -954,6 +1084,9 @@
eq(null),
eq(true), eq(CAMERA_NOT_DISABLED));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, UserHandle.USER_SYSTEM);
+
assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
// ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner
@@ -1044,6 +1177,8 @@
// Check
assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
}
public void testSetProfileOwner_failures() throws Exception {