Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +99 −38 Original line number Original line Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIAN import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; Loading Loading @@ -883,12 +884,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { synchronized (getLockObject()) { // Check whether the user is affiliated, *before* removing its data. // Check whether the user is affiliated, *before* removing its data. boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle); boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle); if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) { // Disable network and security logging mInjector.securityLogSetLoggingEnabledProperty(false); mSecurityLogMonitor.stop(); setNetworkLoggingActiveInternal(false); } removeUserData(userHandle); removeUserData(userHandle); if (!isRemovedUserAffiliated) { if (!isRemovedUserAffiliated) { // We discard the logs when unaffiliated users are deleted (so that the // We discard the logs when unaffiliated users are deleted (so that the Loading Loading @@ -1779,6 +1774,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } void removeUserData(int userHandle) { void removeUserData(int userHandle) { final boolean isOrgOwned; synchronized (getLockObject()) { synchronized (getLockObject()) { if (userHandle == UserHandle.USER_SYSTEM) { if (userHandle == UserHandle.USER_SYSTEM) { Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); Loading @@ -1786,6 +1782,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } updatePasswordQualityCacheForUserGroup(userHandle); updatePasswordQualityCacheForUserGroup(userHandle); mPolicyCache.onUserRemoved(userHandle); mPolicyCache.onUserRemoved(userHandle); isOrgOwned = mOwners.isProfileOwnerOfOrganizationOwnedDevice(userHandle); mOwners.removeProfileOwner(userHandle); mOwners.removeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); Loading @@ -1799,6 +1798,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policyFile.delete(); policyFile.delete(); Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } } if (isOrgOwned) { final UserInfo primaryUser = mUserManager.getPrimaryUser(); if (primaryUser != null) { clearOrgOwnedProfileOwnerDeviceWidePolicies(primaryUser.id); } else { Slogf.wtf(LOG_TAG, "Was unable to get primary user."); } } } } /** /** Loading Loading @@ -3537,6 +3544,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call " "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call " + "forceRemoveActiveAdmin"); + "forceRemoveActiveAdmin"); mInjector.binderWithCleanCallingIdentity(() -> { mInjector.binderWithCleanCallingIdentity(() -> { boolean isOrgOwnedProfile = false; synchronized (getLockObject()) { synchronized (getLockObject()) { if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) { if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) { throw new SecurityException("Attempt to remove non-test admin " throw new SecurityException("Attempt to remove non-test admin " Loading @@ -3548,13 +3556,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle); clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle); } } if (isProfileOwner(adminReceiver, userHandle)) { if (isProfileOwner(adminReceiver, userHandle)) { if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) { isOrgOwnedProfile = isProfileOwnerOfOrganizationOwnedDevice(userHandle); UserHandle parentUserHandle = UserHandle.of(getProfileParentId(userHandle)); mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle); mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, parentUserHandle); } final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle, /* parent */ false); userHandle, /* parent */ false); clearProfileOwnerLocked(admin, userHandle); clearProfileOwnerLocked(admin, userHandle); Loading @@ -3562,11 +3564,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } // Remove the admin skipping sending the broadcast. // Remove the admin skipping sending the broadcast. removeAdminArtifacts(adminReceiver, userHandle); removeAdminArtifacts(adminReceiver, userHandle); // In case of PO on org owned device, clean device-wide policies and restrictions. if (isOrgOwnedProfile) { final UserHandle parentUser = UserHandle.of(getProfileParentId(userHandle)); clearOrgOwnedProfileOwnerUserRestrictions(parentUser); clearOrgOwnedProfileOwnerDeviceWidePolicies(parentUser.getIdentifier()); } Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle); Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle); }); }); } } private void clearDeviceOwnerUserRestrictionLocked(UserHandle userHandle) { private void clearOrgOwnedProfileOwnerUserRestrictions(UserHandle parentUserHandle) { mUserManager.setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle); mUserManager.setUserRestriction( UserManager.DISALLOW_ADD_USER, false, parentUserHandle); } private void clearDeviceOwnerUserRestriction(UserHandle userHandle) { // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); Loading Loading @@ -6710,25 +6727,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // when wipeData is _not_ called on the parent instance, it implies relinquishing // when wipeData is _not_ called on the parent instance, it implies relinquishing // control over the device, wiping only the work profile. So the user restriction // control over the device, wiping only the work profile. So the user restriction // on profile removal needs to be removed first. // on profile removal needs to be removed first. final UserHandle parentUser = UserHandle.of(getProfileParentId(userId)); mInjector.binderWithCleanCallingIdentity(() -> { mInjector.binderWithCleanCallingIdentity( // Clear restriction as user. () -> clearOrgOwnedProfileOwnerUserRestrictions(parentUser)); mUserManager.setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM); mUserManager.setUserRestriction( UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM); // Device-wide policies set by the profile owner need to be cleaned up here. mLockPatternUtils.setDeviceOwnerInfo(null); }); } } } } DevicePolicyEventLogger event = DevicePolicyEventLogger DevicePolicyEventLogger event = DevicePolicyEventLogger .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON) .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON) .setInt(flags) .setInt(flags) .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT) .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT); ; final String adminName; final String adminName; final ComponentName adminComp; final ComponentName adminComp; if (admin != null) { if (admin != null) { Loading @@ -6755,6 +6763,55 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId); wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId); } } /** * Clears device wide policies enforced by COPE PO when relinquishing the device. This method * should be invoked once the admin is gone, so that all methods that rely on calculating * aggregate policy (e.g. strong auth timeout) from all admins aren't affected by its policies. * This method assumes that there is no other device or profile owners left on the device. * Shouldn't be called from binder thread without clearing identity. */ private void clearOrgOwnedProfileOwnerDeviceWidePolicies(@UserIdInt int parentId) { Slogf.i(LOG_TAG, "Cleaning up device-wide policies left over from org-owned profile..."); // Lockscreen message mLockPatternUtils.setDeviceOwnerInfo(null); // Wifi config lockdown mInjector.settingsGlobalPutInt(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); // Security logging if (mInjector.securityLogGetLoggingEnabledProperty()) { mSecurityLogMonitor.stop(); mInjector.securityLogSetLoggingEnabledProperty(false); } // Network logging setNetworkLoggingActiveInternal(false); // System update policy. final boolean hasSystemUpdatePolicy; synchronized (getLockObject()) { hasSystemUpdatePolicy = mOwners.getSystemUpdatePolicy() != null; if (hasSystemUpdatePolicy) { mOwners.clearSystemUpdatePolicy(); mOwners.writeDeviceOwner(); } } if (hasSystemUpdatePolicy) { mContext.sendBroadcastAsUser( new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM); } // Unsuspend personal apps if needed. suspendPersonalAppsInternal(parentId, false); // Notify FRP agent, LSS and WindowManager to ensure they don't hold on to stale policies. final int frpAgentUid = getFrpManagementAgentUid(); if (frpAgentUid > 0) { notifyResetProtectionPolicyChanged(frpAgentUid); } mLockSettingsInternal.refreshStrongAuthTimeout(parentId); updateScreenCaptureDisabled(parentId, getScreenCaptureDisabled(null, parentId, false)); Slogf.i(LOG_TAG, "Cleaning up device-wide policies done."); } private void wipeDataNoLock(ComponentName admin, int flags, String internalReason, private void wipeDataNoLock(ComponentName admin, int flags, String internalReason, String wipeReasonForUser, int userId) { String wipeReasonForUser, int userId) { wtfIfInLock(); wtfIfInLock(); Loading Loading @@ -6822,13 +6879,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(caller.getUserId()); saveSettingsLocked(caller.getUserId()); } } final Intent intent = new Intent( mInjector.binderWithCleanCallingIdentity( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags( () -> notifyResetProtectionPolicyChanged(frpManagementAgentUid)); Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(frpManagementAgentUid), android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION)); DevicePolicyEventLogger DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION) .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION) Loading @@ -6836,6 +6888,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); .write(); } } // Shouldn't be called from binder thread without clearing identity. private void notifyResetProtectionPolicyChanged(int frpManagementAgentUid) { final Intent intent = new Intent( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags( Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(frpManagementAgentUid), permission.MANAGE_FACTORY_RESET_PROTECTION); } @Override @Override public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( @Nullable ComponentName who) { @Nullable ComponentName who) { Loading Loading @@ -8506,7 +8568,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.writeDeviceOwner(); mOwners.writeDeviceOwner(); updateDeviceOwnerLocked(); updateDeviceOwnerLocked(); clearDeviceOwnerUserRestrictionLocked(UserHandle.of(userId)); clearDeviceOwnerUserRestriction(UserHandle.of(userId)); mInjector.securityLogSetLoggingEnabledProperty(false); mInjector.securityLogSetLoggingEnabledProperty(false); mSecurityLogMonitor.stop(); mSecurityLogMonitor.stop(); setNetworkLoggingActiveInternal(false); setNetworkLoggingActiveInternal(false); Loading Loading @@ -12936,8 +12998,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.writeDeviceOwner(); mOwners.writeDeviceOwner(); } } mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED), new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM)); UserHandle.SYSTEM)); DevicePolicyEventLogger DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY) .createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY) .setAdmin(who) .setAdmin(who) services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +69 −6 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChang import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION; import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE; import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.testutils.TestUtils.assertExpectException; import static com.android.server.testutils.TestUtils.assertExpectException; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -82,6 +83,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.PasswordMetrics; import android.app.admin.PasswordMetrics; import android.app.admin.SystemUpdatePolicy; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.Intent; import android.content.Intent; Loading Loading @@ -3939,10 +3941,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Enabling logging should not change the timestamp. // Enabling logging should not change the timestamp. dpm.setSecurityLoggingEnabled(admin1, true); dpm.setSecurityLoggingEnabled(admin1, true); verify(getServices().settings) verify(getServices().settings).securityLogSetLoggingEnabledProperty(true); .securityLogSetLoggingEnabledProperty(true); when(getServices().settings.securityLogGetLoggingEnabledProperty()) when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true); .thenReturn(true); assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); // Retrieving the logs should update the timestamp. // Retrieving the logs should update the timestamp. Loading Loading @@ -4767,14 +4768,76 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().iactivityManager.getCurrentUser()) when(getServices().iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Get mock reason string since we throw an IAE with empty string input. // Get mock reason string since we throw an IAE with empty string input. when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)). when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)) thenReturn("Just a test string."); .thenReturn("Just a test string."); dpm.wipeData(0); dpm.wipeData(0); verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed( verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed( MANAGED_PROFILE_USER_ID); MANAGED_PROFILE_USER_ID); } } @Test public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); // Even if the caller is the managed profile, the current user is the user 0 when(getServices().iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Get mock reason string since we throw an IAE with empty string input. when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)) .thenReturn("Just a test string."); when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE)) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(getServices().userManager.getPrimaryUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Set some device-wide policies: // Security logging when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true); // System update policy dpms.mOwners.setSystemUpdatePolicy(SystemUpdatePolicy.createAutomaticInstallPolicy()); // Make it look as if FRP agent is present. when(dpms.mMockInjector.getPersistentDataBlockManagerInternal().getAllowedUid()) .thenReturn(12345 /* some UID in user 0 */); // Make personal apps look suspended dpms.getUserData(UserHandle.USER_SYSTEM).mAppsSuspended = true; clearInvocations(getServices().iwindowManager); dpm.wipeData(0); verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(CALLER_USER_HANDLE); // Make sure COPE restrictions are lifted: verify(getServices().userManager).setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM); verify(getServices().userManager).setUserRestriction( UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM); // Some device-wide policies are getting cleaned-up after the user is removed. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; sendBroadcastWithUser(dpms, Intent.ACTION_USER_REMOVED, CALLER_USER_HANDLE); // Screenlock info should be removed verify(getServices().lockPatternUtils).setDeviceOwnerInfo(null); // Wifi config lockdown should be lifted verify(getServices().settings).settingsGlobalPutInt( Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); // System update policy should be removed assertThat(dpms.mOwners.getSystemUpdatePolicy()).isNull(); // FRP agent should be notified verify(mContext.spiedContext, times(0)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); // Refresh strong auth timeout and screen capture verify(getServices().lockSettingsInternal).refreshStrongAuthTimeout(UserHandle.USER_SYSTEM); verify(getServices().iwindowManager).refreshScreenCaptureDisabled(UserHandle.USER_SYSTEM); // Unsuspend personal apps verify(getServices().packageManagerInternal) .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM); } @Test @Test public void testWipeDataManagedProfileDisallowed() throws Exception { public void testWipeDataManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_USER_ID = 15; Loading Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +99 −38 Original line number Original line Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIAN import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; Loading Loading @@ -883,12 +884,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { synchronized (getLockObject()) { // Check whether the user is affiliated, *before* removing its data. // Check whether the user is affiliated, *before* removing its data. boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle); boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle); if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) { // Disable network and security logging mInjector.securityLogSetLoggingEnabledProperty(false); mSecurityLogMonitor.stop(); setNetworkLoggingActiveInternal(false); } removeUserData(userHandle); removeUserData(userHandle); if (!isRemovedUserAffiliated) { if (!isRemovedUserAffiliated) { // We discard the logs when unaffiliated users are deleted (so that the // We discard the logs when unaffiliated users are deleted (so that the Loading Loading @@ -1779,6 +1774,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } void removeUserData(int userHandle) { void removeUserData(int userHandle) { final boolean isOrgOwned; synchronized (getLockObject()) { synchronized (getLockObject()) { if (userHandle == UserHandle.USER_SYSTEM) { if (userHandle == UserHandle.USER_SYSTEM) { Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); Loading @@ -1786,6 +1782,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } updatePasswordQualityCacheForUserGroup(userHandle); updatePasswordQualityCacheForUserGroup(userHandle); mPolicyCache.onUserRemoved(userHandle); mPolicyCache.onUserRemoved(userHandle); isOrgOwned = mOwners.isProfileOwnerOfOrganizationOwnedDevice(userHandle); mOwners.removeProfileOwner(userHandle); mOwners.removeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); Loading @@ -1799,6 +1798,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policyFile.delete(); policyFile.delete(); Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } } if (isOrgOwned) { final UserInfo primaryUser = mUserManager.getPrimaryUser(); if (primaryUser != null) { clearOrgOwnedProfileOwnerDeviceWidePolicies(primaryUser.id); } else { Slogf.wtf(LOG_TAG, "Was unable to get primary user."); } } } } /** /** Loading Loading @@ -3537,6 +3544,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call " "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call " + "forceRemoveActiveAdmin"); + "forceRemoveActiveAdmin"); mInjector.binderWithCleanCallingIdentity(() -> { mInjector.binderWithCleanCallingIdentity(() -> { boolean isOrgOwnedProfile = false; synchronized (getLockObject()) { synchronized (getLockObject()) { if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) { if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) { throw new SecurityException("Attempt to remove non-test admin " throw new SecurityException("Attempt to remove non-test admin " Loading @@ -3548,13 +3556,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle); clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle); } } if (isProfileOwner(adminReceiver, userHandle)) { if (isProfileOwner(adminReceiver, userHandle)) { if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) { isOrgOwnedProfile = isProfileOwnerOfOrganizationOwnedDevice(userHandle); UserHandle parentUserHandle = UserHandle.of(getProfileParentId(userHandle)); mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle); mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, parentUserHandle); } final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle, /* parent */ false); userHandle, /* parent */ false); clearProfileOwnerLocked(admin, userHandle); clearProfileOwnerLocked(admin, userHandle); Loading @@ -3562,11 +3564,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } // Remove the admin skipping sending the broadcast. // Remove the admin skipping sending the broadcast. removeAdminArtifacts(adminReceiver, userHandle); removeAdminArtifacts(adminReceiver, userHandle); // In case of PO on org owned device, clean device-wide policies and restrictions. if (isOrgOwnedProfile) { final UserHandle parentUser = UserHandle.of(getProfileParentId(userHandle)); clearOrgOwnedProfileOwnerUserRestrictions(parentUser); clearOrgOwnedProfileOwnerDeviceWidePolicies(parentUser.getIdentifier()); } Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle); Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle); }); }); } } private void clearDeviceOwnerUserRestrictionLocked(UserHandle userHandle) { private void clearOrgOwnedProfileOwnerUserRestrictions(UserHandle parentUserHandle) { mUserManager.setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle); mUserManager.setUserRestriction( UserManager.DISALLOW_ADD_USER, false, parentUserHandle); } private void clearDeviceOwnerUserRestriction(UserHandle userHandle) { // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); Loading Loading @@ -6710,25 +6727,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // when wipeData is _not_ called on the parent instance, it implies relinquishing // when wipeData is _not_ called on the parent instance, it implies relinquishing // control over the device, wiping only the work profile. So the user restriction // control over the device, wiping only the work profile. So the user restriction // on profile removal needs to be removed first. // on profile removal needs to be removed first. final UserHandle parentUser = UserHandle.of(getProfileParentId(userId)); mInjector.binderWithCleanCallingIdentity(() -> { mInjector.binderWithCleanCallingIdentity( // Clear restriction as user. () -> clearOrgOwnedProfileOwnerUserRestrictions(parentUser)); mUserManager.setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM); mUserManager.setUserRestriction( UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM); // Device-wide policies set by the profile owner need to be cleaned up here. mLockPatternUtils.setDeviceOwnerInfo(null); }); } } } } DevicePolicyEventLogger event = DevicePolicyEventLogger DevicePolicyEventLogger event = DevicePolicyEventLogger .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON) .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON) .setInt(flags) .setInt(flags) .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT) .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT); ; final String adminName; final String adminName; final ComponentName adminComp; final ComponentName adminComp; if (admin != null) { if (admin != null) { Loading @@ -6755,6 +6763,55 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId); wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId); } } /** * Clears device wide policies enforced by COPE PO when relinquishing the device. This method * should be invoked once the admin is gone, so that all methods that rely on calculating * aggregate policy (e.g. strong auth timeout) from all admins aren't affected by its policies. * This method assumes that there is no other device or profile owners left on the device. * Shouldn't be called from binder thread without clearing identity. */ private void clearOrgOwnedProfileOwnerDeviceWidePolicies(@UserIdInt int parentId) { Slogf.i(LOG_TAG, "Cleaning up device-wide policies left over from org-owned profile..."); // Lockscreen message mLockPatternUtils.setDeviceOwnerInfo(null); // Wifi config lockdown mInjector.settingsGlobalPutInt(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); // Security logging if (mInjector.securityLogGetLoggingEnabledProperty()) { mSecurityLogMonitor.stop(); mInjector.securityLogSetLoggingEnabledProperty(false); } // Network logging setNetworkLoggingActiveInternal(false); // System update policy. final boolean hasSystemUpdatePolicy; synchronized (getLockObject()) { hasSystemUpdatePolicy = mOwners.getSystemUpdatePolicy() != null; if (hasSystemUpdatePolicy) { mOwners.clearSystemUpdatePolicy(); mOwners.writeDeviceOwner(); } } if (hasSystemUpdatePolicy) { mContext.sendBroadcastAsUser( new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM); } // Unsuspend personal apps if needed. suspendPersonalAppsInternal(parentId, false); // Notify FRP agent, LSS and WindowManager to ensure they don't hold on to stale policies. final int frpAgentUid = getFrpManagementAgentUid(); if (frpAgentUid > 0) { notifyResetProtectionPolicyChanged(frpAgentUid); } mLockSettingsInternal.refreshStrongAuthTimeout(parentId); updateScreenCaptureDisabled(parentId, getScreenCaptureDisabled(null, parentId, false)); Slogf.i(LOG_TAG, "Cleaning up device-wide policies done."); } private void wipeDataNoLock(ComponentName admin, int flags, String internalReason, private void wipeDataNoLock(ComponentName admin, int flags, String internalReason, String wipeReasonForUser, int userId) { String wipeReasonForUser, int userId) { wtfIfInLock(); wtfIfInLock(); Loading Loading @@ -6822,13 +6879,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(caller.getUserId()); saveSettingsLocked(caller.getUserId()); } } final Intent intent = new Intent( mInjector.binderWithCleanCallingIdentity( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags( () -> notifyResetProtectionPolicyChanged(frpManagementAgentUid)); Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(frpManagementAgentUid), android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION)); DevicePolicyEventLogger DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION) .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION) Loading @@ -6836,6 +6888,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); .write(); } } // Shouldn't be called from binder thread without clearing identity. private void notifyResetProtectionPolicyChanged(int frpManagementAgentUid) { final Intent intent = new Intent( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags( Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(frpManagementAgentUid), permission.MANAGE_FACTORY_RESET_PROTECTION); } @Override @Override public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( @Nullable ComponentName who) { @Nullable ComponentName who) { Loading Loading @@ -8506,7 +8568,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.writeDeviceOwner(); mOwners.writeDeviceOwner(); updateDeviceOwnerLocked(); updateDeviceOwnerLocked(); clearDeviceOwnerUserRestrictionLocked(UserHandle.of(userId)); clearDeviceOwnerUserRestriction(UserHandle.of(userId)); mInjector.securityLogSetLoggingEnabledProperty(false); mInjector.securityLogSetLoggingEnabledProperty(false); mSecurityLogMonitor.stop(); mSecurityLogMonitor.stop(); setNetworkLoggingActiveInternal(false); setNetworkLoggingActiveInternal(false); Loading Loading @@ -12936,8 +12998,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.writeDeviceOwner(); mOwners.writeDeviceOwner(); } } mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED), new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM)); UserHandle.SYSTEM)); DevicePolicyEventLogger DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY) .createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY) .setAdmin(who) .setAdmin(who)
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +69 −6 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChang import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION; import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION; import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE; import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.testutils.TestUtils.assertExpectException; import static com.android.server.testutils.TestUtils.assertExpectException; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -82,6 +83,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.PasswordMetrics; import android.app.admin.PasswordMetrics; import android.app.admin.SystemUpdatePolicy; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.Intent; import android.content.Intent; Loading Loading @@ -3939,10 +3941,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Enabling logging should not change the timestamp. // Enabling logging should not change the timestamp. dpm.setSecurityLoggingEnabled(admin1, true); dpm.setSecurityLoggingEnabled(admin1, true); verify(getServices().settings) verify(getServices().settings).securityLogSetLoggingEnabledProperty(true); .securityLogSetLoggingEnabledProperty(true); when(getServices().settings.securityLogGetLoggingEnabledProperty()) when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true); .thenReturn(true); assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); // Retrieving the logs should update the timestamp. // Retrieving the logs should update the timestamp. Loading Loading @@ -4767,14 +4768,76 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().iactivityManager.getCurrentUser()) when(getServices().iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Get mock reason string since we throw an IAE with empty string input. // Get mock reason string since we throw an IAE with empty string input. when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)). when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)) thenReturn("Just a test string."); .thenReturn("Just a test string."); dpm.wipeData(0); dpm.wipeData(0); verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed( verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed( MANAGED_PROFILE_USER_ID); MANAGED_PROFILE_USER_ID); } } @Test public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); // Even if the caller is the managed profile, the current user is the user 0 when(getServices().iactivityManager.getCurrentUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Get mock reason string since we throw an IAE with empty string input. when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)) .thenReturn("Just a test string."); when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE)) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(getServices().userManager.getPrimaryUser()) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); // Set some device-wide policies: // Security logging when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true); // System update policy dpms.mOwners.setSystemUpdatePolicy(SystemUpdatePolicy.createAutomaticInstallPolicy()); // Make it look as if FRP agent is present. when(dpms.mMockInjector.getPersistentDataBlockManagerInternal().getAllowedUid()) .thenReturn(12345 /* some UID in user 0 */); // Make personal apps look suspended dpms.getUserData(UserHandle.USER_SYSTEM).mAppsSuspended = true; clearInvocations(getServices().iwindowManager); dpm.wipeData(0); verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(CALLER_USER_HANDLE); // Make sure COPE restrictions are lifted: verify(getServices().userManager).setUserRestriction( UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM); verify(getServices().userManager).setUserRestriction( UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM); // Some device-wide policies are getting cleaned-up after the user is removed. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; sendBroadcastWithUser(dpms, Intent.ACTION_USER_REMOVED, CALLER_USER_HANDLE); // Screenlock info should be removed verify(getServices().lockPatternUtils).setDeviceOwnerInfo(null); // Wifi config lockdown should be lifted verify(getServices().settings).settingsGlobalPutInt( Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); // System update policy should be removed assertThat(dpms.mOwners.getSystemUpdatePolicy()).isNull(); // FRP agent should be notified verify(mContext.spiedContext, times(0)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); // Refresh strong auth timeout and screen capture verify(getServices().lockSettingsInternal).refreshStrongAuthTimeout(UserHandle.USER_SYSTEM); verify(getServices().iwindowManager).refreshScreenCaptureDisabled(UserHandle.USER_SYSTEM); // Unsuspend personal apps verify(getServices().packageManagerInternal) .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM); } @Test @Test public void testWipeDataManagedProfileDisallowed() throws Exception { public void testWipeDataManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_USER_ID = 15; Loading