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/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 866a551..d1cb00a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1090,6 +1090,172 @@
     public @interface UserProvisioningState {}
 
     /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE}, {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when provisioning is allowed.
+     *
+     * @hide
+     */
+    public static final int CODE_OK = 0;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the device already has a device
+     * owner.
+     *
+     * @hide
+     */
+    public static final int CODE_HAS_DEVICE_OWNER = 1;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the user has a profile owner and for
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} when the profile owner is already set.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_HAS_PROFILE_OWNER = 2;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} when the user isn't running.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_NOT_RUNNING = 3;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} if the device has already been setup and
+     * for {@link #ACTION_PROVISION_MANAGED_USER} if the user has already been setup.
+     *
+     * @hide
+     */
+    public static final int CODE_USER_SETUP_COMPLETED = 4;
+
+    /**
+     * Code used to indicate that the device also has a user other than the system user.
+     *
+     * @hide
+     */
+    public static final int CODE_NONSYSTEM_USER_EXISTS = 5;
+
+    /**
+     * Code used to indicate that device has an account that prevents provisioning.
+     *
+     * @hide
+     */
+    public static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} if the user is not a system user.
+     *
+     * @hide
+     */
+    public static final int CODE_NOT_SYSTEM_USER = 7;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} and {@link #ACTION_PROVISION_MANAGED_USER}
+     * when the device is a watch and is already paired.
+     *
+     * @hide
+     */
+    public static final int CODE_HAS_PAIRED = 8;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} and
+     * {@link #ACTION_PROVISION_MANAGED_USER} on devices which do not support managed users.
+     *
+     * @see {@link PackageManager#FEATURE_MANAGED_USERS}
+     * @hide
+     */
+    public static final int CODE_MANAGED_USERS_NOT_SUPPORTED = 9;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_USER} if the user is a system user.
+     *
+     * @hide
+     */
+    public static final int CODE_SYSTEM_USER = 10;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the user cannot have more
+     * managed profiles.
+     *
+     * @hide
+     */
+    public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices not running with split system
+     * user.
+     *
+     * @hide
+     */
+    public static final int CODE_NOT_SYSTEM_USER_SPLIT = 12;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE}, {@link #ACTION_PROVISION_MANAGED_USER} and
+     * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices which do no support device
+     * admins.
+     *
+     * @hide
+     */
+    public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13;
+
+    /**
+     * Result code for {@link checkProvisioningPreCondition}.
+     *
+     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the device has a device owner
+     * and the user is a system user on a split system user device.
+     *
+     * @hide
+     */
+    public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14;
+
+    /**
+     * Result codes for {@link checkProvisioningPreCondition} indicating all the provisioning pre
+     * conditions.
+     *
+     * @hide
+     */
+    @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, CODE_HAS_PAIRED,
+            CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
+            CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
+            CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER})
+    public @interface ProvisioningPreCondition {}
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
@@ -5951,6 +6117,24 @@
     }
 
     /**
+     * Checks if provisioning a managed profile or device is possible and returns one of the
+     * {@link ProvisioningPreCondition}.
+     *
+     * @param action One of {@link #ACTION_PROVISION_MANAGED_DEVICE},
+     *        {@link #ACTION_PROVISION_MANAGED_PROFILE},
+     *        {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE},
+     *        {@link #ACTION_PROVISION_MANAGED_USER}
+     * @hide
+     */
+    public @ProvisioningPreCondition int checkProvisioningPreCondition(String action) {
+        try {
+            return mService.checkProvisioningPreCondition(action);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return if this user is a managed profile of another user. An admin can become the profile
      * owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
      * user with {@link #createAndManageUser}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3bc8cd0..f14a313 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -269,6 +269,7 @@
             String permission, int grantState);
     int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
     boolean isProvisioningAllowed(String action);
+    int checkProvisioningPreCondition(String action);
     void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList);
     List<String> getKeepUninstalledPackages(in ComponentName admin);
     boolean isManagedProfile(in ComponentName admin);
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.