Return error code from isProvisioningAllowed

Added hidden pre condition codes for PO and DO provsioning.
Added hidden api checkProvisioningPreCondition, which returns codes
instead of boolean. Managed provisioning can use this to show
useful debug information and user facing error dialogs.

Test: All DevicePolicyManagerTest pass

Bug: 27467633
Change-Id: I7d2a79921bc3ac2e12d506629a35563fc7ff62bf
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e6b1fac..1f39faa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,6 +17,21 @@
 package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
+import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED;
+import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
+import static android.app.admin.DevicePolicyManager.CODE_HAS_PAIRED;
+import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
+import static android.app.admin.DevicePolicyManager.CODE_NONSYSTEM_USER_EXISTS;
+import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT;
+import static android.app.admin.DevicePolicyManager.CODE_OK;
+import static android.app.admin.DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_SYSTEM_USER;
+import static android.app.admin.DevicePolicyManager.CODE_USER_HAS_PROFILE_OWNER;
+import static android.app.admin.DevicePolicyManager.CODE_USER_NOT_RUNNING;
+import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -310,21 +325,6 @@
     private static final int PROFILE_KEYGUARD_FEATURES =
             PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
 
-    private static final int CODE_OK = 0;
-    private static final int CODE_HAS_DEVICE_OWNER = 1;
-    private static final int CODE_USER_HAS_PROFILE_OWNER = 2;
-    private static final int CODE_USER_NOT_RUNNING = 3;
-    private static final int CODE_USER_SETUP_COMPLETED = 4;
-    private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
-    private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
-    private static final int CODE_NOT_SYSTEM_USER = 7;
-    private static final int CODE_HAS_PAIRED = 8;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
-            CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER })
-    private @interface DeviceOwnerPreConditionCode {}
-
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
     /**
@@ -6520,7 +6520,7 @@
             enforceCanManageProfileAndDeviceOwners();
         }
 
-        final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb());
+        final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, userId, isAdb());
         switch (code) {
             case CODE_OK:
                 return;
@@ -6547,7 +6547,7 @@
                 throw new IllegalStateException("Not allowed to set the device owner because this "
                         + "device has already paired");
             default:
-                throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
+                throw new IllegalStateException("Unexpected @ProvisioningPreCondition " + code);
         }
     }
 
@@ -8754,79 +8754,42 @@
 
     @Override
     public boolean isProvisioningAllowed(String action) {
+        return checkProvisioningPreConditionSkipPermission(action) == CODE_OK;
+    }
+
+    @Override
+    public int checkProvisioningPreCondition(String action) {
+        enforceCanManageProfileAndDeviceOwners();
+        return checkProvisioningPreConditionSkipPermission(action);
+    }
+
+    private int checkProvisioningPreConditionSkipPermission(String action) {
         if (!mHasFeature) {
-            return false;
+            return CODE_DEVICE_ADMIN_NOT_SUPPORTED;
         }
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
-        if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
-            if (!hasFeatureManagedUsers()) {
-                return false;
+        if (action != null) {
+            switch (action) {
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE:
+                    return checkManagedProfileProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
+                    return checkDeviceOwnerProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_USER:
+                    return checkManagedUserProvisioningPreCondition(callingUserId);
+                case DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
+                    return checkManagedShareableDeviceProvisioningPreCondition(callingUserId);
             }
-            synchronized (this) {
-                if (mOwners.hasDeviceOwner()) {
-                    // STOPSHIP Only allow creating a managed profile if allowed by the device
-                    // owner. http://b/31952368
-                    if (mInjector.userManagerIsSplitSystemUser()) {
-                        if (callingUserId == UserHandle.USER_SYSTEM) {
-                            // Managed-profiles cannot be setup on the system user.
-                            return false;
-                        }
-                    }
-                }
-            }
-            if (getProfileOwner(callingUserId) != null) {
-                // Managed user cannot have a managed profile.
-                return false;
-            }
-            boolean canRemoveProfile
-                    = !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
-                if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
-                    return false;
-                }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
-            return true;
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE.equals(action)) {
-            return isDeviceOwnerProvisioningAllowed(callingUserId);
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_USER.equals(action)) {
-            if (!hasFeatureManagedUsers()) {
-                return false;
-            }
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                // ACTION_PROVISION_MANAGED_USER only supported on split-user systems.
-                return false;
-            }
-            if (callingUserId == UserHandle.USER_SYSTEM) {
-                // System user cannot be a managed user.
-                return false;
-            }
-            if (hasUserSetupCompleted(callingUserId)) {
-                return false;
-            }
-            if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
-                return false;
-            }
-            return true;
-        } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE.equals(action)) {
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                // ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE only supported on split-user systems.
-                return false;
-            }
-            return isDeviceOwnerProvisioningAllowed(callingUserId);
         }
         throw new IllegalArgumentException("Unknown provisioning action " + action);
     }
 
-    /*
+    /**
      * The device owner can only be set before the setup phase of the primary user has completed,
      * except for adb command if no accounts or additional users are present on the device.
      */
