/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.devicepolicy; import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY; import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY; import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED; import android.Manifest.permission; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.StringParceledListSlice; import android.content.res.Resources; import android.graphics.Color; import android.net.IIpConnectivityMetrics; import android.net.Uri; import android.content.pm.UserInfo; import android.net.wifi.WifiInfo; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.IBinder; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; import android.security.IKeyChainService; import android.security.KeyChain; import android.telephony.TelephonyManager; import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import android.util.Pair; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserRestrictionsUtils; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS; import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.nullable; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; /** * Tests for DevicePolicyManager( and DevicePolicyManagerService). * You can run them via: m FrameworksServicesTests && adb install \ -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) * * , or: * runtest -c com.android.server.devicepolicy.DevicePolicyManagerTest frameworks-services */ @SmallTest public class DevicePolicyManagerTest extends DpmTestBase { private static final List OWNER_SETUP_PERMISSIONS = Arrays.asList( permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL); private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; /* * The CA cert below is the content of cacert.pem as generated by: * * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem */ private static final String TEST_CA = "-----BEGIN CERTIFICATE-----\n" + "MIIDXTCCAkWgAwIBAgIJAK9Tl/F9V8kSMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n" + "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n" + "aWRnaXRzIFB0eSBMdGQwHhcNMTUwMzA2MTczMjExWhcNMjUwMzAzMTczMjExWjBF\n" + "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAvItOutsE75WBTgTyNAHt4JXQ3JoseaGqcC3WQij6vhrleWi5KJ0jh1/M\n" + "Rpry7Fajtwwb4t8VZa0NuM2h2YALv52w1xivql88zce/HU1y7XzbXhxis9o6SCI+\n" + "oVQSbPeXRgBPppFzBEh3ZqYTVhAqw451XhwdA4Aqs3wts7ddjwlUzyMdU44osCUg\n" + "kVg7lfPf9sTm5IoHVcfLSCWH5n6Nr9sH3o2ksyTwxuOAvsN11F/a0mmUoPciYPp+\n" + "q7DzQzdi7akRG601DZ4YVOwo6UITGvDyuAAdxl5isovUXqe6Jmz2/myTSpAKxGFs\n" + "jk9oRoG6WXWB1kni490GIPjJ1OceyQIDAQABo1AwTjAdBgNVHQ4EFgQUH1QIlPKL\n" + "p2OQ/AoLOjKvBW4zK3AwHwYDVR0jBBgwFoAUH1QIlPKLp2OQ/AoLOjKvBW4zK3Aw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcMi4voMMJHeQLjtq8Oky\n" + "Azpyk8moDwgCd4llcGj7izOkIIFqq/lyqKdtykVKUWz2bSHO5cLrtaOCiBWVlaCV\n" + "DYAnnVLM8aqaA6hJDIfaGs4zmwz0dY8hVMFCuCBiLWuPfiYtbEmjHGSmpQTG6Qxn\n" + "ZJlaK5CZyt5pgh5EdNdvQmDEbKGmu0wpCq9qjZImwdyAul1t/B0DrsWApZMgZpeI\n" + "d2od0VBrCICB1K4p+C51D93xyQiva7xQcCne+TAnGNy9+gjQ/MyR8MRpwRLv5ikD\n" + "u0anJCN8pXo6IMglfMAsoton1J6o5/ae5uhC6caQU8bNUsCK570gpNfjkzo6rbP0\n" + "wQ==\n" + "-----END CERTIFICATE-----\n"; @Override protected void setUp() throws Exception { super.setUp(); mContext = getContext(); when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(true); // By default, pretend all users are running and unlocked. when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true); initializeDpms(); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID); setUpUserManager(); } @Override protected void tearDown() throws Exception { flushTasks(); super.tearDown(); } private void initializeDpms() { // Need clearCallingIdentity() to pass permission checks. final long ident = mContext.binder.clearCallingIdentity(); try { LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY); dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED); dpm = new DevicePolicyManagerTestable(mContext, dpms); } finally { mContext.binder.restoreCallingIdentity(ident); } } private void setUpUserManager() { // Emulate UserManager.set/getApplicationRestriction(). final Map, Bundle> appRestrictions = new HashMap<>(); // UM.setApplicationRestrictions() will save to appRestrictions. doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { String pkg = (String) invocation.getArguments()[0]; Bundle bundle = (Bundle) invocation.getArguments()[1]; UserHandle user = (UserHandle) invocation.getArguments()[2]; appRestrictions.put(Pair.create(pkg, user), bundle); return null; } }).when(mContext.userManager).setApplicationRestrictions( anyString(), nullable(Bundle.class), any(UserHandle.class)); // UM.getApplicationRestrictions() will read from appRestrictions. doAnswer(new Answer() { @Override public Bundle answer(InvocationOnMock invocation) throws Throwable { String pkg = (String) invocation.getArguments()[0]; UserHandle user = (UserHandle) invocation.getArguments()[1]; return appRestrictions.get(Pair.create(pkg, user)); } }).when(mContext.userManager).getApplicationRestrictions( anyString(), any(UserHandle.class)); // Add the first secondary user. mContext.addUser(DpmMockContext.CALLER_USER_HANDLE, 0); } private void setAsProfileOwner(ComponentName admin) { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // PO needs to be an DA. dpm.setActiveAdmin(admin, /* replace =*/ false); // Fire! assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE)); // Check assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); } public void testHasNoFeature() throws Exception { when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(false); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); new DevicePolicyManagerServiceTestable(mContext, dataDir); // If the device has no DPMS feature, it shouldn't register the local service. assertNull(LocalServices.getService(DevicePolicyManagerInternal.class)); } /** * Caller doesn't have proper permissions. */ public void testSetActiveAdmin_SecurityException() { // 1. Failure cases. // Caller doesn't have MANAGE_DEVICE_ADMINS. try { dpm.setActiveAdmin(admin1, false); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } // Caller has MANAGE_DEVICE_ADMINS, but for different user. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); try { dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } /** * Test for: * {@link DevicePolicyManager#setActiveAdmin} * with replace=false and replace=true * {@link DevicePolicyManager#isAdminActive} * {@link DevicePolicyManager#isAdminActiveAsUser} * {@link DevicePolicyManager#getActiveAdmins} * {@link DevicePolicyManager#getActiveAdminsAsUser} */ public void testSetActiveAdmin() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); // 2. Call the API. dpm.setActiveAdmin(admin1, /* replace =*/ false); // 3. Verify internal calls. // Check if the boradcast is sent. verify(mContext.spiedContext).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); verify(mContext.spiedContext).sendBroadcastAsUser( MockUtils.checkIntentAction( DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( eq(admin1.getPackageName()), eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), eq(PackageManager.DONT_KILL_APP), eq(DpmMockContext.CALLER_USER_HANDLE), anyString()); // TODO Verify other calls too. // Make sure it's active admin1. assertTrue(dpm.isAdminActive(admin1)); assertFalse(dpm.isAdminActive(admin2)); assertFalse(dpm.isAdminActive(admin3)); // But not admin1 for a different user. // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL. // (Because we're checking a different user's status from CALLER_USER_HANDLE.) mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1)); assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1)); mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); // Next, add one more admin. // Before doing so, update the application info, now it's enabled. setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID, PackageManager.COMPONENT_ENABLED_STATE_ENABLED); dpm.setActiveAdmin(admin2, /* replace =*/ false); // Now we have two admins. assertTrue(dpm.isAdminActive(admin1)); assertTrue(dpm.isAdminActive(admin2)); assertFalse(dpm.isAdminActive(admin3)); // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called // again. (times(1) because it was previously called for admin1) verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( eq(admin1.getPackageName()), eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), eq(PackageManager.DONT_KILL_APP), eq(DpmMockContext.CALLER_USER_HANDLE), anyString()); // 4. Add the same admin1 again without replace, which should throw. try { dpm.setActiveAdmin(admin1, /* replace =*/ false); fail("Didn't throw"); } catch (IllegalArgumentException expected) { } // 5. Add the same admin1 again with replace, which should succeed. dpm.setActiveAdmin(admin1, /* replace =*/ true); // TODO make sure it's replaced. // 6. Test getActiveAdmins() List admins = dpm.getActiveAdmins(); assertEquals(2, admins.size()); assertEquals(admin1, admins.get(0)); assertEquals(admin2, admins.get(1)); // Another user has no admins. mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); assertEquals(0, DpmTestUtils.getListSizeAllowingNull( dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1))); mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); } public void testSetActiveAdmin_multiUsers() throws Exception { final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456); mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user. // Set up pacakge manager for the other user. setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID); mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, /* replace =*/ false); mMockContext.binder.callingUid = ANOTHER_ADMIN_UID; dpm.setActiveAdmin(admin2, /* replace =*/ false); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; assertTrue(dpm.isAdminActive(admin1)); assertFalse(dpm.isAdminActive(admin2)); mMockContext.binder.callingUid = ANOTHER_ADMIN_UID; assertFalse(dpm.isAdminActive(admin1)); assertTrue(dpm.isAdminActive(admin2)); } /** * Test for: * {@link DevicePolicyManager#setActiveAdmin} * with replace=false */ public void testSetActiveAdmin_twiceWithoutReplace() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.isAdminActive(admin1)); // Add the same admin1 again without replace, which should throw. try { dpm.setActiveAdmin(admin1, /* replace =*/ false); fail("Didn't throw"); } catch (IllegalArgumentException expected) { } } /** * Test for: * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with * BIND_DEVICE_ADMIN. */ public void testSetActiveAdmin_permissionCheck() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); try { dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false); fail(); } catch (IllegalArgumentException expected) { assertTrue(expected.getMessage().contains(permission.BIND_DEVICE_ADMIN)); } assertFalse(dpm.isAdminActive(adminNoPerm)); // Change the target API level to MNC. Now it can be set as DA. setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null, VERSION_CODES.M); dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false); assertTrue(dpm.isAdminActive(adminNoPerm)); // TODO Test the "load from the file" case where DA will still be loaded even without // BIND_DEVICE_ADMIN and target API is N. } /** * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ public void testRemoveActiveAdmin_SecurityException() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); // Add admin. dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.isAdminActive(admin1)); assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); // Directly call the DPMS method with a different userid, which should fail. try { dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } // Try to remove active admin with a different caller userid should fail too, without // having MANAGE_DEVICE_ADMINS. mContext.callerPermissions.clear(); // Change the caller, and call into DPMS directly with a different user-id. mContext.binder.callingUid = 1234567; try { dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } /** * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked * (because we can't send the remove broadcast). */ public void testRemoveActiveAdmin_userNotRunningOrLocked() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Add admin. dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.isAdminActive(admin1)); assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); // 1. User not unlocked. when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE))) .thenReturn(false); try { dpm.removeActiveAdmin(admin1); fail("Didn't throw IllegalStateException"); } catch (IllegalStateException expected) { MoreAsserts.assertContainsRegex( "User must be running and unlocked", expected.getMessage()); } assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); // 2. User unlocked. when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE))) .thenReturn(true); dpm.removeActiveAdmin(admin1); assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); } /** * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() { 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)); // Different user, but should work, because caller has proper permissions. mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // Change the caller, and call into DPMS directly with a different user-id. mContext.binder.callingUid = 1234567; dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE); assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); // TODO DO Still can't be removed in this case. } /** * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() { // 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)); // Broadcast from saveSettingsLocked(). verify(mContext.spiedContext, times(1)).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)); // Again broadcast from saveSettingsLocked(). verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); // TODO Check other internal calls. } /** * Test for: @{link DevicePolicyManager#setActivePasswordState} * * Validates that when the password for a user changes, the notification broadcast intent * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in * addition to ones in the original user. */ public void testSetActivePasswordState_sendToProfiles() throws Exception { mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); final int MANAGED_PROFILE_USER_ID = 78; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); // Setup device owner. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Change the parent user's password. dpm.reportPasswordChanged(UserHandle.USER_SYSTEM); // Both the device owner and the managed profile owner should receive this broadcast. final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED); intent.setComponent(admin1); intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntent(intent), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntent(intent), MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID)); } /** * Test for: @{link DevicePolicyManager#setActivePasswordState} * * Validates that when the password for a managed profile changes, the notification broadcast * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not * its parent. */ public void testSetActivePasswordState_notSentToParent() throws Exception { mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); final int MANAGED_PROFILE_USER_ID = 78; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); // Setup device owner. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); doReturn(true).when(mContext.lockPatternUtils) .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID); setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Change the profile's password. dpm.reportPasswordChanged(MANAGED_PROFILE_USER_ID); // Both the device owner and the managed profile owner should receive this broadcast. final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED); intent.setComponent(admin1); intent.putExtra(Intent.EXTRA_USER, UserHandle.of(MANAGED_PROFILE_USER_ID)); verify(mContext.spiedContext, never()).sendBroadcastAsUser( MockUtils.checkIntent(intent), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntent(intent), MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID)); } /** * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully. */ public void testSetDeviceOwner() throws Exception { setDeviceOwner(); // Try to set a profile owner on the same user, which should fail. setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM); try { dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM); fail("IllegalStateException not thrown"); } catch (IllegalStateException expected) { assertTrue("Message was: " + expected.getMessage(), expected.getMessage().contains("already has a device owner")); } // DO admin can't be deactivated. dpm.removeActiveAdmin(admin1); assertTrue(dpm.isAdminActive(admin1)); // TODO Test getDeviceOwnerName() too. To do so, we need to change // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. } private void setDeviceOwner() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // In this test, change the caller user to "system". mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Make sure admin1 is installed on system user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); // Check various get APIs. checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false); // DO needs to be an DA. dpm.setActiveAdmin(admin1, /* replace =*/ false); // Fire! assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); // getDeviceOwnerComponent should return the admin1 component. assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); // Check various get APIs. checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true); // getDeviceOwnerComponent should *NOT* return the admin1 component for other users. mContext.binder.callingUid = DpmMockContext.CALLER_UID; assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Verify internal calls. verify(mContext.iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); // TODO We should check if the caller has called clearCallerIdentity(). verify(mContext.ibackupManager, times(1)).setBackupServiceActive( eq(UserHandle.USER_SYSTEM), eq(false)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); } private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) { final int origCallingUser = mContext.binder.callingUid; final List origPermissions = new ArrayList(mContext.callerPermissions); mContext.callerPermissions.clear(); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.binder.callingUid = Process.SYSTEM_UID; // TODO Test getDeviceOwnerName() too. To do so, we need to change // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. if (hasDeviceOwner) { assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); } else { assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); } mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; if (hasDeviceOwner) { assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); } else { assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); } mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Still with MANAGE_USERS. assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); if (hasDeviceOwner) { assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); } else { assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); } mContext.binder.callingUid = Process.SYSTEM_UID; mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can still call "OnAnyUser" without MANAGE_USERS. if (hasDeviceOwner) { assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); } else { assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); } mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Still no MANAGE_USERS. if (hasDeviceOwner) { assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); } else { assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); } try { dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerComponentOnAnyUser(); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerUserId(); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerNameOnAnyUser(); fail(); } catch (SecurityException expected) { } mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Still no MANAGE_USERS. assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); try { dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerComponentOnAnyUser(); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerUserId(); fail(); } catch (SecurityException expected) { } try { dpm.getDeviceOwnerNameOnAnyUser(); fail(); } catch (SecurityException expected) { } // Restore. mContext.binder.callingUid = origCallingUser; mContext.callerPermissions.addAll(origPermissions); } /** * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist. */ public void testSetDeviceOwner_noSuchPackage() { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // Call from a process on the system user. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; try { dpm.setDeviceOwner(new ComponentName("a.b.c", ".def")); fail("Didn't throw IllegalArgumentException"); } catch (IllegalArgumentException expected) { assertTrue("Message was: " + expected.getMessage(), expected.getMessage().contains("Invalid component")); } } public void testSetDeviceOwner_failures() throws Exception { // TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner(). } public void testClearDeviceOwner() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // Set admin1 as a DA to the secondary user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); // Set admin 1 as the DO to the system user. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); // Verify internal calls. verify(mContext.iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); when(mContext.userManager.hasUserRestriction(eq(UserManager.DISALLOW_ADD_USER), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM))).thenReturn(true); assertTrue(dpm.isAdminActive(admin1)); assertFalse(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM)); // Set up other mocks. when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle()); // Now call clear. doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser( eq(admin1.getPackageName()), anyInt()); // But first pretend the user is locked. Then it should fail. when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(false); try { dpm.clearDeviceOwnerApp(admin1.getPackageName()); fail("Didn't throw IllegalStateException"); } catch (IllegalStateException expected) { MoreAsserts.assertContainsRegex( "User must be running and unlocked", expected.getMessage()); } when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true); reset(mContext.userManagerInternal); dpm.clearDeviceOwnerApp(admin1.getPackageName()); // Now DO shouldn't be set. assertNull(dpm.getDeviceOwnerComponentOnAnyUser()); verify(mContext.userManager).setUserRestriction(eq(UserManager.DISALLOW_ADD_USER), eq(false), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), eq(null), eq(true), eq(CAMERA_NOT_DISABLED)); assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM)); // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner // and once for clearing it. verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); // TODO Check other calls. } public void testClearDeviceOwner_fromDifferentUser() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // Set admin1 as a DA to the secondary user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); // Set admin 1 as the DO to the system user. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); // Verify internal calls. verify(mContext.iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); // Now call clear from the secondary user, which should throw. mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Now call clear. doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser( eq(admin1.getPackageName()), anyInt()); try { dpm.clearDeviceOwnerApp(admin1.getPackageName()); fail("Didn't throw"); } catch (SecurityException e) { assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage()); } // DO shouldn't be removed. assertTrue(dpm.isDeviceManaged()); } public void testSetProfileOwner() throws Exception { setAsProfileOwner(admin1); // PO admin can't be deactivated. dpm.removeActiveAdmin(admin1); assertTrue(dpm.isAdminActive(admin1)); // Try setting DO on the same user, which should fail. setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); dpm.setActiveAdmin(admin2, /* refreshing= */ true, DpmMockContext.CALLER_USER_HANDLE); try { dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE); fail("IllegalStateException not thrown"); } catch (IllegalStateException expected) { assertTrue("Message was: " + expected.getMessage(), expected.getMessage().contains("already has a profile owner")); } } public void testClearProfileOwner() throws Exception { setAsProfileOwner(admin1); mContext.binder.callingUid = DpmMockContext.CALLER_UID; assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName())); assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); // First try when the user is locked, which should fail. when(mContext.userManager.isUserUnlocked(anyInt())) .thenReturn(false); try { dpm.clearProfileOwner(admin1); fail("Didn't throw IllegalStateException"); } catch (IllegalStateException expected) { MoreAsserts.assertContainsRegex( "User must be running and unlocked", expected.getMessage()); } // Clear, really. when(mContext.userManager.isUserUnlocked(anyInt())) .thenReturn(true); dpm.clearProfileOwner(admin1); // Check assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName())); assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); } public void testSetProfileOwner_failures() throws Exception { // TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner(). } public void testGetDeviceOwnerAdminLocked() throws Exception { checkDeviceOwnerWithMultipleDeviceAdmins(); } private void checkDeviceOwnerWithMultipleDeviceAdmins() throws Exception { // In ths test, we use 3 users (system + 2 secondary users), set some device admins to them, // set admin2 on CALLER_USER_HANDLE as DO, then call getDeviceOwnerAdminLocked() to // make sure it gets the right component from the right user. final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456); mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user. mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); // Make sure the admin packge is installed to each user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID); // Set active admins to the users. dpm.setActiveAdmin(admin1, /* replace =*/ false); dpm.setActiveAdmin(admin3, /* replace =*/ false); dpm.setActiveAdmin(admin1, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE); dpm.setActiveAdmin(admin2, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE); dpm.setActiveAdmin(admin2, /* replace =*/ false, ANOTHER_USER_ID); // Set DO on the first non-system user. mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true); assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE)); assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)); // Then check getDeviceOwnerAdminLocked(). assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent()); assertEquals(DpmMockContext.CALLER_UID, dpms.getDeviceOwnerAdminLocked().getUid()); } /** * This essentially tests * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is * private.) * * We didn't use to persist the DO component class name, but now we do, and the above method * finds the right component from a package name upon migration. */ public void testDeviceOwnerMigration() throws Exception { when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); checkDeviceOwnerWithMultipleDeviceAdmins(); // Overwrite the device owner setting and clears the clas name. dpms.mOwners.setDeviceOwner( new ComponentName(admin2.getPackageName(), ""), "owner-name", DpmMockContext.CALLER_USER_HANDLE); dpms.mOwners.writeDeviceOwner(); // Make sure the DO component name doesn't have a class name. assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName()); // Then create a new DPMS to have it load the settings from files. when(mContext.userManager.getUserRestrictions(any(UserHandle.class))) .thenReturn(new Bundle()); initializeDpms(); // Now the DO component name is a full name. // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the // DO. assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)); } public void testSetGetApplicationRestriction() { setAsProfileOwner(admin1); mContext.packageName = admin1.getPackageName(); { Bundle rest = new Bundle(); rest.putString("KEY_STRING", "Foo1"); dpm.setApplicationRestrictions(admin1, "pkg1", rest); } { Bundle rest = new Bundle(); rest.putString("KEY_STRING", "Foo2"); dpm.setApplicationRestrictions(admin1, "pkg2", rest); } { Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1"); assertNotNull(returned); assertEquals(returned.size(), 1); assertEquals(returned.get("KEY_STRING"), "Foo1"); } { Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2"); assertNotNull(returned); assertEquals(returned.size(), 1); assertEquals(returned.get("KEY_STRING"), "Foo2"); } dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle()); assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size()); } /** * Setup a package in the package manager mock for {@link DpmMockContext#CALLER_USER_HANDLE}. * Useful for faking installed applications. * * @param packageName the name of the package to be setup * @param appId the application ID to be given to the package * @return the UID of the package as known by the mock package manager */ private int setupPackageInPackageManager(final String packageName, final int appId) throws Exception { return setupPackageInPackageManager( packageName, DpmMockContext.CALLER_USER_HANDLE, appId, ApplicationInfo.FLAG_HAS_CODE); } /** * Setup a package in the package manager mock. Useful for faking installed applications. * * @param packageName the name of the package to be setup * @param userId the user id where the package will be "installed" * @param appId the application ID to be given to the package * @param flags flags to set in the ApplicationInfo for this package * @return the UID of the package as known by the mock package manager */ private int setupPackageInPackageManager( final String packageName, int userId, final int appId, int flags) throws Exception { // Make the PackageManager return the package instead of throwing a NameNotFoundException final PackageInfo pi = new PackageInfo(); pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.flags = flags; doReturn(pi).when(mContext.ipackageManager).getPackageInfo( eq(packageName), anyInt(), eq(userId)); doReturn(pi.applicationInfo).when(mContext.ipackageManager).getApplicationInfo( eq(packageName), anyInt(), eq(userId)); // Setup application UID with the PackageManager final int uid = UserHandle.getUid(userId, appId); doReturn(uid).when(mContext.packageManager).getPackageUidAsUser( eq(packageName), eq(userId)); // Associate packageName to uid doReturn(packageName).when(mContext.ipackageManager).getNameForUid(eq(uid)); doReturn(new String[]{packageName}) .when(mContext.ipackageManager).getPackagesForUid(eq(uid)); return uid; } public void testCertificateDisclosure() throws Exception { final int userId = DpmMockContext.CALLER_USER_HANDLE; final UserHandle user = UserHandle.of(userId); mContext.applicationInfo = new ApplicationInfo(); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.packageName = "com.android.frameworks.servicestests"; mContext.addPackageContext(user, mContext); when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); StringParceledListSlice oneCert = asSlice(new String[] {"1"}); StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"}); final String TEST_STRING = "Test for exactly 2 certs out of 4"; doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2)); // Given that we have exactly one certificate installed, when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert); // when that certificate is approved, dpms.approveCaCert(oneCert.getList().get(0), userId, true); // a notification should not be shown. verify(mContext.notificationManager, timeout(1000)) .cancelAsUser(anyString(), anyInt(), eq(user)); // Given that we have four certificates installed, when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts); // when two of them are approved (one of them approved twice hence no action), dpms.approveCaCert(fourCerts.getList().get(0), userId, true); dpms.approveCaCert(fourCerts.getList().get(1), userId, true); // a notification should be shown saying that there are two certificates left to approve. verify(mContext.notificationManager, timeout(1000)) .notifyAsUser(anyString(), anyInt(), argThat( new BaseMatcher() { @Override public boolean matches(Object item) { final Notification noti = (Notification) item; return TEST_STRING.equals( noti.extras.getString(Notification.EXTRA_TITLE)); } @Override public void describeTo(Description description) { description.appendText( "Notification{title=\"" + TEST_STRING + "\"}"); } }), eq(user)); } /** * Simple test for delegate set/get and general delegation. Tests verifying that delegated * privileges can acually be exercised by a delegate are not covered here. */ public void testDelegation() throws Exception { setAsProfileOwner(admin1); final int userHandle = DpmMockContext.CALLER_USER_HANDLE; // Given two packages final String CERT_DELEGATE = "com.delegate.certs"; final String RESTRICTIONS_DELEGATE = "com.delegate.apprestrictions"; final int CERT_DELEGATE_UID = setupPackageInPackageManager(CERT_DELEGATE, 20988); final int RESTRICTIONS_DELEGATE_UID = setupPackageInPackageManager(RESTRICTIONS_DELEGATE, 20989); // On delegation mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); dpm.setCertInstallerPackage(admin1, CERT_DELEGATE); dpm.setApplicationRestrictionsManagingPackage(admin1, RESTRICTIONS_DELEGATE); // DPMS correctly stores and retrieves the delegates DevicePolicyManagerService.DevicePolicyData policy = dpms.mUserData.get(userHandle); assertEquals(2, policy.mDelegationMap.size()); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE), DELEGATION_CERT_INSTALL); MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, CERT_DELEGATE), DELEGATION_CERT_INSTALL); assertEquals(CERT_DELEGATE, dpm.getCertInstallerPackage(admin1)); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(RESTRICTIONS_DELEGATE), DELEGATION_APP_RESTRICTIONS); MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, RESTRICTIONS_DELEGATE), DELEGATION_APP_RESTRICTIONS); assertEquals(RESTRICTIONS_DELEGATE, dpm.getApplicationRestrictionsManagingPackage(admin1)); // On calling install certificate APIs from an unauthorized process mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID; mContext.packageName = RESTRICTIONS_DELEGATE; // DPMS throws a SecurityException try { dpm.installCaCert(null, null); fail("Didn't throw SecurityException on unauthorized access"); } catch (SecurityException expected) { } // On calling install certificate APIs from an authorized process mContext.binder.callingUid = CERT_DELEGATE_UID; mContext.packageName = CERT_DELEGATE; // DPMS executes without a SecurityException try { dpm.installCaCert(null, null); } catch (SecurityException unexpected) { fail("Threw SecurityException on authorized access"); } catch (NullPointerException expected) { } // On removing a delegate mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); dpm.setCertInstallerPackage(admin1, null); // DPMS does not allow access to ex-delegate mContext.binder.callingUid = CERT_DELEGATE_UID; mContext.packageName = CERT_DELEGATE; try { dpm.installCaCert(null, null); fail("Didn't throw SecurityException on unauthorized access"); } catch (SecurityException expected) { } // But still allows access to other existing delegates mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID; mContext.packageName = RESTRICTIONS_DELEGATE; try { dpm.getApplicationRestrictions(null, "pkg"); } catch (SecurityException expected) { fail("Threw SecurityException on authorized access"); } } public void testApplicationRestrictionsManagingApp() throws Exception { setAsProfileOwner(admin1); final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2"; final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager"; final int appRestrictionsManagerAppId = 20987; final int appRestrictionsManagerUid = setupPackageInPackageManager( appRestrictionsManagerPackage, appRestrictionsManagerAppId); // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't // delegated that permission yet. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); Bundle rest = new Bundle(); rest.putString("KEY_STRING", "Foo1"); try { dpm.setApplicationRestrictions(null, "pkg1", rest); fail("Didn't throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex( "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.", expected.getMessage()); } try { dpm.getApplicationRestrictions(null, "pkg1"); fail("Didn't throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex( "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.", expected.getMessage()); } // Check via the profile owner that no restrictions were set. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size()); // Check the API does not allow setting a non-existent package try { dpm.setApplicationRestrictionsManagingPackage(admin1, nonExistAppRestrictionsManagerPackage); fail("Non-existent app set as app restriction manager."); } catch (PackageManager.NameNotFoundException expected) { MoreAsserts.assertContainsRegex( nonExistAppRestrictionsManagerPackage, expected.getMessage()); } // Let appRestrictionsManagerPackage manage app restrictions dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage); assertEquals(appRestrictionsManagerPackage, dpm.getApplicationRestrictionsManagingPackage(admin1)); // Now that package should be able to set and retrieve app restrictions. mContext.binder.callingUid = appRestrictionsManagerUid; mContext.packageName = appRestrictionsManagerPackage; assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage()); dpm.setApplicationRestrictions(null, "pkg1", rest); Bundle returned = dpm.getApplicationRestrictions(null, "pkg1"); assertEquals(1, returned.size(), 1); assertEquals("Foo1", returned.get("KEY_STRING")); // The same app running on a separate user shouldn't be able to manage app restrictions. mContext.binder.callingUid = UserHandle.getUid( UserHandle.USER_SYSTEM, appRestrictionsManagerAppId); assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); try { dpm.setApplicationRestrictions(null, "pkg1", rest); fail("Didn't throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex( "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.", expected.getMessage()); } // The DPM is still able to manage app restrictions, even if it allowed another app to do it // too. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1")); dpm.setApplicationRestrictions(admin1, "pkg1", null); assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size()); // Removing the ability for the package to manage app restrictions. dpm.setApplicationRestrictionsManagingPackage(admin1, null); assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1)); mContext.binder.callingUid = appRestrictionsManagerUid; mContext.packageName = appRestrictionsManagerPackage; assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); try { dpm.setApplicationRestrictions(null, "pkg1", null); fail("Didn't throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex( "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.", expected.getMessage()); } } public void testSetUserRestriction_asDo() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // First, set DO. // Call from a process on the system user. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Make sure admin1 is installed on system user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); // Call. dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); assertTrue(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)); // Check that the user restrictions that are enabled by default are set. Then unset them. String[] defaultRestrictions = UserRestrictionsUtils .getDefaultEnabledForDeviceOwner().toArray(new String[0]); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(defaultRestrictions), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(defaultRestrictions), dpm.getUserRestrictions(admin1) ); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(defaultRestrictions), eq(true) /* isDeviceOwner */, eq(CAMERA_NOT_DISABLED) ); reset(mContext.userManagerInternal); for (String restriction : defaultRestrictions) { dpm.clearUserRestriction(admin1, restriction); } assertNoDeviceOwnerRestrictions(); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS, UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS), dpm.getUserRestrictions(admin1) ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), dpm.getUserRestrictions(admin1) ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); assertNoDeviceOwnerRestrictions(); // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE are PO restrictions, but when // DO sets them, the scope is global. dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_UNMUTE_MICROPHONE), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE); reset(mContext.userManagerInternal); // More tests. dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN, UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.setCameraDisabled(admin1, true); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), // DISALLOW_CAMERA will be applied to both local and global. MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN, UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_DISABLED_GLOBALLY)); reset(mContext.userManagerInternal); // Set up another DA and let it disable camera. Now DISALLOW_CAMERA will only be applied // locally. dpm.setCameraDisabled(admin1, false); reset(mContext.userManagerInternal); setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM); dpm.setCameraDisabled(admin2, true); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN, UserManager.DISALLOW_ADD_USER), eq(true), eq(CAMERA_DISABLED_LOCALLY)); reset(mContext.userManagerInternal); // TODO Make sure restrictions are written to the file. } public void testSetUserRestriction_asPo() { setAsProfileOwner(admin1); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) .ensureUserRestrictions() ); dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES), eq(false), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_OUTGOING_CALLS), eq(false), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_OUTGOING_CALLS ), dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) .ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_OUTGOING_CALLS ), dpm.getUserRestrictions(admin1) ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), eq(false), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_OUTGOING_CALLS ), dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) .ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( UserManager.DISALLOW_OUTGOING_CALLS ), dpm.getUserRestrictions(admin1) ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(), eq(false), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) .ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), dpm.getUserRestrictions(admin1) ); // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even // though when DO sets them they'll be applied globally. dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME); reset(mContext.userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_UNMUTE_MICROPHONE), eq(false), eq(CAMERA_NOT_DISABLED)); reset(mContext.userManagerInternal); dpm.setCameraDisabled(admin1, true); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_UNMUTE_MICROPHONE), eq(false), eq(CAMERA_DISABLED_LOCALLY)); reset(mContext.userManagerInternal); // TODO Make sure restrictions are written to the file. } public void testDefaultEnabledUserRestrictions() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // First, set DO. // Call from a process on the system user. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Make sure admin1 is installed on system user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); assertTrue(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)); // Check that the user restrictions that are enabled by default are set. Then unset them. String[] defaultRestrictions = UserRestrictionsUtils .getDefaultEnabledForDeviceOwner().toArray(new String[0]); assertTrue(defaultRestrictions.length > 0); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(defaultRestrictions), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(defaultRestrictions), dpm.getUserRestrictions(admin1) ); verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(defaultRestrictions), eq(true) /* isDeviceOwner */, eq(CAMERA_NOT_DISABLED) ); reset(mContext.userManagerInternal); for (String restriction : defaultRestrictions) { dpm.clearUserRestriction(admin1, restriction); } assertNoDeviceOwnerRestrictions(); // Initialize DPMS again and check that the user restriction wasn't enabled again. reset(mContext.userManagerInternal); initializeDpms(); assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertNotNull(dpms.getDeviceOwnerAdminLocked()); assertNoDeviceOwnerRestrictions(); // Add a new restriction to the default set, initialize DPMS, and check that the restriction // is set as it wasn't enabled during setDeviceOwner. final String newDefaultEnabledRestriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE; assertFalse(UserRestrictionsUtils .getDefaultEnabledForDeviceOwner().contains(newDefaultEnabledRestriction)); UserRestrictionsUtils .getDefaultEnabledForDeviceOwner().add(newDefaultEnabledRestriction); try { reset(mContext.userManagerInternal); initializeDpms(); assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertNotNull(dpms.getDeviceOwnerAdminLocked()); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(newDefaultEnabledRestriction), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(newDefaultEnabledRestriction), dpm.getUserRestrictions(admin1) ); verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(newDefaultEnabledRestriction), eq(true) /* isDeviceOwner */, eq(CAMERA_NOT_DISABLED) ); reset(mContext.userManagerInternal); // Remove the restriction. dpm.clearUserRestriction(admin1, newDefaultEnabledRestriction); // Initialize DPMS again. The restriction shouldn't be enabled for a second time. initializeDpms(); assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); assertNotNull(dpms.getDeviceOwnerAdminLocked()); assertNoDeviceOwnerRestrictions(); } finally { UserRestrictionsUtils .getDefaultEnabledForDeviceOwner().remove(newDefaultEnabledRestriction); } } private void assertNoDeviceOwnerRestrictions() { DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() ); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), dpm.getUserRestrictions(admin1) ); } public void testGetMacAddress() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // In this test, change the caller user to "system". mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Make sure admin1 is installed on system user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); // Test 1. Caller doesn't have DO or DA. try { dpm.getWifiMacAddress(admin1); fail(); } catch (SecurityException e) { MoreAsserts.assertContainsRegex("No active admin", e.getMessage()); } // DO needs to be an DA. dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.isAdminActive(admin1)); // Test 2. Caller has DA, but not DO. try { dpm.getWifiMacAddress(admin1); fail(); } catch (SecurityException e) { MoreAsserts.assertContainsRegex("does not own the device", e.getMessage()); } // Test 3. Caller has PO, but not DO. assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); try { dpm.getWifiMacAddress(admin1); fail(); } catch (SecurityException e) { MoreAsserts.assertContainsRegex("does not own the device", e.getMessage()); } // Remove PO. dpm.clearProfileOwner(admin1); dpm.setActiveAdmin(admin1, false); // Test 4, Caller is DO now. assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); // 4-1. But no WifiInfo. assertNull(dpm.getWifiMacAddress(admin1)); // 4-2. Returns WifiInfo, but with the default MAC. when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo()); assertNull(dpm.getWifiMacAddress(admin1)); // 4-3. With a real MAC address. final WifiInfo wi = new WifiInfo(); wi.setMacAddress("11:22:33:44:55:66"); when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi); assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); } public void testReboot() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // In this test, change the caller user to "system". mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Make sure admin1 is installed on system user. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); // Set admin1 as DA. dpm.setActiveAdmin(admin1, false); assertTrue(dpm.isAdminActive(admin1)); try { dpm.reboot(admin1); fail("DA calls DPM.reboot(), did not throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage()); } // Set admin1 as PO. assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); try { dpm.reboot(admin1); fail("PO calls DPM.reboot(), did not throw expected SecurityException"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage()); } // Remove PO and add DO. dpm.clearProfileOwner(admin1); dpm.setActiveAdmin(admin1, false); assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); // admin1 is DO. // Set current call state of device to ringing. when(mContext.telephonyManager.getCallState()) .thenReturn(TelephonyManager.CALL_STATE_RINGING); try { dpm.reboot(admin1); fail("DPM.reboot() called when receiveing a call, should thrown IllegalStateException"); } catch (IllegalStateException expected) { MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage()); } // Set current call state of device to dialing/active. when(mContext.telephonyManager.getCallState()) .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK); try { dpm.reboot(admin1); fail("DPM.reboot() called when dialing, should thrown IllegalStateException"); } catch (IllegalStateException expected) { MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage()); } // Set current call state of device to idle. when(mContext.telephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE); dpm.reboot(admin1); } public void testSetGetSupportText() { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, true); dpm.setActiveAdmin(admin2, true); mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS); // Null default support messages. { assertNull(dpm.getLongSupportMessage(admin1)); assertNull(dpm.getShortSupportMessage(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertNull(dpm.getShortSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); assertNull(dpm.getLongSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; } // Only system can call the per user versions. { try { dpm.getShortSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE); fail("Only system should be able to call getXXXForUser versions"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex("message for user", expected.getMessage()); } try { dpm.getLongSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE); fail("Only system should be able to call getXXXForUser versions"); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex("message for user", expected.getMessage()); } } // Can't set message for admin in another uid. { mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1; try { dpm.setShortSupportMessage(admin1, "Some text"); fail("Admins should only be able to change their own support text."); } catch (SecurityException expected) { MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage()); } mContext.binder.callingUid = DpmMockContext.CALLER_UID; } // Set/Get short returns what it sets and other admins text isn't changed. { final String supportText = "Some text to test with."; dpm.setShortSupportMessage(admin1, supportText); assertEquals(supportText, dpm.getShortSupportMessage(admin1)); assertNull(dpm.getLongSupportMessage(admin1)); assertNull(dpm.getShortSupportMessage(admin2)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); assertNull(dpm.getShortSupportMessageForUser(admin2, DpmMockContext.CALLER_USER_HANDLE)); assertNull(dpm.getLongSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; dpm.setShortSupportMessage(admin1, null); assertNull(dpm.getShortSupportMessage(admin1)); } // Set/Get long returns what it sets and other admins text isn't changed. { final String supportText = "Some text to test with.\nWith more text."; dpm.setLongSupportMessage(admin1, supportText); assertEquals(supportText, dpm.getLongSupportMessage(admin1)); assertNull(dpm.getShortSupportMessage(admin1)); assertNull(dpm.getLongSupportMessage(admin2)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); assertNull(dpm.getLongSupportMessageForUser(admin2, DpmMockContext.CALLER_USER_HANDLE)); assertNull(dpm.getShortSupportMessageForUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; dpm.setLongSupportMessage(admin1, null); assertNull(dpm.getLongSupportMessage(admin1)); } } public void testCreateAdminSupportIntent() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // Nonexisting permission returns null Intent intent = dpm.createAdminSupportIntent("disallow_nothing"); assertNull(intent); // Existing permission that is not set returns null intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); assertNull(intent); // Existing permission that is not set by device/profile owner returns null when(mContext.userManager.hasUserRestriction( eq(UserManager.DISALLOW_ADJUST_VOLUME), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(true); intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); assertNull(intent); // Permission that is set by device owner returns correct intent when(mContext.userManager.getUserRestrictionSource( eq(UserManager.DISALLOW_ADJUST_VOLUME), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); assertNotNull(intent); assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction()); assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID), intent.getIntExtra(Intent.EXTRA_USER_ID, -1)); assertEquals(admin1, (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN)); assertEquals(UserManager.DISALLOW_ADJUST_VOLUME, intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); // Try with POLICY_DISABLE_CAMERA and POLICY_DISABLE_SCREEN_CAPTURE, which are not // user restrictions // Camera is not disabled intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); assertNull(intent); // Camera is disabled dpm.setCameraDisabled(admin1, true); intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); assertNotNull(intent); assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA, intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); // Screen capture is not disabled intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); assertNull(intent); // Screen capture is disabled dpm.setScreenCaptureDisabled(admin1, true); intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); assertNotNull(intent); assertEquals(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE, intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); // Same checks for different user mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Camera should be disabled by device owner intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); assertNotNull(intent); assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA, intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID), intent.getIntExtra(Intent.EXTRA_USER_ID, -1)); // ScreenCapture should not be disabled by device owner intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); assertNull(intent); } /** * Test for: * {@link DevicePolicyManager#setAffiliationIds} * {@link DevicePolicyManager#getAffiliationIds} * {@link DevicePolicyManager#isAffiliatedUser} */ public void testUserAffiliation() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); // Check that the system user is unaffiliated. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; assertFalse(dpm.isAffiliatedUser()); // Set a device owner on the system user. Check that the system user becomes affiliated. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); assertTrue(dpm.isAffiliatedUser()); assertTrue(dpm.getAffiliationIds(admin1).isEmpty()); // Install a profile owner. Check that the test user is unaffiliated. mContext.binder.callingUid = DpmMockContext.CALLER_UID; setAsProfileOwner(admin2); assertFalse(dpm.isAffiliatedUser()); assertTrue(dpm.getAffiliationIds(admin2).isEmpty()); // Have the profile owner specify a set of affiliation ids. Check that the test user remains // unaffiliated. final Set userAffiliationIds = new ArraySet<>(); userAffiliationIds.add("red"); userAffiliationIds.add("green"); userAffiliationIds.add("blue"); dpm.setAffiliationIds(admin2, userAffiliationIds); MoreAsserts.assertContentsInAnyOrder(dpm.getAffiliationIds(admin2), "red", "green", "blue"); assertFalse(dpm.isAffiliatedUser()); // Have the device owner specify a set of affiliation ids that do not intersect with those // specified by the profile owner. Check that the test user remains unaffiliated. final Set deviceAffiliationIds = new ArraySet<>(); deviceAffiliationIds.add("cyan"); deviceAffiliationIds.add("yellow"); deviceAffiliationIds.add("magenta"); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; dpm.setAffiliationIds(admin1, deviceAffiliationIds); MoreAsserts.assertContentsInAnyOrder( dpm.getAffiliationIds(admin1), "cyan", "yellow", "magenta"); mContext.binder.callingUid = DpmMockContext.CALLER_UID; assertFalse(dpm.isAffiliatedUser()); // Have the profile owner specify a set of affiliation ids that intersect with those // specified by the device owner. Check that the test user becomes affiliated. userAffiliationIds.add("yellow"); dpm.setAffiliationIds(admin2, userAffiliationIds); MoreAsserts.assertContentsInAnyOrder( dpm.getAffiliationIds(admin2), "red", "green", "blue", "yellow"); assertTrue(dpm.isAffiliatedUser()); // Clear affiliation ids for the profile owner. The user becomes unaffiliated. dpm.setAffiliationIds(admin2, Collections.emptySet()); assertTrue(dpm.getAffiliationIds(admin2).isEmpty()); assertFalse(dpm.isAffiliatedUser()); // Set affiliation ids again, then clear PO to check that the user becomes unaffiliated dpm.setAffiliationIds(admin2, userAffiliationIds); assertTrue(dpm.isAffiliatedUser()); dpm.clearProfileOwner(admin2); assertFalse(dpm.isAffiliatedUser()); // Check that the system user remains affiliated. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; assertTrue(dpm.isAffiliatedUser()); // Clear the device owner - the user becomes unaffiliated. clearDeviceOwner(); assertFalse(dpm.isAffiliatedUser()); } public void testGetUserProvisioningState_defaultResult() { assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); } public void testSetUserProvisioningState_permission() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_unprivileged() throws Exception { setupProfileOwner(); try { dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED, DpmMockContext.CALLER_USER_HANDLE); fail("Expected SecurityException"); } catch (SecurityException expected) { } } public void testSetUserProvisioningState_noManagement() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); try { dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED, DpmMockContext.CALLER_USER_HANDLE); fail("IllegalStateException expected"); } catch (IllegalStateException e) { MoreAsserts.assertContainsRegex("change provisioning state unless a .* owner is set", e.getMessage()); } assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); } public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM, DevicePolicyManager.STATE_USER_SETUP_COMPLETE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM, DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_PROFILE_COMPLETE, DevicePolicyManager.STATE_USER_UNMANAGED); } public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_SETUP_COMPLETE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); try { exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_SETUP_FINALIZED, DevicePolicyManager.STATE_USER_UNMANAGED); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { MoreAsserts.assertContainsRegex("Cannot move to user provisioning state", e.getMessage()); } } public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState() throws Exception { setupProfileOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); try { exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE, DevicePolicyManager.STATE_USER_SETUP_COMPLETE); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { MoreAsserts.assertContainsRegex("Cannot move to user provisioning state", e.getMessage()); } } private void exerciseUserProvisioningTransitions(int userId, int... states) { assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); for (int state : states) { dpm.setUserProvisioningState(state, userId); assertEquals(state, dpm.getUserProvisioningState()); } } private void setupProfileOwner() throws Exception { mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); dpm.setActiveAdmin(admin1, false); assertTrue(dpm.setProfileOwner(admin1, null, DpmMockContext.CALLER_USER_HANDLE)); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } private void setupDeviceOwner() throws Exception { mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, false); assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } public void testSetMaximumTimeToLock() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, /* replace =*/ false); dpm.setActiveAdmin(admin2, /* replace =*/ false); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin1, 0); verifyScreenTimeoutCall(null, false); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin1, 1); verifyScreenTimeoutCall(1, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin2, 10); verifyScreenTimeoutCall(null, false); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin1, 5); verifyScreenTimeoutCall(5, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin2, 4); verifyScreenTimeoutCall(4, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin1, 0); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE); verifyScreenTimeoutCall(Integer.MAX_VALUE, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE + 1); verifyScreenTimeoutCall(Integer.MAX_VALUE, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); dpm.setMaximumTimeToLock(admin2, 10); verifyScreenTimeoutCall(10, true); reset(mMockContext.powerManagerInternal); reset(mMockContext.settings); // There's no restriction; shold be set to MAX. dpm.setMaximumTimeToLock(admin2, 0); verifyScreenTimeoutCall(Integer.MAX_VALUE, false); } public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1); final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1); final long MIN_PLUS_ONE_MINUTE = MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE; final long MAX_MINUS_ONE_MINUTE = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE; // verify that the minimum timeout cannot be modified on user builds (system property is // not being read) mContext.buildMock.isDebuggable = false; dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE); verify(mContext.systemProperties, never()).getLong(anyString(), anyLong()); // restore to the debuggable build state mContext.buildMock.isDebuggable = true; // Always return the default (second arg) when getting system property for long type when(mContext.systemProperties.getLong(anyString(), anyLong())).thenAnswer( new Answer() { @Override public Long answer(InvocationOnMock invocation) throws Throwable { return (Long) invocation.getArguments()[1]; } } ); // reset to default (0 means the admin is not participating, so default should be returned) dpm.setRequiredStrongAuthTimeout(admin1, 0); // aggregation should be the default if unset by any admin assertEquals(dpm.getRequiredStrongAuthTimeout(null), DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); // admin not participating by default assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); //clamping from the top dpm.setRequiredStrongAuthTimeout(admin1, DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); assertEquals(dpm.getRequiredStrongAuthTimeout(null), DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); // 0 means the admin is not participating, so default should be returned dpm.setRequiredStrongAuthTimeout(admin1, 0); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); assertEquals(dpm.getRequiredStrongAuthTimeout(null), DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); // clamping from the bottom dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS); assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS); // values within range dpm.setRequiredStrongAuthTimeout(admin1, MIN_PLUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MIN_PLUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(null), MIN_PLUS_ONE_MINUTE); dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE); assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE); // reset to default dpm.setRequiredStrongAuthTimeout(admin1, 0); assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); assertEquals(dpm.getRequiredStrongAuthTimeout(null), DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); // negative value try { dpm.setRequiredStrongAuthTimeout(admin1, -ONE_MINUTE); fail("Didn't throw IllegalArgumentException"); } catch (IllegalArgumentException iae) { } } private void verifyScreenTimeoutCall(Integer expectedTimeout, boolean shouldStayOnWhilePluggedInBeCleared) { if (expectedTimeout == null) { verify(mMockContext.powerManagerInternal, times(0)) .setMaximumScreenOffTimeoutFromDeviceAdmin(anyInt()); } else { verify(mMockContext.powerManagerInternal, times(1)) .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(expectedTimeout)); } // TODO Verify calls to settingsGlobalPutInt. Tried but somehow mockito threw // UnfinishedVerificationException. } private void setup_DeviceAdminFeatureOff() throws Exception { when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) .thenReturn(false); when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(false); initializeDpms(); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(true); setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception { setup_DeviceAdminFeatureOff(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false); } public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception { setup_DeviceAdminFeatureOff(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED); } private void setup_ManagedProfileFeatureOff() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(false); initializeDpms(); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(true); setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception { setup_ManagedProfileFeatureOff(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false); // Test again when split user is on when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false); } public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception { setup_ManagedProfileFeatureOff(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED); // Test again when split user is on when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED); } private void setup_nonSplitUser_firstBoot_primaryUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(true); setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception { setup_nonSplitUser_firstBoot_primaryUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, false /* because of non-split user */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false /* because of non-split user */); } public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser() throws Exception { setup_nonSplitUser_firstBoot_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); } private void setup_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(true); setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } private void setup_nonSplitUser_withDo_primaryUser() throws Exception { setDeviceOwner(); setup_nonSplitUser_afterDeviceSetup_primaryUser(); setUpPackageManagerForFakeAdmin(adminAnotherPackage, DpmMockContext.ANOTHER_UID, admin2); } private void setup_nonSplitUser_withDo_primaryUser_ManagedProfile() throws Exception { setup_nonSplitUser_withDo_primaryUser(); final int MANAGED_PROFILE_USER_ID = 18; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false /* we can't remove a managed profile */)).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)).thenReturn(true); } public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { setup_nonSplitUser_afterDeviceSetup_primaryUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false/* because of completed device setup */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, false/* because of non-split user */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false/* because of non-split user */); } public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { setup_nonSplitUser_afterDeviceSetup_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_USER_SETUP_COMPLETED); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); } public void testProvisioning_nonSplitUser_withDo_primaryUser() throws Exception { setup_nonSplitUser_withDo_primaryUser(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_HAS_DEVICE_OWNER); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false); // COMP mode is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); // And other DPCs can also provision a managed profile (DO + BYOD case). assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception { setup_nonSplitUser_withDo_primaryUser(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // The DO should be allowed to initiate provisioning if it set the restriction itself, but // other packages should be forbidden. when(mContext.userManager.hasUserRestriction( eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(true); when(mContext.userManager.getUserRestrictionSource( eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedBySystem() throws Exception { setup_nonSplitUser_withDo_primaryUser(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // The DO should not be allowed to initiate provisioning if the restriction is set by // another entity. when(mContext.userManager.hasUserRestriction( eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(true); when(mContext.userManager.getUserRestrictionSource( eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // We can delete the managed profile to create a new one, so provisioning is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } public void testCheckProvisioningPreCondition_nonSplitUser_comp_cannot_remove_profile() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); when(mContext.userManager.hasUserRestriction( eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE), eq(UserHandle.SYSTEM))) .thenReturn(true); when(mContext.userManager.getUserRestrictionSource( eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE), eq(UserHandle.SYSTEM))) .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); // We can't remove the profile to create a new one. assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); // But the device owner can still do it because it has set the restriction itself. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); } private void setup_splitUser_firstBoot_systemUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(false); setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception { setup_splitUser_firstBoot_systemUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false /* because canAddMoreManagedProfiles returns false */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false/* because calling uid is system user */); } public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser() throws Exception { setup_splitUser_firstBoot_systemUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_SYSTEM_USER); } private void setup_splitUser_afterDeviceSetup_systemUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(false); setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception { setup_splitUser_afterDeviceSetup_systemUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true/* it's undefined behavior. Can be changed into false in the future */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false /* because canAddMoreManagedProfiles returns false */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, true/* it's undefined behavior. Can be changed into false in the future */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false/* because calling uid is system user */); } public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser() throws Exception { setup_splitUser_afterDeviceSetup_systemUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_SYSTEM_USER); } private void setup_splitUser_firstBoot_primaryUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = DpmMockContext.CALLER_UID; } public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception { setup_splitUser_firstBoot_primaryUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true); } public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser() throws Exception { setup_splitUser_firstBoot_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_OK); } private void setup_splitUser_afterDeviceSetup_primaryUser() throws Exception { when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = DpmMockContext.CALLER_UID; } public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser() throws Exception { setup_splitUser_afterDeviceSetup_primaryUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true/* it's undefined behavior. Can be changed into false in the future */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, true/* it's undefined behavior. Can be changed into false in the future */); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false/* because user setup completed */); } public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser() throws Exception { setup_splitUser_afterDeviceSetup_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE, DevicePolicyManager.CODE_OK); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, DevicePolicyManager.CODE_USER_SETUP_COMPLETED); } private void setup_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setDeviceOwner(); when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) .thenReturn(false); setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_systemUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false /* can't provision managed profile on system user */); } public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_systemUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER); } private void setup_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setDeviceOwner(); when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = DpmMockContext.CALLER_UID; } public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); mContext.packageName = admin1.getPackageName(); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); } public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // COMP mode is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_OK); } private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setDeviceOwner(); when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); when(mContext.userManager.hasUserRestriction( eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE), eq(UserHandle.of(DpmMockContext.CALLER_USER_HANDLE)))) .thenReturn(true); when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, false /* we can't remove a managed profile */)).thenReturn(false); when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = DpmMockContext.CALLER_UID; } public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setup_provisionManagedProfileCantRemoveUser_primaryUser(); mContext.packageName = admin1.getPackageName(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setup_provisionManagedProfileCantRemoveUser_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); } public void testCheckProvisioningPreCondition_permission() { // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted try { dpm.checkProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, "some.package"); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } public void testForceUpdateUserSetupComplete_permission() { // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted try { dpm.forceUpdateUserSetupComplete(); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } public void testForceUpdateUserSetupComplete_systemUser() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // GIVEN calling from user 20 mContext.binder.callingUid = DpmMockContext.CALLER_UID; try { dpm.forceUpdateUserSetupComplete(); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } public void testForceUpdateUserSetupComplete_userbuild() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; final int userId = UserHandle.USER_SYSTEM; // GIVEN userComplete is false in SettingsProvider setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM DevicePolicyManagerService.DevicePolicyData userData = new DevicePolicyManagerService.DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); // GIVEN it's user build mContext.buildMock.isDebuggable = false; assertTrue(dpms.hasUserSetupCompleted()); dpm.forceUpdateUserSetupComplete(); // THEN the state in dpms is not changed assertTrue(dpms.hasUserSetupCompleted()); } public void testForceUpdateUserSetupComplete_userDebugbuild() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; final int userId = UserHandle.USER_SYSTEM; // GIVEN userComplete is false in SettingsProvider setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM DevicePolicyManagerService.DevicePolicyData userData = new DevicePolicyManagerService.DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); // GIVEN it's userdebug build mContext.buildMock.isDebuggable = true; assertTrue(dpms.hasUserSetupCompleted()); dpm.forceUpdateUserSetupComplete(); // THEN the state in dpms is not changed assertFalse(dpms.hasUserSetupCompleted()); } private void clearDeviceOwner() throws Exception { final long ident = mContext.binder.clearCallingIdentity(); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager) .getPackageUidAsUser(eq(admin1.getPackageName()), anyInt()); dpm.clearDeviceOwnerApp(admin1.getPackageName()); mContext.binder.restoreCallingIdentity(ident); } public void testGetLastSecurityLogRetrievalTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the // feature is disabled because there are non-affiliated secondary users. mContext.removeUser(DpmMockContext.CALLER_USER_HANDLE); when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs)) .thenReturn(true); // No logs were retrieved so far. assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); // Enabling logging should not change the timestamp. dpm.setSecurityLoggingEnabled(admin1, true); verify(mContext.settings) .securityLogSetLoggingEnabledProperty(true); when(mContext.settings.securityLogGetLoggingEnabledProperty()) .thenReturn(true); assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); // Retrieving the logs should update the timestamp. final long beforeRetrieval = System.currentTimeMillis(); dpm.retrieveSecurityLogs(admin1); final long firstSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); final long afterRetrieval = System.currentTimeMillis(); assertTrue(firstSecurityLogRetrievalTime >= beforeRetrieval); assertTrue(firstSecurityLogRetrievalTime <= afterRetrieval); // Retrieving the pre-boot logs should update the timestamp. Thread.sleep(2); dpm.retrievePreRebootSecurityLogs(admin1); final long secondSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); assertTrue(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime); // Checking the timestamp again should not change it. Thread.sleep(2); assertEquals(secondSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); // Retrieving the logs again should update the timestamp. dpm.retrieveSecurityLogs(admin1); final long thirdSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); assertTrue(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime); // Disabling logging should not change the timestamp. Thread.sleep(2); dpm.setSecurityLoggingEnabled(admin1, false); assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); // Restarting the DPMS should not lose the timestamp. initializeDpms(); assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); // Removing the device owner should clear the timestamp. clearDeviceOwner(); assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); } public void testGetLastBugReportRequestTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.packageName = admin1.getPackageName(); mContext.applicationInfo = new ApplicationInfo(); when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject())) .thenReturn(Color.WHITE); when(mContext.resources.getColor(eq(R.color.notification_material_background_color), anyObject())).thenReturn(Color.WHITE); // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the // feature is disabled because there are non-affiliated secondary users. mContext.removeUser(DpmMockContext.CALLER_USER_HANDLE); // No bug reports were requested so far. assertEquals(-1, dpm.getLastBugReportRequestTime()); // Requesting a bug report should update the timestamp. final long beforeRequest = System.currentTimeMillis(); dpm.requestBugreport(admin1); final long bugReportRequestTime = dpm.getLastBugReportRequestTime(); final long afterRequest = System.currentTimeMillis(); assertTrue(bugReportRequestTime >= beforeRequest); assertTrue(bugReportRequestTime <= afterRequest); // Checking the timestamp again should not change it. Thread.sleep(2); assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); // Restarting the DPMS should not lose the timestamp. initializeDpms(); assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); // Removing the device owner should clear the timestamp. clearDeviceOwner(); assertEquals(-1, dpm.getLastBugReportRequestTime()); } public void testGetLastNetworkLogRetrievalTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); mContext.packageName = admin1.getPackageName(); mContext.applicationInfo = new ApplicationInfo(); when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject())) .thenReturn(Color.WHITE); when(mContext.resources.getColor(eq(R.color.notification_material_background_color), anyObject())).thenReturn(Color.WHITE); // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the // feature is disabled because there are non-affiliated secondary users. mContext.removeUser(DpmMockContext.CALLER_USER_HANDLE); when(mContext.iipConnectivityMetrics.registerNetdEventCallback(anyObject())) .thenReturn(true); // No logs were retrieved so far. assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); // Attempting to retrieve logs without enabling logging should not change the timestamp. dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); // Enabling logging should not change the timestamp. dpm.setNetworkLoggingEnabled(admin1, true); assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); // Retrieving the logs should update the timestamp. final long beforeRetrieval = System.currentTimeMillis(); dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); final long firstNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); final long afterRetrieval = System.currentTimeMillis(); assertTrue(firstNetworkLogRetrievalTime >= beforeRetrieval); assertTrue(firstNetworkLogRetrievalTime <= afterRetrieval); // Checking the timestamp again should not change it. Thread.sleep(2); assertEquals(firstNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); // Retrieving the logs again should update the timestamp. dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); final long secondNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); assertTrue(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime); // Disabling logging should not change the timestamp. Thread.sleep(2); dpm.setNetworkLoggingEnabled(admin1, false); assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); // Restarting the DPMS should not lose the timestamp. initializeDpms(); assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); // Removing the device owner should clear the timestamp. clearDeviceOwner(); assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); } public void testGetBindDeviceAdminTargetUsers() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // Only device owner is setup, the result list should be empty. List targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); // Setup a managed profile managed by the same admin. final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Add a secondary user, it should never talk with. final int ANOTHER_USER_ID = 36; mContext.addUser(ANOTHER_USER_ID, 0); // Since the managed profile is not affiliated, they should not be allowed to talk to each // other. targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); // Setting affiliation ids final Set userAffiliationIds = Collections.singleton("some.affiliation-id"); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; dpm.setAffiliationIds(admin1, userAffiliationIds); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setAffiliationIds(admin1, userAffiliationIds); // Calling from device owner admin, the result list should just contain the managed // profile user id. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID)); // Calling from managed profile admin, the result list should just contain the system // user id. mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM); // Changing affiliation ids in one dpm.setAffiliationIds(admin1, Collections.singleton("some-different-affiliation-id")); // Since the managed profile is not affiliated any more, they should not be allowed to talk // to each other. targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); } public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception { // Setup a device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // Set up a managed profile managed by different package. final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); final ComponentName adminDifferentPackage = new ComponentName("another.package", "whatever.class"); addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); // Setting affiliation ids final Set userAffiliationIds = Collections.singleton("some-affiliation-id"); dpm.setAffiliationIds(admin1, userAffiliationIds); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); // Calling from device owner admin, we should get zero bind device admin target users as // their packages are different. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; List targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); // Calling from managed profile admin, we should still get zero target users for the same // reason. mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage); MoreAsserts.assertEmpty(targetUsers); } public void testLockTaskPackagesAllowedForAffiliatedUsers() throws Exception { // Setup a device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // Lock task packages are updated when loading user data. verify(mContext.iactivityManager) .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(new String[0])); // Set up a managed profile managed by different package (package name shouldn't matter) final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); final ComponentName adminDifferentPackage = new ComponentName("another.package", "whatever.class"); addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); verify(mContext.iactivityManager) .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0])); // The DO can still set lock task packages mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; final String[] doPackages = {"doPackage1", "doPackage2"}; dpm.setLockTaskPackages(admin1, doPackages); MoreAsserts.assertEquals(doPackages, dpm.getLockTaskPackages(admin1)); assertTrue(dpm.isLockTaskPermitted("doPackage1")); assertFalse(dpm.isLockTaskPermitted("anotherPackage")); verify(mContext.iactivityManager) .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(doPackages)); // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages. mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; final String[] poPackages = {"poPackage1", "poPackage2"}; try { dpm.setLockTaskPackages(adminDifferentPackage, poPackages); fail("Didn't throw expected security exception."); } catch (SecurityException expected) { } try { dpm.getLockTaskPackages(adminDifferentPackage); fail("Didn't throw expected security exception."); } catch (SecurityException expected) { } assertFalse(dpm.isLockTaskPermitted("doPackage1")); // Setting same affiliation ids final Set userAffiliationIds = Collections.singleton("some-affiliation-id"); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; dpm.setAffiliationIds(admin1, userAffiliationIds); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); // Now the managed profile can set lock task packages. dpm.setLockTaskPackages(adminDifferentPackage, poPackages); MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage)); assertTrue(dpm.isLockTaskPermitted("poPackage1")); assertFalse(dpm.isLockTaskPermitted("doPackage2")); verify(mContext.iactivityManager) .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(poPackages)); // Unaffiliate the profile, lock task mode no longer available on the profile. dpm.setAffiliationIds(adminDifferentPackage, Collections.emptySet()); assertFalse(dpm.isLockTaskPermitted("poPackage1")); // Lock task packages cleared when loading user data and when the user becomes unaffiliated. verify(mContext.iactivityManager, times(2)) .updateLockTaskPackages(eq(MANAGED_PROFILE_USER_ID), eq(new String[0])); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; assertTrue(dpm.isLockTaskPermitted("doPackage1")); } public void testIsDeviceManaged() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // The device owner itself, any uid holding MANAGE_USERS permission and the system can // find out that the device has a device owner. assertTrue(dpm.isDeviceManaged()); mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertTrue(dpm.isDeviceManaged()); mContext.callerPermissions.remove(permission.MANAGE_USERS); mContext.binder.clearCallingIdentity(); assertTrue(dpm.isDeviceManaged()); clearDeviceOwner(); // Any uid holding MANAGE_USERS permission and the system can find out that the device does // not have a device owner. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertFalse(dpm.isDeviceManaged()); mContext.callerPermissions.remove(permission.MANAGE_USERS); mContext.binder.clearCallingIdentity(); assertFalse(dpm.isDeviceManaged()); } public void testDeviceOwnerOrganizationName() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); dpm.setOrganizationName(admin1, "organization"); // Device owner can retrieve organization managing the device. assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); // Any uid holding MANAGE_USERS permission can retrieve organization managing the device. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve organization managing the device. mContext.binder.clearCallingIdentity(); assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); // Removing the device owner clears the organization managing the device. clearDeviceOwner(); assertNull(dpm.getDeviceOwnerOrganizationName()); } public void testWipeDataManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; // Even if the caller is the managed profile, the current user is the user 0 when(mContext.iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); dpm.wipeData(0); verify(mContext.userManagerInternal).removeUserEvenWhenDisallowed( MANAGED_PROFILE_USER_ID); } public void testWipeDataManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Even if the caller is the managed profile, the current user is the user 0 when(mContext.iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.of(MANAGED_PROFILE_USER_ID))) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; try { // The PO is not allowed to remove the profile if the user restriction was set on the // profile by the system dpm.wipeData(0); fail("SecurityException not thrown"); } catch (SecurityException expected) { } } public void testWipeDataDeviceOwner() throws Exception { setDeviceOwner(); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM)) .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); dpm.wipeData(0); verify(mContext.recoverySystem).rebootWipeUserData( /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true)); } public void testWipeDataDeviceOwnerDisallowed() throws Exception { setDeviceOwner(); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM)) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); try { // The DO is not allowed to wipe the device if the user restriction was set // by the system dpm.wipeData(0); fail("SecurityException not thrown"); } catch (SecurityException expected) { } } public void testMaximumFailedPasswordAttemptsReachedManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Even if the caller is the managed profile, the current user is the user 0 when(mContext.iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.of(MANAGED_PROFILE_USER_ID))) .thenReturn(UserManager.RESTRICTION_SOURCE_PROFILE_OWNER); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setMaximumFailedPasswordsForWipe(admin1, 3); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); // Failed password attempts on the parent user are taken into account, as there isn't a // separate work challenge. dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); // The profile should be wiped even if DISALLOW_REMOVE_MANAGED_PROFILE is enabled, because // both the user restriction and the policy were set by the PO. verify(mContext.userManagerInternal).removeUserEvenWhenDisallowed( MANAGED_PROFILE_USER_ID); verifyZeroInteractions(mContext.recoverySystem); } public void testMaximumFailedPasswordAttemptsReachedManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); // Even if the caller is the managed profile, the current user is the user 0 when(mContext.iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.of(MANAGED_PROFILE_USER_ID))) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setMaximumFailedPasswordsForWipe(admin1, 3); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); // Failed password attempts on the parent user are taken into account, as there isn't a // separate work challenge. dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); // DISALLOW_REMOVE_MANAGED_PROFILE was set by the system, not the PO, so the profile is // not wiped. verify(mContext.userManagerInternal, never()) .removeUserEvenWhenDisallowed(anyInt()); verifyZeroInteractions(mContext.recoverySystem); } public void testMaximumFailedPasswordAttemptsReachedDeviceOwner() throws Exception { setDeviceOwner(); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM)) .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); dpm.setMaximumFailedPasswordsForWipe(admin1, 3); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); // The device should be wiped even if DISALLOW_FACTORY_RESET is enabled, because both the // user restriction and the policy were set by the DO. verify(mContext.recoverySystem).rebootWipeUserData( /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true)); } public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception { setDeviceOwner(); when(mContext.userManager.getUserRestrictionSource( UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM)) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); dpm.setMaximumFailedPasswordsForWipe(admin1, 3); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM); // DISALLOW_FACTORY_RESET was set by the system, not the DO, so the device is not wiped. verifyZeroInteractions(mContext.recoverySystem); verify(mContext.userManagerInternal, never()) .removeUserEvenWhenDisallowed(anyInt()); } public void testGetPermissionGrantState() throws Exception { final String permission = "some.permission"; final String app1 = "com.example.app1"; final String app2 = "com.example.app2"; when(mContext.ipackageManager.checkPermission(eq(permission), eq(app1), anyInt())) .thenReturn(PackageManager.PERMISSION_GRANTED); doReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED).when(mContext.packageManager) .getPermissionFlags(permission, app1, UserHandle.SYSTEM); when(mContext.packageManager.getPermissionFlags(permission, app1, UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))) .thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED); when(mContext.ipackageManager.checkPermission(eq(permission), eq(app2), anyInt())) .thenReturn(PackageManager.PERMISSION_DENIED); doReturn(0).when(mContext.packageManager).getPermissionFlags(permission, app2, UserHandle.SYSTEM); when(mContext.packageManager.getPermissionFlags(permission, app2, UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(0); // System can retrieve permission grant state. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = "com.example.system"; assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, dpm.getPermissionGrantState(null, app1, permission)); assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT, dpm.getPermissionGrantState(null, app2, permission)); // A regular app cannot retrieve permission grant state. mContext.binder.callingUid = setupPackageInPackageManager(app1, 1); mContext.packageName = app1; try { dpm.getPermissionGrantState(null, app1, permission); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } // Profile owner can retrieve permission grant state. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); setAsProfileOwner(admin1); assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, dpm.getPermissionGrantState(admin1, app1, permission)); assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT, dpm.getPermissionGrantState(admin1, app2, permission)); } public void testResetPasswordWithToken() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // test token validation try { dpm.setResetPasswordToken(admin1, new byte[31]); fail("should not have accepted tokens too short"); } catch (IllegalArgumentException expected) { } // test adding a token final byte[] token = new byte[32]; final long handle = 123456; final String password = "password"; when(mContext.lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM))) .thenReturn(handle); assertTrue(dpm.setResetPasswordToken(admin1, token)); // test password activation when(mContext.lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM))) .thenReturn(true); assertTrue(dpm.isResetPasswordTokenActive(admin1)); // test reset password with token when(mContext.lockPatternUtils.setLockCredentialWithToken(eq(password), eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), eq(handle), eq(token), eq(UserHandle.USER_SYSTEM))) .thenReturn(true); assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0)); // test removing a token when(mContext.lockPatternUtils.removeEscrowToken(eq(handle), eq(UserHandle.USER_SYSTEM))) .thenReturn(true); assertTrue(dpm.clearResetPasswordToken(admin1)); } public void testIsCurrentInputMethodSetByOwnerForDeviceOwner() throws Exception { final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD; final Uri currentImeUri = Settings.Secure.getUriFor(currentIme); final int deviceOwnerUid = DpmMockContext.CALLER_SYSTEM_USER_UID; final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM, DpmMockContext.SYSTEM_UID); final int secondUserSystemUid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); // Set up a device owner. mContext.binder.callingUid = deviceOwnerUid; setupDeviceOwner(); // First and second user set IMEs manually. mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Device owner changes IME for first user. mContext.binder.callingUid = deviceOwnerUid; when(mContext.settings.settingsSecureGetStringForUser(currentIme, UserHandle.USER_SYSTEM)) .thenReturn("ime1"); dpm.setSecureSetting(admin1, currentIme, "ime2"); verify(mContext.settings).settingsSecurePutStringForUser(currentIme, "ime2", UserHandle.USER_SYSTEM); reset(mContext.settings); dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Second user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // First user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Device owner changes IME for first user again. mContext.binder.callingUid = deviceOwnerUid; when(mContext.settings.settingsSecureGetStringForUser(currentIme, UserHandle.USER_SYSTEM)) .thenReturn("ime2"); dpm.setSecureSetting(admin1, currentIme, "ime3"); verify(mContext.settings).settingsSecurePutStringForUser(currentIme, "ime3", UserHandle.USER_SYSTEM); dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Restarting the DPMS should not lose information. initializeDpms(); mContext.binder.callingUid = firstUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Device owner can find out whether it set the current IME itself. mContext.binder.callingUid = deviceOwnerUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // Removing the device owner should clear the information that it set the current IME. clearDeviceOwner(); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); } public void testIsCurrentInputMethodSetByOwnerForProfileOwner() throws Exception { final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD; final Uri currentImeUri = Settings.Secure.getUriFor(currentIme); final int profileOwnerUid = DpmMockContext.CALLER_UID; final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM, DpmMockContext.SYSTEM_UID); final int secondUserSystemUid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); // Set up a profile owner. mContext.binder.callingUid = profileOwnerUid; setupProfileOwner(); // First and second user set IMEs manually. mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Profile owner changes IME for second user. mContext.binder.callingUid = profileOwnerUid; when(mContext.settings.settingsSecureGetStringForUser(currentIme, DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime1"); dpm.setSecureSetting(admin1, currentIme, "ime2"); verify(mContext.settings).settingsSecurePutStringForUser(currentIme, "ime2", DpmMockContext.CALLER_USER_HANDLE); reset(mContext.settings); dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // First user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // Second user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); // Profile owner changes IME for second user again. mContext.binder.callingUid = profileOwnerUid; when(mContext.settings.settingsSecureGetStringForUser(currentIme, DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime2"); dpm.setSecureSetting(admin1, currentIme, "ime3"); verify(mContext.settings).settingsSecurePutStringForUser(currentIme, "ime3", DpmMockContext.CALLER_USER_HANDLE); dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // Restarting the DPMS should not lose information. initializeDpms(); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // Profile owner can find out whether it set the current IME itself. mContext.binder.callingUid = profileOwnerUid; assertTrue(dpm.isCurrentInputMethodSetByOwner()); // Removing the profile owner should clear the information that it set the current IME. dpm.clearProfileOwner(admin1); mContext.binder.callingUid = firstUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); mContext.binder.callingUid = secondUserSystemUid; assertFalse(dpm.isCurrentInputMethodSetByOwner()); } public void testSetPermittedCrossProfileNotificationListeners_unavailableForDo() throws Exception { // Set up a device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid); } public void testSetPermittedCrossProfileNotificationListeners_unavailableForPoOnUser() throws Exception { // Set up a profile owner. mContext.binder.callingUid = DpmMockContext.CALLER_UID; setupProfileOwner(); assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid); } private void assertSetPermittedCrossProfileNotificationListenersUnavailable( int adminUid) throws Exception { mContext.binder.callingUid = adminUid; final int userId = UserHandle.getUserId(adminUid); final String packageName = "some.package"; assertFalse(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.singletonList(packageName))); assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId)); // Attempt to set to empty list (which means no listener is whitelisted) mContext.binder.callingUid = adminUid; assertFalse(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.emptyList())); assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId)); } public void testIsNotificationListenerServicePermitted_onlySystemCanCall() throws Exception { // Set up a managed profile final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; final String permittedListener = "some.package"; setupPackageInPackageManager( permittedListener, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. /*appId=*/ 12345, /*flags=*/ 0); assertTrue(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.singletonList(permittedListener))); try { dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID); fail("isNotificationListenerServicePermitted should throw if not called from System"); } catch (SecurityException expected) { } mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID)); } public void testSetPermittedCrossProfileNotificationListeners_managedProfile() throws Exception { // Set up a managed profile final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; final String permittedListener = "permitted.package"; int appId = 12345; setupPackageInPackageManager( permittedListener, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. appId, /*flags=*/ 0); final String notPermittedListener = "not.permitted.package"; setupPackageInPackageManager( notPermittedListener, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. ++appId, /*flags=*/ 0); final String systemListener = "system.package"; setupPackageInPackageManager( systemListener, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. ++appId, ApplicationInfo.FLAG_SYSTEM); // By default all packages are allowed assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( notPermittedListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); // Setting only one package in the whitelist mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; assertTrue(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.singletonList(permittedListener))); List permittedListeners = dpms.getPermittedCrossProfileNotificationListeners(admin1); assertEquals(1, permittedListeners.size()); assertEquals(permittedListener, permittedListeners.get(0)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID)); assertFalse(dpms.isNotificationListenerServicePermitted( notPermittedListener, MANAGED_PROFILE_USER_ID)); // System packages are always allowed (even if not in the whitelist) assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); // Setting an empty whitelist - only system listeners allowed mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; assertTrue(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.emptyList())); assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size()); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertFalse(dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID)); assertFalse(dpms.isNotificationListenerServicePermitted( notPermittedListener, MANAGED_PROFILE_USER_ID)); // System packages are always allowed (even if not in the whitelist) assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); // Setting a null whitelist - all listeners allowed mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; assertTrue(dpms.setPermittedCrossProfileNotificationListeners(admin1, null)); assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted( permittedListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( notPermittedListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); } public void testSetPermittedCrossProfileNotificationListeners_doesNotAffectPrimaryProfile() throws Exception { // Set up a managed profile final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; final String nonSystemPackage = "non.system.package"; int appId = 12345; setupPackageInPackageManager( nonSystemPackage, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. appId, /*flags=*/ 0); final String systemListener = "system.package"; setupPackageInPackageManager( systemListener, UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. ++appId, ApplicationInfo.FLAG_SYSTEM); // By default all packages are allowed (for all profiles) assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertTrue(dpms.isNotificationListenerServicePermitted( nonSystemPackage, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( nonSystemPackage, UserHandle.USER_SYSTEM)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, UserHandle.USER_SYSTEM)); // Setting an empty whitelist - only system listeners allowed in managed profile, but // all allowed in primary profile mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; assertTrue(dpms.setPermittedCrossProfileNotificationListeners( admin1, Collections.emptyList())); assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size()); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; assertFalse(dpms.isNotificationListenerServicePermitted( nonSystemPackage, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, MANAGED_PROFILE_USER_ID)); assertTrue(dpms.isNotificationListenerServicePermitted( nonSystemPackage, UserHandle.USER_SYSTEM)); assertTrue(dpms.isNotificationListenerServicePermitted( systemListener, UserHandle.USER_SYSTEM)); } public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception { mContext.packageName = mRealTestContext.getPackageName(); setDeviceOwner(); final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); caller.packageName = admin1.getPackageName(); caller.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; verifyCanGetOwnerInstalledCaCerts(admin1, caller); } public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception { mContext.packageName = mRealTestContext.getPackageName(); setAsProfileOwner(admin1); final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); caller.packageName = admin1.getPackageName(); caller.binder.callingUid = DpmMockContext.CALLER_UID; verifyCanGetOwnerInstalledCaCerts(admin1, caller); verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, caller); } public void testGetOwnerInstalledCaCertsForDelegate() throws Exception { mContext.packageName = mRealTestContext.getPackageName(); setAsProfileOwner(admin1); final String delegate = "com.example.delegate"; final int delegateUid = setupPackageInPackageManager(delegate, 20988); dpm.setCertInstallerPackage(admin1, delegate); final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); caller.packageName = delegate; caller.binder.callingUid = delegateUid; verifyCanGetOwnerInstalledCaCerts(null, caller); verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller); } private void verifyCanGetOwnerInstalledCaCerts( final ComponentName caller, final DpmMockContext callerContext) throws Exception { final String alias = "cert"; final byte[] caCert = TEST_CA.getBytes(); // device admin (used for posting the tls notification) final DpmMockContext admin1Context; if (admin1.getPackageName().equals(callerContext.getPackageName())) { admin1Context = callerContext; } else { admin1Context = new DpmMockContext(mRealTestContext, "test-admin"); admin1Context.packageName = admin1.getPackageName(); admin1Context.applicationInfo = new ApplicationInfo(); } when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); // caller: device admin or delegated certificate installer callerContext.applicationInfo = new ApplicationInfo(); final UserHandle callerUser = callerContext.binder.getCallingUserHandle(); // system_server final DpmMockContext serviceContext = mContext; serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; serviceContext.addPackageContext(callerUser, admin1Context); serviceContext.addPackageContext(callerUser, callerContext); // Install a CA cert. runAsCaller(callerContext, dpms, (dpm) -> { when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) .thenReturn(alias); assertTrue(dpm.installCaCert(caller, caCert)); when(mContext.keyChainConnection.getService().getUserCaAliases()) .thenReturn(asSlice(new String[] {alias})); }); serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); final List ownerInstalledCaCerts = new ArrayList<>(); // Device Owner / Profile Owner can find out which CA certs were installed by itself. runAsCaller(admin1Context, dpms, (dpm) -> { final List installedCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); assertEquals(Arrays.asList(alias), installedCaCerts); ownerInstalledCaCerts.addAll(installedCaCerts); }); // Restarting the DPMS should not lose information. initializeDpms(); runAsCaller(admin1Context, dpms, (dpm) -> { assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)); }); // System can find out which CA certs were installed by the Device Owner / Profile Owner. runAsCaller(serviceContext, dpms, (dpm) -> { assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)); // Remove the CA cert. reset(mContext.keyChainConnection.getService()); }); serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile // Owner. runAsCaller(admin1Context, dpms, (dpm) -> { MoreAsserts.assertEmpty(dpm.getOwnerInstalledCaCerts(callerUser)); }); } private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval( final ComponentName callerName, final DpmMockContext callerContext) throws Exception { final String alias = "cert"; final byte[] caCert = TEST_CA.getBytes(); // device admin (used for posting the tls notification) final DpmMockContext admin1Context; if (admin1.getPackageName().equals(callerContext.getPackageName())) { admin1Context = callerContext; } else { admin1Context = new DpmMockContext(mRealTestContext, "test-admin"); admin1Context.packageName = admin1.getPackageName(); admin1Context.applicationInfo = new ApplicationInfo(); } when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); // caller: device admin or delegated certificate installer callerContext.applicationInfo = new ApplicationInfo(); final UserHandle callerUser = callerContext.binder.getCallingUserHandle(); // system_server final DpmMockContext serviceContext = mContext; serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; serviceContext.addPackageContext(callerUser, admin1Context); serviceContext.addPackageContext(callerUser, callerContext); // Install a CA cert as caller runAsCaller(callerContext, dpms, (dpm) -> { when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) .thenReturn(alias); assertTrue(dpm.installCaCert(callerName, caCert)); }); // Fake the CA cert as having been installed when(serviceContext.keyChainConnection.getService().getUserCaAliases()) .thenReturn(asSlice(new String[] {alias})); serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); // Removing the Profile Owner should clear the information on which CA certs were installed runAsCaller(admin1Context, dpms, (dpm) -> { dpm.clearProfileOwner(admin1); }); runAsCaller(serviceContext, dpms, (dpm) -> { final List ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); assertNotNull(ownerInstalledCaCerts); assertTrue(ownerInstalledCaCerts.isEmpty()); }); } private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, userhandle)).thenReturn(isUserSetupComplete ? 1 : 0); dpms.notifyChangeToContentObserver( Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle); } private void assertProvisioningAllowed(String action, boolean expected) { assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected, dpm.isProvisioningAllowed(action)); } private void assertProvisioningAllowed(String action, boolean expected, String packageName, int uid) { String previousPackageName = mContext.packageName; int previousUid = mMockContext.binder.callingUid; // Call assertProvisioningAllowed with the packageName / uid passed as arguments. mContext.packageName = packageName; mMockContext.binder.callingUid = uid; assertProvisioningAllowed(action, expected); // Set the previous package name / calling uid to go back to the initial state. mContext.packageName = previousPackageName; mMockContext.binder.callingUid = previousUid; } private void assertCheckProvisioningPreCondition(String action, int provisioningCondition) { assertCheckProvisioningPreCondition(action, admin1.getPackageName(), provisioningCondition); } private void assertCheckProvisioningPreCondition( String action, String packageName, int provisioningCondition) { assertEquals("checkProvisioningPreCondition(" + action + ", " + packageName + ") returning unexpected result", provisioningCondition, dpm.checkProvisioningPreCondition(action, packageName)); } /** * Setup a managed profile with the specified admin and its uid. * @param admin ComponentName that's visible to the test code, which doesn't have to exist. * @param adminUid uid of the admin package. * @param copyFromAdmin package information for {@code admin} will be built based on this * component's information. */ private void addManagedProfile( ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception { final int userId = UserHandle.getUserId(adminUid); mContext.addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM); mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin); dpm.setActiveAdmin(admin, false, userId); assertTrue(dpm.setProfileOwner(admin, null, userId)); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } /** * Convert String[] to StringParceledListSlice. */ private static StringParceledListSlice asSlice(String[] s) { return new StringParceledListSlice(Arrays.asList(s)); } private void flushTasks() throws Exception { dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/); dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/); // We can't let exceptions happen on the background thread. Throw them here if they happen // so they still cause the test to fail despite being suppressed. mContext.rethrowBackgroundBroadcastExceptions(); } }