summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Pavel Grafov <pgrafov@google.com> 2019-11-27 12:41:26 +0000
committer Pavel Grafov <pgrafov@google.com> 2020-01-15 18:06:00 +0000
commit72451325a2150f4948db8d9b1b6a24fc06a06b7a (patch)
tree9383a392a166f8acdb2b82eab538ede3c8d4939d
parenteeb90fec267478176a07edfb7b2fc9a0f9ef4ce4 (diff)
Migrate COMP to PO on corp owned device on boot.
When the syste boots, check if the device is in COMP mode and if it is: * Mark PO as PO on corp owned device. * Migrate policies from from DO admin to PO parent instance: * password, timeout, keyguard related policies * camera, screenshot * accounts types with management disabled * support messages * applicable user restrictions * Clears DO and disables it as device admin. Two new unit tests verify that the decision whether to migrate or not is made correctly and that after the migrateion DO ceases to be device admin. Test: atest com.android.server.devicepolicy.DevicePolicyManagerServiceMigrationTest Bug: 143516163 Change-Id: I9131fb35da0f78066a662eed9c00207a5a923352
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java190
-rw-r--r--services/tests/servicestests/res/raw/comp_device_owner.xml8
-rw-r--r--services/tests/servicestests/res/raw/comp_policies_primary.xml7
-rw-r--r--services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml6
-rw-r--r--services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml6
-rw-r--r--services/tests/servicestests/res/raw/comp_profile_owner_another_package.xml7
-rw-r--r--services/tests/servicestests/res/raw/comp_profile_owner_same_package.xml7
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java116
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java8
11 files changed, 326 insertions, 41 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 24d3bb63fe7e..0def81445d07 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -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;
@@ -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();
@@ -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()) {
@@ -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.
@@ -12923,37 +13049,43 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Grant access under lock.
synchronized (getLockObject()) {
- // 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)) {
- throw new IllegalArgumentException(String.format(
- "Component %s is not a Profile Owner of user %d",
- who.flattenToString(), userId));
- }
+ markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId);
+ }
+ }
- Slog.i(LOG_TAG, String.format(
- "Marking %s as profile owner on organization-owned device for user %d",
+ @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)) {
+ throw new IllegalArgumentException(String.format(
+ "Component %s is not a Profile Owner of user %d",
who.flattenToString(), userId));
+ }
- // First, set restriction on removing the profile.
- mInjector.binderWithCleanCallingIdentity(() -> {
- // Clear restriction as user.
- 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"
+ Slog.i(LOG_TAG, String.format(
+ "Marking %s as profile owner on organization-owned device for user %d",
+ who.flattenToString(), userId));
+
+ // First, set restriction on removing the profile.
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ // Clear restriction as user.
+ 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"
+ " primary user can be granted access to device identifiers, not"
+ " on user %d", parentUser.getIdentifier()));
- }
+ }
- mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
- parentUser);
- });
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
+ parentUser);
+ });
- // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
- // data, no need to do it manually.
- mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
- }
+ // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
+ // data, no need to do it manually.
+ mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
}
private void pushMeteredDisabledPackagesLocked(int userId) {
@@ -14917,4 +15049,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);
+ }
+ }
}
diff --git a/services/tests/servicestests/res/raw/comp_device_owner.xml b/services/tests/servicestests/res/raw/comp_device_owner.xml
new file mode 100644
index 000000000000..0a10242ec59d
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_device_owner.xml
@@ -0,0 +1,8 @@
+<?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>
diff --git a/services/tests/servicestests/res/raw/comp_policies_primary.xml b/services/tests/servicestests/res/raw/comp_policies_primary.xml
new file mode 100644
index 000000000000..1e1a0eff874c
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_policies_primary.xml
@@ -0,0 +1,7 @@
+<?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>
diff --git a/services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml b/services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml
new file mode 100644
index 000000000000..141315e6c2d2
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_policies_profile_another_package.xml
@@ -0,0 +1,6 @@
+<?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>
diff --git a/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml b/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml
new file mode 100644
index 000000000000..c874dcca2c73
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml
@@ -0,0 +1,6 @@
+<?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>
diff --git a/services/tests/servicestests/res/raw/comp_profile_owner_another_package.xml b/services/tests/servicestests/res/raw/comp_profile_owner_another_package.xml
new file mode 100644
index 000000000000..d65ba7826fef
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_profile_owner_another_package.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<root>
+ <profile-owner package="com.another.package.name"
+ name="com.another.package.name"
+ component="com.another.package.name/whatever.random.class"
+ userRestrictionsMigrated="true"/>
+</root>
diff --git a/services/tests/servicestests/res/raw/comp_profile_owner_same_package.xml b/services/tests/servicestests/res/raw/comp_profile_owner_same_package.xml
new file mode 100644
index 000000000000..7f98c91c0a94
--- /dev/null
+++ b/services/tests/servicestests/res/raw/comp_profile_owner_same_package.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<root>
+ <profile-owner package="com.android.frameworks.servicestests"
+ name="com.android.frameworks.servicestests"
+ component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
+ userRestrictionsMigrated="true"/>
+</root>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 5f1f3083361b..46b83713c159 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -15,6 +15,10 @@
*/
package com.android.server.devicepolicy;
+import static android.os.UserHandle.USER_SYSTEM;
+
+import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
@@ -22,12 +26,14 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import com.android.frameworks.servicestests.R;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
@@ -37,9 +43,13 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+// TODO (b/143516163): Fix old test cases and put into presubmit.
public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
private static final String USER_TYPE_EMPTY = "";
+ private static final int COPE_ADMIN1_APP_ID = 123;
+ private static final int COPE_ANOTHER_ADMIN_APP_ID = 125;
+ private static final int COPE_PROFILE_USER_ID = 11;
private DpmMockContext mContext;
@@ -85,7 +95,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
// Set up UserManager
when(getServices().userManagerInternal.getBaseUserRestrictions(
- eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
+ eq(USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_RECORD_AUDIO));
@@ -137,7 +147,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
}
assertTrue(dpms.mOwners.hasDeviceOwner());
- assertFalse(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+ assertFalse(dpms.mOwners.hasProfileOwner(USER_SYSTEM));
assertTrue(dpms.mOwners.hasProfileOwner(10));
assertTrue(dpms.mOwners.hasProfileOwner(11));
assertFalse(dpms.mOwners.hasProfileOwner(12));
@@ -145,7 +155,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
// Now all information should be migrated.
assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
- UserHandle.USER_SYSTEM));
+ USER_SYSTEM));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12));
@@ -155,7 +165,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_RECORD_AUDIO
),
- newBaseRestrictions.get(UserHandle.USER_SYSTEM));
+ newBaseRestrictions.get(USER_SYSTEM));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
@@ -214,7 +224,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
// Set up UserManager
when(getServices().userManagerInternal.getBaseUserRestrictions(
- eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
+ eq(USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_RECORD_AUDIO,
UserManager.DISALLOW_SMS,
@@ -249,19 +259,19 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
mContext.binder.restoreCallingIdentity(ident);
}
assertFalse(dpms.mOwners.hasDeviceOwner());
- assertTrue(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+ assertTrue(dpms.mOwners.hasProfileOwner(USER_SYSTEM));
// Now all information should be migrated.
assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
- UserHandle.USER_SYSTEM));
+ USER_SYSTEM));
// Check the new base restrictions.
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_RECORD_AUDIO
),
- newBaseRestrictions.get(UserHandle.USER_SYSTEM));
+ newBaseRestrictions.get(USER_SYSTEM));
// Check the new owner restrictions.
DpmTestUtils.assertRestrictions(
@@ -270,7 +280,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS
),
- dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions());
+ dpms.getProfileOwnerAdminLocked(USER_SYSTEM).ensureUserRestrictions());
}
// Test setting default restrictions for managed profile.
@@ -332,4 +342,92 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
assertEquals(alreadySet.size(), 1);
assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING));
}
+
+ public void testCompMigrationUnAffiliated_skipped() throws Exception {
+ prepareAdmin1AsDo();
+ prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID);
+
+ final DevicePolicyManagerServiceTestable dpms;
+ dpms = bootDpmsUp();
+
+ // DO should still be DO since no migration should happen.
+ assertTrue(dpms.mOwners.hasDeviceOwner());
+ }
+
+ public void testCompMigrationAffiliated() throws Exception {
+ prepareAdmin1AsDo();
+ prepareAdmin1AsPo(COPE_PROFILE_USER_ID);
+
+ // Secure lock screen is needed for password policy APIs to work.
+ when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
+
+ final DevicePolicyManagerServiceTestable dpms;
+ dpms = bootDpmsUp();
+
+ // DO should cease to be DO.
+ assertFalse(dpms.mOwners.hasDeviceOwner());
+
+ final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
+ poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
+
+ runAsCaller(poContext, dpms, dpm -> {
+ // Check that DO policy is now set on parent instance.
+ assertEquals(33, dpm.getParentProfileInstance(admin1).getPasswordHistoryLength(admin1));
+ // And NOT set on profile instance.
+ assertEquals(0, dpm.getPasswordHistoryLength(admin1));
+
+ // TODO(b/143516163): verify more policies.
+ });
+ }
+
+ private DevicePolicyManagerServiceTestable bootDpmsUp() {
+ DevicePolicyManagerServiceTestable dpms;
+ final long ident = mContext.binder.clearCallingIdentity();
+ try {
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
+
+ dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
+ dpms.systemReady(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+ dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
+ } finally {
+ mContext.binder.restoreCallingIdentity(ident);
+ }
+ return dpms;
+ }
+
+ private void prepareAdmin1AsDo() throws Exception {
+ setUpPackageManagerForAdmin(admin1, UserHandle.getUid(USER_SYSTEM, COPE_ADMIN1_APP_ID));
+ final int xmlResource = R.raw.comp_policies_primary;
+ writeInputStreamToFile(getRawStream(xmlResource),
+ (new File(getServices().systemUserDataDir, "device_policies.xml"))
+ .getAbsoluteFile());
+ writeInputStreamToFile(getRawStream(R.raw.comp_device_owner),
+ (new File(getServices().dataDir, "device_owner_2.xml"))
+ .getAbsoluteFile());
+ }
+
+ private void prepareAdmin1AsPo(int profileUserId) throws Exception {
+ preparePo(profileUserId, admin1, R.raw.comp_profile_owner_same_package,
+ R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID);
+ }
+
+ private void prepareAdminAnotherPackageAsPo(int profileUserId) throws Exception {
+ preparePo(profileUserId, adminAnotherPackage, R.raw.comp_profile_owner_another_package,
+ R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID);
+ }
+
+ private void preparePo(int profileUserId, ComponentName admin, int profileOwnerXmlResId,
+ int policyXmlResId, int adminAppId) throws Exception {
+ final File profileDir = getServices().addUser(profileUserId, 0,
+ UserManager.USER_TYPE_PROFILE_MANAGED, USER_SYSTEM /* profile group */);
+ setUpPackageManagerForFakeAdmin(
+ admin, UserHandle.getUid(profileUserId, adminAppId), admin1);
+ writeInputStreamToFile(getRawStream(policyXmlResId),
+ (new File(profileDir, "device_policies.xml")).getAbsoluteFile());
+ writeInputStreamToFile(getRawStream(profileOwnerXmlResId),
+ (new File(profileDir, "profile_owner.xml")).getAbsoluteFile());
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 45729e5fd41f..c4d0f50fa308 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -58,7 +58,6 @@ import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.testng.Assert.assertThrows;
import android.Manifest.permission;
-import android.annotation.RawRes;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.Notification;
@@ -112,7 +111,6 @@ import org.mockito.internal.util.collections.Sets;
import org.mockito.stubbing.Answer;
import java.io.File;
-import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -5783,10 +5781,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
return new File(parentDir, "device_policies.xml");
}
- private InputStream getRawStream(@RawRes int id) {
- return mRealTestContext.getResources().openRawResource(id);
- }
-
private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
when(getServices().settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index a34c2ff8ce07..9a1a5fbfd186 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -24,6 +24,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
+import android.annotation.RawRes;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -36,6 +37,7 @@ import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.test.AndroidTestCase;
+import java.io.InputStream;
import java.util.List;
public abstract class DpmTestBase extends AndroidTestCase {
@@ -256,4 +258,8 @@ public abstract class DpmTestBase extends AndroidTestCase {
invocation -> invocation.getArguments()[1]
);
}
+
+ protected InputStream getRawStream(@RawRes int id) {
+ return mRealTestContext.getResources().openRawResource(id);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 6c2c1446a459..068daf5ee310 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -236,6 +237,13 @@ public class MockSystemServices {
return ui == null ? null : getUserInfo(ui.profileGroupId);
}
);
+ when(userManager.getProfileParent(any(UserHandle.class))).thenAnswer(
+ invocation -> {
+ final UserHandle userHandle = (UserHandle) invocation.getArguments()[0];
+ final UserInfo ui = getUserInfo(userHandle.getIdentifier());
+ return ui == null ? UserHandle.USER_NULL : UserHandle.of(ui.profileGroupId);
+ }
+ );
when(userManager.getProfiles(anyInt())).thenAnswer(
invocation -> {
final int userId12 = (int) invocation.getArguments()[0];