-    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked(
-            @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) {
+    private int checkDeviceOwnerProvisioningPreConditionLocked(@Nullable ComponentName owner,
+            int deviceOwnerUserId, boolean isAdb) {
         if (mOwners.hasDeviceOwner()) {
             return CODE_HAS_DEVICE_OWNER;
         }
@@ -8871,13 +8834,75 @@
         }
     }
 
-    private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
+    private int checkDeviceOwnerProvisioningPreCondition(int deviceOwnerUserId) {
         synchronized (this) {
-            return CODE_OK == checkSetDeviceOwnerPreConditionLocked(
-                    /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false);
+            return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null,
+                    deviceOwnerUserId, /* isAdb= */ false);
         }
     }
 
+    private int checkManagedProfileProvisioningPreCondition(int callingUserId) {
+        if (!hasFeatureManagedUsers()) {
+            return CODE_MANAGED_USERS_NOT_SUPPORTED;
+        }
+        synchronized (this) {
+            if (mOwners.hasDeviceOwner()) {
+                // STOPSHIP Only allow creating a managed profile if allowed by the device
+                // owner. http://b/31952368
+                if (mInjector.userManagerIsSplitSystemUser()) {
+                    if (callingUserId == UserHandle.USER_SYSTEM) {
+                        // Managed-profiles cannot be setup on the system user.
+                        return CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
+                    }
+                }
+            }
+        }
+        if (getProfileOwner(callingUserId) != null) {
+            // Managed user cannot have a managed profile.
+            return CODE_USER_HAS_PROFILE_OWNER;
+        }
+        boolean canRemoveProfile =
+                !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
+                return CODE_CANNOT_ADD_MANAGED_PROFILE;
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+        return CODE_OK;
+    }
+
+    private int checkManagedUserProvisioningPreCondition(int callingUserId) {
+        if (!hasFeatureManagedUsers()) {
+            return CODE_MANAGED_USERS_NOT_SUPPORTED;
+        }
+        if (!mInjector.userManagerIsSplitSystemUser()) {
+            // ACTION_PROVISION_MANAGED_USER only supported on split-user systems.
+            return CODE_NOT_SYSTEM_USER_SPLIT;
+        }
+        if (callingUserId == UserHandle.USER_SYSTEM) {
+            // System user cannot be a managed user.
+            return CODE_SYSTEM_USER;
+        }
+        if (hasUserSetupCompleted(callingUserId)) {
+            return CODE_USER_SETUP_COMPLETED;
+        }
+        if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
+            return CODE_HAS_PAIRED;
+        }
+        return CODE_OK;
+    }
+
+    private int checkManagedShareableDeviceProvisioningPreCondition(int callingUserId) {
+        if (!mInjector.userManagerIsSplitSystemUser()) {
+            // ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE only supported on split-user systems.
+            return CODE_NOT_SYSTEM_USER_SPLIT;
+        }
+        return checkDeviceOwnerProvisioningPreCondition(callingUserId);
+    }
+
     private boolean hasFeatureManagedUsers() {
         try {
             return mIPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0);
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 350be51..387af17 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1993,7 +1993,7 @@
         // UnfinishedVerificationException.
     }
 
-    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+    public void setup_DeviceAdminFeatureOff() throws Exception {
         when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
                 .thenReturn(false);
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2005,7 +2005,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+        setup_DeviceAdminFeatureOff();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2013,7 +2016,21 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
     }
 
-    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+    public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception {
+        setup_DeviceAdminFeatureOff();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
+    }
+
+    public void setup_ManagedProfileFeatureOff() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(false);
         initializeDpms();
