Loading cmds/dpm/src/com/android/commands/dpm/Dpm.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.commands.dpm; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; Loading Loading @@ -143,6 +144,10 @@ public final class Dpm extends BaseCommand { mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); throw e; throw e; } } mDevicePolicyManager.setUserProvisioningState( DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); System.out.println("Success: Device owner set to package " + mComponent); System.out.println("Success: Device owner set to package " + mComponent); System.out.println("Active admin set to component " + mComponent.toShortString()); System.out.println("Active admin set to component " + mComponent.toShortString()); } } Loading @@ -161,6 +166,10 @@ public final class Dpm extends BaseCommand { mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId); mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId); throw e; throw e; } } mDevicePolicyManager.setUserProvisioningState( DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); System.out.println("Success: Active admin and profile owner set to " System.out.println("Success: Active admin and profile owner set to " + mComponent.toShortString() + " for user " + mUserId); + mComponent.toShortString() + " for user " + mUserId); } } Loading core/java/android/app/admin/DevicePolicyManager.java +90 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.app.admin; package android.app.admin; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant; Loading Loading @@ -53,6 +54,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Proxy; import java.security.KeyFactory; import java.security.KeyFactory; Loading Loading @@ -279,6 +282,21 @@ public class DevicePolicyManager { public static final String ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE public static final String ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE = "android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE"; = "android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE"; /** * Activity action: Finalizes management provisioning, should be used after user-setup * has been completed and {@link #getUserProvisioningState()} returns one of: * <ul> * <li>{@link #STATE_USER_SETUP_INCOMPLETE}</li> * <li>{@link #STATE_USER_SETUP_COMPLETE}</li> * <li>{@link #STATE_USER_PROFILE_COMPLETE}</li> * </ul> * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION"; /** /** * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that * allows a mobile device management application or NFC programmer application which starts * allows a mobile device management application or NFC programmer application which starts Loading Loading @@ -860,6 +878,44 @@ public class DevicePolicyManager { */ */ public static final int PERMISSION_GRANT_STATE_DENIED = 2; public static final int PERMISSION_GRANT_STATE_DENIED = 2; /** * No management for current user in-effect. This is the default. * @hide */ public static final int STATE_USER_UNMANAGED = 0; /** * Management partially setup, user setup needs to be completed. * @hide */ public static final int STATE_USER_SETUP_INCOMPLETE = 1; /** * Management partially setup, user setup completed. * @hide */ public static final int STATE_USER_SETUP_COMPLETE = 2; /** * Management setup and active on current user. * @hide */ public static final int STATE_USER_SETUP_FINALIZED = 3; /** * Management partially setup on a managed profile. * @hide */ public static final int STATE_USER_PROFILE_COMPLETE = 4; /** * @hide */ @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE, STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE}) @Retention(RetentionPolicy.SOURCE) public @interface UserProvisioningState {} /** /** * Return true if the given administrator component is currently * Return true if the given administrator component is currently * active (enabled) in the system. * active (enabled) in the system. Loading Loading @@ -5246,6 +5302,40 @@ public class DevicePolicyManager { } } } } /** * @return the {@link UserProvisioningState} for the current user - for unmanaged users will * return {@link #STATE_USER_UNMANAGED} * @hide */ @UserProvisioningState public int getUserProvisioningState() { if (mService != null) { try { return mService.getUserProvisioningState(); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } } return STATE_USER_UNMANAGED; } /** * Set the {@link UserProvisioningState} for the supplied user, if they are managed. * * @param state to store * @param userHandle for user * @hide */ public void setUserProvisioningState(@UserProvisioningState int state, int userHandle) { if (mService != null) { try { mService.setUserProvisioningState(state, userHandle); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } } } /** /** * @hide * @hide * Indicates the entity that controls the device or profile owner. A user/profile is considered * Indicates the entity that controls the device or profile owner. A user/profile is considered Loading core/java/android/app/admin/IDevicePolicyManager.aidl +3 −0 Original line number Original line Diff line number Diff line Loading @@ -269,6 +269,9 @@ interface IDevicePolicyManager { int getOrganizationColor(in ComponentName admin); int getOrganizationColor(in ComponentName admin); int getOrganizationColorForUser(int userHandle); int getOrganizationColorForUser(int userHandle); int getUserProvisioningState(); void setUserProvisioningState(int state, int userHandle); void setAffiliationIds(in ComponentName admin, in List<String> ids); void setAffiliationIds(in ComponentName admin, in List<String> ids); boolean isAffiliatedUser(); boolean isAffiliatedUser(); } } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +105 −1 Original line number Original line Diff line number Diff line Loading @@ -202,6 +202,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; Loading Loading @@ -364,6 +365,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int mPasswordOwner = -1; int mPasswordOwner = -1; long mLastMaximumTimeToLock = -1; long mLastMaximumTimeToLock = -1; boolean mUserSetupComplete = false; boolean mUserSetupComplete = false; int mUserProvisioningState; int mPermissionPolicy; int mPermissionPolicy; final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); Loading Loading @@ -2017,6 +2019,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_SETUP_COMPLETE, out.attribute(null, ATTR_SETUP_COMPLETE, Boolean.toString(true)); Boolean.toString(true)); } } if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { out.attribute(null, ATTR_PROVISIONING_STATE, Integer.toString(policy.mUserProvisioningState)); } if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { out.attribute(null, ATTR_PERMISSION_POLICY, out.attribute(null, ATTR_PERMISSION_POLICY, Integer.toString(policy.mPermissionPolicy)); Integer.toString(policy.mPermissionPolicy)); Loading Loading @@ -2167,6 +2173,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { policy.mUserSetupComplete = true; policy.mUserSetupComplete = true; } } String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); if (!TextUtils.isEmpty(provisioningState)) { policy.mUserProvisioningState = Integer.parseInt(provisioningState); } String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); if (!TextUtils.isEmpty(permissionPolicy)) { if (!TextUtils.isEmpty(permissionPolicy)) { policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); Loading Loading @@ -5379,6 +5389,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mDelegatedCertInstallerPackage = null; policy.mDelegatedCertInstallerPackage = null; policy.mApplicationRestrictionsManagingPackage = null; policy.mApplicationRestrictionsManagingPackage = null; policy.mStatusBarDisabled = false; policy.mStatusBarDisabled = false; policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED; saveSettingsLocked(userId); saveSettingsLocked(userId); final long ident = mInjector.binderClearCallingIdentity(); final long ident = mInjector.binderClearCallingIdentity(); Loading @@ -5405,6 +5416,98 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return getUserData(userHandle).mUserSetupComplete; return getUserData(userHandle).mUserSetupComplete; } } @Override public int getUserProvisioningState() { if (!mHasFeature) { return DevicePolicyManager.STATE_USER_UNMANAGED; } int userHandle = mInjector.userHandleGetCallingUserId(); return getUserProvisioningState(userHandle); } private int getUserProvisioningState(int userHandle) { return getUserData(userHandle).mUserProvisioningState; } @Override public void setUserProvisioningState(int newState, int userHandle) { if (!mHasFeature) { return; } if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle) && getManagedUserId(userHandle) == -1) { // No managed device, user or profile, so setting provisioning state makes no sense. throw new IllegalStateException("Not allowed to change provisioning state unless a " + "device or profile owner is set."); } synchronized (this) { boolean transitionCheckNeeded = true; // Calling identity/permission checks. final int callingUid = mInjector.binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { // ADB shell can only move directly from un-managed to finalized as part of directly // setting profile-owner or device-owner. if (getUserProvisioningState(userHandle) != DevicePolicyManager.STATE_USER_UNMANAGED || newState != DevicePolicyManager.STATE_USER_SETUP_FINALIZED) { throw new IllegalStateException("Not allowed to change provisioning state " + "unless current provisioning state is unmanaged, and new state is " + "finalized."); } transitionCheckNeeded = false; } else { // For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS. mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); } final DevicePolicyData policyData = getUserData(userHandle); if (transitionCheckNeeded) { // Optional state transition check for non-ADB case. checkUserProvisioningStateTransition(policyData.mUserProvisioningState, newState); } policyData.mUserProvisioningState = newState; saveSettingsLocked(userHandle); } } private void checkUserProvisioningStateTransition(int currentState, int newState) { // Valid transitions for normal use-cases. switch (currentState) { case DevicePolicyManager.STATE_USER_UNMANAGED: // Can move to any state from unmanaged (except itself as an edge case).. if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) { return; } break; case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE: case DevicePolicyManager.STATE_USER_SETUP_COMPLETE: // Can only move to finalized from these states. if (newState == DevicePolicyManager.STATE_USER_SETUP_FINALIZED) { return; } break; case DevicePolicyManager.STATE_USER_PROFILE_COMPLETE: // Current user has a managed-profile, but current user is not managed, so // rather than moving to finalized state, go back to unmanaged once // profile provisioning is complete. if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) { return; } break; case DevicePolicyManager.STATE_USER_SETUP_FINALIZED: // Cannot transition out of finalized. break; } // Didn't meet any of the accepted state transition checks above, throw appropriate error. throw new IllegalStateException("Cannot move to user provisioning state [" + newState + "] " + "from state [" + currentState + "]"); } @Override @Override public void setProfileEnabled(ComponentName who) { public void setProfileEnabled(ComponentName who) { if (!mHasFeature) { if (!mHasFeature) { Loading Loading @@ -5724,7 +5827,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (int u = 0; u < userCount; u++) { for (int u = 0; u < userCount; u++) { DevicePolicyData policy = getUserData(mUserData.keyAt(u)); DevicePolicyData policy = getUserData(mUserData.keyAt(u)); pw.println(); pw.println(); pw.println(" Enabled Device Admins (User " + policy.mUserHandle + "):"); pw.println(" Enabled Device Admins (User " + policy.mUserHandle + ", provisioningState: " + policy.mUserProvisioningState + "):"); final int N = policy.mAdminList.size(); final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { for (int i=0; i<N; i++) { ActiveAdmin ap = policy.mAdminList.get(i); ActiveAdmin ap = policy.mAdminList.get(i); Loading services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +162 −5 Original line number Original line Diff line number Diff line Loading @@ -15,9 +15,6 @@ */ */ package com.android.server.devicepolicy; package com.android.server.devicepolicy; import com.android.server.LocalServices; import com.android.server.SystemService; import android.Manifest.permission; import android.Manifest.permission; import android.app.Activity; import android.app.Activity; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DeviceAdminReceiver; Loading @@ -27,7 +24,6 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Bundle; import android.os.Process; import android.os.Process; Loading @@ -38,11 +34,16 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import android.util.ArraySet; import android.util.Pair; import android.util.Pair; import com.android.server.LocalServices; import com.android.server.SystemService; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; Loading @@ -65,7 +66,7 @@ import static org.mockito.Mockito.when; * * m FrameworksServicesTests && m FrameworksServicesTests && adb install \ adb install \ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Loading @@ -73,6 +74,10 @@ import static org.mockito.Mockito.when; */ */ @SmallTest @SmallTest public class DevicePolicyManagerTest extends DpmTestBase { public class DevicePolicyManagerTest extends DpmTestBase { private static final List<String> 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; private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; public DevicePolicyManagerServiceTestable dpms; Loading Loading @@ -1545,4 +1550,156 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; assertTrue(dpm.isAffiliatedUser()); assertTrue(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); } } } Loading
cmds/dpm/src/com/android/commands/dpm/Dpm.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.commands.dpm; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; Loading Loading @@ -143,6 +144,10 @@ public final class Dpm extends BaseCommand { mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); throw e; throw e; } } mDevicePolicyManager.setUserProvisioningState( DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); System.out.println("Success: Device owner set to package " + mComponent); System.out.println("Success: Device owner set to package " + mComponent); System.out.println("Active admin set to component " + mComponent.toShortString()); System.out.println("Active admin set to component " + mComponent.toShortString()); } } Loading @@ -161,6 +166,10 @@ public final class Dpm extends BaseCommand { mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId); mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId); throw e; throw e; } } mDevicePolicyManager.setUserProvisioningState( DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); System.out.println("Success: Active admin and profile owner set to " System.out.println("Success: Active admin and profile owner set to " + mComponent.toShortString() + " for user " + mUserId); + mComponent.toShortString() + " for user " + mUserId); } } Loading
core/java/android/app/admin/DevicePolicyManager.java +90 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.app.admin; package android.app.admin; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant; Loading Loading @@ -53,6 +54,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Proxy; import java.security.KeyFactory; import java.security.KeyFactory; Loading Loading @@ -279,6 +282,21 @@ public class DevicePolicyManager { public static final String ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE public static final String ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE = "android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE"; = "android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE"; /** * Activity action: Finalizes management provisioning, should be used after user-setup * has been completed and {@link #getUserProvisioningState()} returns one of: * <ul> * <li>{@link #STATE_USER_SETUP_INCOMPLETE}</li> * <li>{@link #STATE_USER_SETUP_COMPLETE}</li> * <li>{@link #STATE_USER_PROFILE_COMPLETE}</li> * </ul> * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION"; /** /** * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that * allows a mobile device management application or NFC programmer application which starts * allows a mobile device management application or NFC programmer application which starts Loading Loading @@ -860,6 +878,44 @@ public class DevicePolicyManager { */ */ public static final int PERMISSION_GRANT_STATE_DENIED = 2; public static final int PERMISSION_GRANT_STATE_DENIED = 2; /** * No management for current user in-effect. This is the default. * @hide */ public static final int STATE_USER_UNMANAGED = 0; /** * Management partially setup, user setup needs to be completed. * @hide */ public static final int STATE_USER_SETUP_INCOMPLETE = 1; /** * Management partially setup, user setup completed. * @hide */ public static final int STATE_USER_SETUP_COMPLETE = 2; /** * Management setup and active on current user. * @hide */ public static final int STATE_USER_SETUP_FINALIZED = 3; /** * Management partially setup on a managed profile. * @hide */ public static final int STATE_USER_PROFILE_COMPLETE = 4; /** * @hide */ @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE, STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE}) @Retention(RetentionPolicy.SOURCE) public @interface UserProvisioningState {} /** /** * Return true if the given administrator component is currently * Return true if the given administrator component is currently * active (enabled) in the system. * active (enabled) in the system. Loading Loading @@ -5246,6 +5302,40 @@ public class DevicePolicyManager { } } } } /** * @return the {@link UserProvisioningState} for the current user - for unmanaged users will * return {@link #STATE_USER_UNMANAGED} * @hide */ @UserProvisioningState public int getUserProvisioningState() { if (mService != null) { try { return mService.getUserProvisioningState(); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } } return STATE_USER_UNMANAGED; } /** * Set the {@link UserProvisioningState} for the supplied user, if they are managed. * * @param state to store * @param userHandle for user * @hide */ public void setUserProvisioningState(@UserProvisioningState int state, int userHandle) { if (mService != null) { try { mService.setUserProvisioningState(state, userHandle); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } } } /** /** * @hide * @hide * Indicates the entity that controls the device or profile owner. A user/profile is considered * Indicates the entity that controls the device or profile owner. A user/profile is considered Loading
core/java/android/app/admin/IDevicePolicyManager.aidl +3 −0 Original line number Original line Diff line number Diff line Loading @@ -269,6 +269,9 @@ interface IDevicePolicyManager { int getOrganizationColor(in ComponentName admin); int getOrganizationColor(in ComponentName admin); int getOrganizationColorForUser(int userHandle); int getOrganizationColorForUser(int userHandle); int getUserProvisioningState(); void setUserProvisioningState(int state, int userHandle); void setAffiliationIds(in ComponentName admin, in List<String> ids); void setAffiliationIds(in ComponentName admin, in List<String> ids); boolean isAffiliatedUser(); boolean isAffiliatedUser(); } }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +105 −1 Original line number Original line Diff line number Diff line Loading @@ -202,6 +202,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; Loading Loading @@ -364,6 +365,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int mPasswordOwner = -1; int mPasswordOwner = -1; long mLastMaximumTimeToLock = -1; long mLastMaximumTimeToLock = -1; boolean mUserSetupComplete = false; boolean mUserSetupComplete = false; int mUserProvisioningState; int mPermissionPolicy; int mPermissionPolicy; final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); Loading Loading @@ -2017,6 +2019,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_SETUP_COMPLETE, out.attribute(null, ATTR_SETUP_COMPLETE, Boolean.toString(true)); Boolean.toString(true)); } } if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { out.attribute(null, ATTR_PROVISIONING_STATE, Integer.toString(policy.mUserProvisioningState)); } if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { out.attribute(null, ATTR_PERMISSION_POLICY, out.attribute(null, ATTR_PERMISSION_POLICY, Integer.toString(policy.mPermissionPolicy)); Integer.toString(policy.mPermissionPolicy)); Loading Loading @@ -2167,6 +2173,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { policy.mUserSetupComplete = true; policy.mUserSetupComplete = true; } } String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); if (!TextUtils.isEmpty(provisioningState)) { policy.mUserProvisioningState = Integer.parseInt(provisioningState); } String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); if (!TextUtils.isEmpty(permissionPolicy)) { if (!TextUtils.isEmpty(permissionPolicy)) { policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); Loading Loading @@ -5379,6 +5389,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mDelegatedCertInstallerPackage = null; policy.mDelegatedCertInstallerPackage = null; policy.mApplicationRestrictionsManagingPackage = null; policy.mApplicationRestrictionsManagingPackage = null; policy.mStatusBarDisabled = false; policy.mStatusBarDisabled = false; policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED; saveSettingsLocked(userId); saveSettingsLocked(userId); final long ident = mInjector.binderClearCallingIdentity(); final long ident = mInjector.binderClearCallingIdentity(); Loading @@ -5405,6 +5416,98 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return getUserData(userHandle).mUserSetupComplete; return getUserData(userHandle).mUserSetupComplete; } } @Override public int getUserProvisioningState() { if (!mHasFeature) { return DevicePolicyManager.STATE_USER_UNMANAGED; } int userHandle = mInjector.userHandleGetCallingUserId(); return getUserProvisioningState(userHandle); } private int getUserProvisioningState(int userHandle) { return getUserData(userHandle).mUserProvisioningState; } @Override public void setUserProvisioningState(int newState, int userHandle) { if (!mHasFeature) { return; } if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle) && getManagedUserId(userHandle) == -1) { // No managed device, user or profile, so setting provisioning state makes no sense. throw new IllegalStateException("Not allowed to change provisioning state unless a " + "device or profile owner is set."); } synchronized (this) { boolean transitionCheckNeeded = true; // Calling identity/permission checks. final int callingUid = mInjector.binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { // ADB shell can only move directly from un-managed to finalized as part of directly // setting profile-owner or device-owner. if (getUserProvisioningState(userHandle) != DevicePolicyManager.STATE_USER_UNMANAGED || newState != DevicePolicyManager.STATE_USER_SETUP_FINALIZED) { throw new IllegalStateException("Not allowed to change provisioning state " + "unless current provisioning state is unmanaged, and new state is " + "finalized."); } transitionCheckNeeded = false; } else { // For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS. mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); } final DevicePolicyData policyData = getUserData(userHandle); if (transitionCheckNeeded) { // Optional state transition check for non-ADB case. checkUserProvisioningStateTransition(policyData.mUserProvisioningState, newState); } policyData.mUserProvisioningState = newState; saveSettingsLocked(userHandle); } } private void checkUserProvisioningStateTransition(int currentState, int newState) { // Valid transitions for normal use-cases. switch (currentState) { case DevicePolicyManager.STATE_USER_UNMANAGED: // Can move to any state from unmanaged (except itself as an edge case).. if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) { return; } break; case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE: case DevicePolicyManager.STATE_USER_SETUP_COMPLETE: // Can only move to finalized from these states. if (newState == DevicePolicyManager.STATE_USER_SETUP_FINALIZED) { return; } break; case DevicePolicyManager.STATE_USER_PROFILE_COMPLETE: // Current user has a managed-profile, but current user is not managed, so // rather than moving to finalized state, go back to unmanaged once // profile provisioning is complete. if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) { return; } break; case DevicePolicyManager.STATE_USER_SETUP_FINALIZED: // Cannot transition out of finalized. break; } // Didn't meet any of the accepted state transition checks above, throw appropriate error. throw new IllegalStateException("Cannot move to user provisioning state [" + newState + "] " + "from state [" + currentState + "]"); } @Override @Override public void setProfileEnabled(ComponentName who) { public void setProfileEnabled(ComponentName who) { if (!mHasFeature) { if (!mHasFeature) { Loading Loading @@ -5724,7 +5827,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (int u = 0; u < userCount; u++) { for (int u = 0; u < userCount; u++) { DevicePolicyData policy = getUserData(mUserData.keyAt(u)); DevicePolicyData policy = getUserData(mUserData.keyAt(u)); pw.println(); pw.println(); pw.println(" Enabled Device Admins (User " + policy.mUserHandle + "):"); pw.println(" Enabled Device Admins (User " + policy.mUserHandle + ", provisioningState: " + policy.mUserProvisioningState + "):"); final int N = policy.mAdminList.size(); final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { for (int i=0; i<N; i++) { ActiveAdmin ap = policy.mAdminList.get(i); ActiveAdmin ap = policy.mAdminList.get(i); Loading
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +162 −5 Original line number Original line Diff line number Diff line Loading @@ -15,9 +15,6 @@ */ */ package com.android.server.devicepolicy; package com.android.server.devicepolicy; import com.android.server.LocalServices; import com.android.server.SystemService; import android.Manifest.permission; import android.Manifest.permission; import android.app.Activity; import android.app.Activity; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DeviceAdminReceiver; Loading @@ -27,7 +24,6 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Bundle; import android.os.Process; import android.os.Process; Loading @@ -38,11 +34,16 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import android.util.ArraySet; import android.util.Pair; import android.util.Pair; import com.android.server.LocalServices; import com.android.server.SystemService; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; Loading @@ -65,7 +66,7 @@ import static org.mockito.Mockito.when; * * m FrameworksServicesTests && m FrameworksServicesTests && adb install \ adb install \ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Loading @@ -73,6 +74,10 @@ import static org.mockito.Mockito.when; */ */ @SmallTest @SmallTest public class DevicePolicyManagerTest extends DpmTestBase { public class DevicePolicyManagerTest extends DpmTestBase { private static final List<String> 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; private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; public DevicePolicyManagerServiceTestable dpms; Loading Loading @@ -1545,4 +1550,156 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; assertTrue(dpm.isAffiliatedUser()); assertTrue(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); } } }