Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +164 −26 Original line number Diff line number Diff line Loading @@ -1095,7 +1095,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { String globalProxySpec = null; String globalProxyExclusionList = null; ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); @NonNull ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); List<String> crossProfileWidgetProviders; Loading Loading @@ -1650,6 +1650,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } @NonNull private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( XmlPullParser parser, String tag) throws XmlPullParserException, IOException { int outerDepthDAM = parser.getDepth(); Loading Loading @@ -2434,11 +2435,133 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { migrateUserRestrictionsIfNecessaryLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. updateDeviceOwnerLocked(); } } /** * Checks if the device is in COMP mode, and if so migrates it to managed profile on a * corporate owned device. */ @GuardedBy("getLockObject()") private void maybeMigrateToProfileOnOrganizationOwnedDeviceLocked() { logIfVerbose("Checking whether we need to migrate COMP "); final int doUserId = mOwners.getDeviceOwnerUserId(); if (doUserId == UserHandle.USER_NULL) { logIfVerbose("No DO found, skipping migration."); return; } final List<UserInfo> profiles = mUserManager.getProfiles(doUserId); if (profiles.size() != 2) { if (profiles.size() == 1) { logIfVerbose("Profile not found, skipping migration."); } else { Slog.wtf(LOG_TAG, "Found " + profiles.size() + " profiles, skipping migration"); } return; } final int poUserId = getManagedUserId(doUserId); if (poUserId < 0) { Slog.wtf(LOG_TAG, "Found DO and a profile, but it is not managed, skipping migration"); return; } final ActiveAdmin doAdmin = getDeviceOwnerAdminLocked(); final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(poUserId); if (doAdmin == null || poAdmin == null) { Slog.wtf(LOG_TAG, "Failed to get either PO or DO admin, aborting migration."); return; } final ComponentName doAdminComponent = mOwners.getDeviceOwnerComponent(); final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(poUserId); if (doAdminComponent == null || poAdminComponent == null) { Slog.wtf(LOG_TAG, "Cannot find PO or DO component name, aborting migration."); return; } if (!doAdminComponent.getPackageName().equals(poAdminComponent.getPackageName())) { Slog.e(LOG_TAG, "DO and PO are different packages, aborting migration."); return; } Slog.i(LOG_TAG, String.format( "Migrating COMP to PO on a corp owned device; primary user: %d; profile: %d", doUserId, poUserId)); Slog.i(LOG_TAG, "Giving the PO additional power..."); markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId); Slog.i(LOG_TAG, "Migrating DO policies to PO..."); moveDoPoliciesToProfileParentAdmin(doAdmin, poAdmin.getParentActiveAdmin()); saveSettingsLocked(poUserId); Slog.i(LOG_TAG, "Clearing the DO..."); final ComponentName doAdminReceiver = doAdmin.info.getComponent(); clearDeviceOwnerLocked(doAdmin, doUserId); // TODO(b/143516163): If we have a power cut here, we might leave active admin. Consider if // it is worth the complexity to make it more robust. Slog.i(LOG_TAG, "Removing admin artifacts..."); // TODO(b/143516163): Clean up application restrictions in UserManager. removeAdminArtifacts(doAdminReceiver, doUserId); Slog.i(LOG_TAG, "Migration complete."); // Note: KeyChain keys are not removed and will remain accessible for the apps that have // been given grants to use them. } private void moveDoPoliciesToProfileParentAdmin(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) { // The following policies can be already controlled via parent instance, skip if so. if (parentAdmin.mPasswordPolicy.quality == PASSWORD_QUALITY_UNSPECIFIED) { parentAdmin.mPasswordPolicy = doAdmin.mPasswordPolicy; } if (parentAdmin.passwordHistoryLength == ActiveAdmin.DEF_PASSWORD_HISTORY_LENGTH) { parentAdmin.passwordHistoryLength = doAdmin.passwordHistoryLength; } if (parentAdmin.passwordExpirationTimeout == ActiveAdmin.DEF_PASSWORD_HISTORY_LENGTH) { parentAdmin.passwordExpirationTimeout = doAdmin.passwordExpirationTimeout; } if (parentAdmin.maximumFailedPasswordsForWipe == ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { parentAdmin.maximumFailedPasswordsForWipe = doAdmin.maximumFailedPasswordsForWipe; } if (parentAdmin.maximumTimeToUnlock == ActiveAdmin.DEF_MAXIMUM_TIME_TO_UNLOCK) { parentAdmin.maximumTimeToUnlock = doAdmin.maximumTimeToUnlock; } if (parentAdmin.strongAuthUnlockTimeout == DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { parentAdmin.strongAuthUnlockTimeout = doAdmin.strongAuthUnlockTimeout; } parentAdmin.disabledKeyguardFeatures |= doAdmin.disabledKeyguardFeatures & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; parentAdmin.trustAgentInfos.putAll(doAdmin.trustAgentInfos); // The following policies weren't available to PO, but will be available after migration. parentAdmin.disableCamera = doAdmin.disableCamera; // TODO(b/143516163): Uncomment once corresponding APIs are available via parent instance. // parentAdmin.disableScreenCapture = doAdmin.disableScreenCapture; // parentAdmin.accountTypesWithManagementDisabled.addAll( // doAdmin.accountTypesWithManagementDisabled); moveDoUserRestrictionsToCopeParent(doAdmin, parentAdmin); // TODO(b/143516163): migrate network and security logging state, currently they are // turned off when DO is removed. } private void moveDoUserRestrictionsToCopeParent(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) { if (doAdmin.userRestrictions == null) { return; } for (final String restriction : doAdmin.userRestrictions.keySet()) { if (UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(restriction)) { parentAdmin.userRestrictions.putBoolean( restriction, doAdmin.userRestrictions.getBoolean(restriction)); } } } /** Apply default restrictions that haven't been applied to profile owners yet. */ private void maybeSetDefaultProfileOwnerUserRestrictions() { synchronized (getLockObject()) { Loading Loading @@ -3625,6 +3748,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { break; case SystemService.PHASE_ACTIVITY_MANAGER_READY: maybeStartSecurityLogMonitorOnActivityManagerReady(); synchronized (getLockObject()) { maybeMigrateToProfileOnOrganizationOwnedDeviceLocked(); } break; case SystemService.PHASE_BOOT_COMPLETED: ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this. Loading Loading @@ -12919,6 +13045,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Grant access under lock. synchronized (getLockObject()) { markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId); } } @GuardedBy("getLockObject()") private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked( ComponentName who, int userId) { // Sanity check: Make sure that the user has a profile owner and that the specified // component is the profile owner of that user. if (!isProfileOwner(who, userId)) { Loading @@ -12934,7 +13067,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // First, set restriction on removing the profile. mInjector.binderWithCleanCallingIdentity(() -> { // Clear restriction as user. UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId)); final UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId)); if (!parentUser.isSystem()) { throw new IllegalStateException( String.format("Only the profile owner of a managed profile on the" Loading @@ -12950,7 +13083,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // data, no need to do it manually. mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId); } } private void pushMeteredDisabledPackagesLocked(int userId) { mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages( Loading Loading @@ -14913,4 +15045,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return packages == null ? Collections.EMPTY_LIST : packages; } } private void logIfVerbose(String message) { if (VERBOSE_LOG) { Slog.d(LOG_TAG, message); } } } services/tests/servicestests/res/raw/comp_device_owner.xml 0 → 100644 +8 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <root> <device-owner package="com.android.frameworks.servicestests" name="" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1" userRestrictionsMigrated="true" /> <device-owner-context userId="0" /> </root> services/tests/servicestests/res/raw/comp_policies_primary.xml 0 → 100644 +7 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> <password-history-length value="33" /> </admin> </policies> services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml 0 → 100644 +6 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.another.package.name/whatever.random.class"> <policies flags="991"/> </admin> </policies> services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml 0 → 100644 +6 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> </admin> </policies> Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +164 −26 Original line number Diff line number Diff line Loading @@ -1095,7 +1095,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { String globalProxySpec = null; String globalProxyExclusionList = null; ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); @NonNull ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); List<String> crossProfileWidgetProviders; Loading Loading @@ -1650,6 +1650,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } @NonNull private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( XmlPullParser parser, String tag) throws XmlPullParserException, IOException { int outerDepthDAM = parser.getDepth(); Loading Loading @@ -2434,11 +2435,133 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { migrateUserRestrictionsIfNecessaryLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. updateDeviceOwnerLocked(); } } /** * Checks if the device is in COMP mode, and if so migrates it to managed profile on a * corporate owned device. */ @GuardedBy("getLockObject()") private void maybeMigrateToProfileOnOrganizationOwnedDeviceLocked() { logIfVerbose("Checking whether we need to migrate COMP "); final int doUserId = mOwners.getDeviceOwnerUserId(); if (doUserId == UserHandle.USER_NULL) { logIfVerbose("No DO found, skipping migration."); return; } final List<UserInfo> profiles = mUserManager.getProfiles(doUserId); if (profiles.size() != 2) { if (profiles.size() == 1) { logIfVerbose("Profile not found, skipping migration."); } else { Slog.wtf(LOG_TAG, "Found " + profiles.size() + " profiles, skipping migration"); } return; } final int poUserId = getManagedUserId(doUserId); if (poUserId < 0) { Slog.wtf(LOG_TAG, "Found DO and a profile, but it is not managed, skipping migration"); return; } final ActiveAdmin doAdmin = getDeviceOwnerAdminLocked(); final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(poUserId); if (doAdmin == null || poAdmin == null) { Slog.wtf(LOG_TAG, "Failed to get either PO or DO admin, aborting migration."); return; } final ComponentName doAdminComponent = mOwners.getDeviceOwnerComponent(); final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(poUserId); if (doAdminComponent == null || poAdminComponent == null) { Slog.wtf(LOG_TAG, "Cannot find PO or DO component name, aborting migration."); return; } if (!doAdminComponent.getPackageName().equals(poAdminComponent.getPackageName())) { Slog.e(LOG_TAG, "DO and PO are different packages, aborting migration."); return; } Slog.i(LOG_TAG, String.format( "Migrating COMP to PO on a corp owned device; primary user: %d; profile: %d", doUserId, poUserId)); Slog.i(LOG_TAG, "Giving the PO additional power..."); markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId); Slog.i(LOG_TAG, "Migrating DO policies to PO..."); moveDoPoliciesToProfileParentAdmin(doAdmin, poAdmin.getParentActiveAdmin()); saveSettingsLocked(poUserId); Slog.i(LOG_TAG, "Clearing the DO..."); final ComponentName doAdminReceiver = doAdmin.info.getComponent(); clearDeviceOwnerLocked(doAdmin, doUserId); // TODO(b/143516163): If we have a power cut here, we might leave active admin. Consider if // it is worth the complexity to make it more robust. Slog.i(LOG_TAG, "Removing admin artifacts..."); // TODO(b/143516163): Clean up application restrictions in UserManager. removeAdminArtifacts(doAdminReceiver, doUserId); Slog.i(LOG_TAG, "Migration complete."); // Note: KeyChain keys are not removed and will remain accessible for the apps that have // been given grants to use them. } private void moveDoPoliciesToProfileParentAdmin(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) { // The following policies can be already controlled via parent instance, skip if so. if (parentAdmin.mPasswordPolicy.quality == PASSWORD_QUALITY_UNSPECIFIED) { parentAdmin.mPasswordPolicy = doAdmin.mPasswordPolicy; } if (parentAdmin.passwordHistoryLength == ActiveAdmin.DEF_PASSWORD_HISTORY_LENGTH) { parentAdmin.passwordHistoryLength = doAdmin.passwordHistoryLength; } if (parentAdmin.passwordExpirationTimeout == ActiveAdmin.DEF_PASSWORD_HISTORY_LENGTH) { parentAdmin.passwordExpirationTimeout = doAdmin.passwordExpirationTimeout; } if (parentAdmin.maximumFailedPasswordsForWipe == ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { parentAdmin.maximumFailedPasswordsForWipe = doAdmin.maximumFailedPasswordsForWipe; } if (parentAdmin.maximumTimeToUnlock == ActiveAdmin.DEF_MAXIMUM_TIME_TO_UNLOCK) { parentAdmin.maximumTimeToUnlock = doAdmin.maximumTimeToUnlock; } if (parentAdmin.strongAuthUnlockTimeout == DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { parentAdmin.strongAuthUnlockTimeout = doAdmin.strongAuthUnlockTimeout; } parentAdmin.disabledKeyguardFeatures |= doAdmin.disabledKeyguardFeatures & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; parentAdmin.trustAgentInfos.putAll(doAdmin.trustAgentInfos); // The following policies weren't available to PO, but will be available after migration. parentAdmin.disableCamera = doAdmin.disableCamera; // TODO(b/143516163): Uncomment once corresponding APIs are available via parent instance. // parentAdmin.disableScreenCapture = doAdmin.disableScreenCapture; // parentAdmin.accountTypesWithManagementDisabled.addAll( // doAdmin.accountTypesWithManagementDisabled); moveDoUserRestrictionsToCopeParent(doAdmin, parentAdmin); // TODO(b/143516163): migrate network and security logging state, currently they are // turned off when DO is removed. } private void moveDoUserRestrictionsToCopeParent(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) { if (doAdmin.userRestrictions == null) { return; } for (final String restriction : doAdmin.userRestrictions.keySet()) { if (UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(restriction)) { parentAdmin.userRestrictions.putBoolean( restriction, doAdmin.userRestrictions.getBoolean(restriction)); } } } /** Apply default restrictions that haven't been applied to profile owners yet. */ private void maybeSetDefaultProfileOwnerUserRestrictions() { synchronized (getLockObject()) { Loading Loading @@ -3625,6 +3748,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { break; case SystemService.PHASE_ACTIVITY_MANAGER_READY: maybeStartSecurityLogMonitorOnActivityManagerReady(); synchronized (getLockObject()) { maybeMigrateToProfileOnOrganizationOwnedDeviceLocked(); } break; case SystemService.PHASE_BOOT_COMPLETED: ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this. Loading Loading @@ -12919,6 +13045,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Grant access under lock. synchronized (getLockObject()) { markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId); } } @GuardedBy("getLockObject()") private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked( ComponentName who, int userId) { // Sanity check: Make sure that the user has a profile owner and that the specified // component is the profile owner of that user. if (!isProfileOwner(who, userId)) { Loading @@ -12934,7 +13067,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // First, set restriction on removing the profile. mInjector.binderWithCleanCallingIdentity(() -> { // Clear restriction as user. UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId)); final UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId)); if (!parentUser.isSystem()) { throw new IllegalStateException( String.format("Only the profile owner of a managed profile on the" Loading @@ -12950,7 +13083,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // data, no need to do it manually. mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId); } } private void pushMeteredDisabledPackagesLocked(int userId) { mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages( Loading Loading @@ -14913,4 +15045,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return packages == null ? Collections.EMPTY_LIST : packages; } } private void logIfVerbose(String message) { if (VERBOSE_LOG) { Slog.d(LOG_TAG, message); } } }
services/tests/servicestests/res/raw/comp_device_owner.xml 0 → 100644 +8 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <root> <device-owner package="com.android.frameworks.servicestests" name="" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1" userRestrictionsMigrated="true" /> <device-owner-context userId="0" /> </root>
services/tests/servicestests/res/raw/comp_policies_primary.xml 0 → 100644 +7 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> <password-history-length value="33" /> </admin> </policies>
services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml 0 → 100644 +6 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.another.package.name/whatever.random.class"> <policies flags="991"/> </admin> </policies>
services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml 0 → 100644 +6 −0 Original line number Diff line number Diff line <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true" provisioning-state="3"> <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> </admin> </policies>