@@ -2023,7 +2040,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+        setup_ManagedProfileFeatureOff();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2039,7 +2059,33 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
     }
 
-    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+    public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception {
+        setup_ManagedProfileFeatureOff();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+
+        // Test again when split user is on
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
+    }
+
+    public void setup_nonSplitUser_firstBoot_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
@@ -2048,7 +2094,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+        setup_nonSplitUser_firstBoot_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
@@ -2057,8 +2106,22 @@
                 false /* because of non-split user */);
     }
 
-    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+    public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser()
             throws Exception {
+        setup_nonSplitUser_firstBoot_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+    }
+
+    public void setup_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
@@ -2067,7 +2130,11 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_nonSplitUser_afterDeviceSetup_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 false/* because of completed device setup */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
@@ -2077,7 +2144,22 @@
                 false/* because of non-split user */);
     }
 
-    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+    public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_nonSplitUser_afterDeviceSetup_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
+    }
+
+    public void setup_splitUser_firstBoot_systemUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2086,7 +2168,10 @@
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+        setup_splitUser_firstBoot_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 false /* because canAddMoreManagedProfiles returns false */);
@@ -2094,10 +2179,24 @@
                 true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                 false/* because calling uid is system user */);
-
     }
 
-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+    public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser()
+            throws Exception {
+        setup_splitUser_firstBoot_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_SYSTEM_USER);
+    }
+
+    public void setup_splitUser_afterDeviceSetup_systemUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2106,7 +2205,10 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+        setup_splitUser_afterDeviceSetup_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 true/* it's undefined behavior. Can be changed into false in the future */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
@@ -2117,7 +2219,22 @@
                 false/* because calling uid is system user */);
     }
 
-    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser()
+            throws Exception {
+        setup_splitUser_afterDeviceSetup_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_SYSTEM_USER);
+    }
+
+    public void setup_splitUser_firstBoot_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2126,17 +2243,33 @@
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+        setup_splitUser_firstBoot_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                 true);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
-
     }
 
-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+    public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser()
             throws Exception {
+        setup_splitUser_firstBoot_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_OK);
+    }
+
+    public void setup_splitUser_afterDeviceSetup_primaryUser() throws Exception {
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
@@ -2145,7 +2278,11 @@
         setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        setup_splitUser_afterDeviceSetup_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                 true/* it's undefined behavior. Can be changed into false in the future */);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
@@ -2155,8 +2292,22 @@
                 false/* because user setup completed */);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser()
             throws Exception {
+        setup_splitUser_afterDeviceSetup_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(
+                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                DevicePolicyManager.CODE_OK);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
+    }
+
+    public void setup_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2167,13 +2318,24 @@
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+            throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_systemUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 false /* can't provision managed profile on system user */);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser()
             throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_systemUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
+    }
+
+    private void setup_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2184,12 +2346,23 @@
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
     }
 
-    public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser()
             throws Exception {
+        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_OK);
+    }
+
+    private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception {
         setDeviceOwner();
 
         when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
@@ -2198,16 +2371,37 @@
         when(mContext.userManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER))
                 .thenReturn(true);
         when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
-                false /* we can't remove a managed profile*/)).thenReturn(false);
+                false /* we can't remove a managed profile */)).thenReturn(false);
         when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                 true)).thenReturn(true);
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+    }
 
+    public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileCantRemoveUser_primaryUser();
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
     }
 
+    public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser()
+            throws Exception {
+        setup_provisionManagedProfileCantRemoveUser_primaryUser();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+    }
+
+    public void testCheckProvisioningPreCondition_permission() {
+        // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
+        try {
+            dpm.checkProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
     public void testForceUpdateUserSetupComplete_permission() {
         // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
         try {
@@ -2518,6 +2712,11 @@
                 dpm.isProvisioningAllowed(action));
     }
 
+    private void assertCheckProvisioningPreCondition(String action, int provisioningCondition) {
+        assertEquals("checkProvisioningPreCondition(" + action + ") returning unexpected result",
+                provisioningCondition, dpm.checkProvisioningPreCondition(action));
+    }
+
     /**
      * Setup a managed profile with the specified admin and its uid.
      * @param admin ComponentName that's visible to the test code, which doesn't have to exist.