Add method to tell the dpc if provisioning is allowed.
The DPC can use it to tell if provisioning a managed profile or for
device owner would work or not.
BUG:25338478
Change-Id: I09ea6a9f23a8e88e4ed37c048170b2a68213086e
diff --git a/api/current.txt b/api/current.txt
index 62f0113..6c64e28 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5741,6 +5741,7 @@
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
+ method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void removeActiveAdmin(android.content.ComponentName);
diff --git a/api/system-current.txt b/api/system-current.txt
index 4118f33..df63ecf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5870,6 +5870,7 @@
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
+ method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void notifyPendingSystemUpdate(long);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0fdf3d3..6a3f8e6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4299,4 +4299,23 @@
return PERMISSION_GRANT_STATE_DEFAULT;
}
}
+
+ /**
+ * Returns if provisioning a managed profile or device is possible or not.
+ * @param action One of {@link #ACTION_PROVISION_MANAGED_DEVICE},
+ * {@link #ACTION_PROVISION_MANAGED_PROFILE}.
+ * Note that even if this method returns true, there is a slight possibility that the
+ * provisioning will not be allowed when it is actually initiated because some event has
+ * happened in between.
+ * @return if provisioning a managed profile or device is possible or not.
+ * @throws IllegalArgumentException if the supplied action is not valid.
+ */
+ public boolean isProvisioningAllowed(String action) {
+ try {
+ return mService.isProvisioningAllowed(action);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
+ return false;
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ccaa8cb..15e8837 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -227,4 +227,5 @@
boolean setPermissionGrantState(in ComponentName admin, String packageName,
String permission, int grantState);
int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
+ boolean isProvisioningAllowed(String action);
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 12cac85..b5bbbbb 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -44,7 +44,7 @@
UserInfo getPrimaryUser();
List<UserInfo> getUsers(boolean excludeDying);
List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
- boolean canAddMoreManagedProfiles(int userId);
+ boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
UserInfo getProfileParent(int userHandle);
boolean isSameProfileGroup(int userId, int otherUserId);
UserInfo getUserInfo(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e892349..c191b23 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1077,13 +1077,15 @@
/**
* Checks whether it's possible to add more managed profiles. Caller must hold the MANAGE_USERS
* permission.
+ * if allowedToRemoveOne is true and if the user already has a managed profile, then return if
+ * we could add a new managed profile to this user after removing the existing one.
*
* @return true if more managed profiles can be added, false if limit has been reached.
* @hide
*/
- public boolean canAddMoreManagedProfiles(int userId) {
+ public boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne) {
try {
- return mService.canAddMoreManagedProfiles(userId);
+ return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne);
} catch (RemoteException re) {
Log.w(TAG, "Could not check if we can add more managed profiles", re);
return false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c41d493..ebb69bf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -853,7 +853,7 @@
}
@Override
- public boolean canAddMoreManagedProfiles(int userId) {
+ public boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne) {
checkManageUsersPermission("check if more managed profiles can be added.");
if (ActivityManager.isLowRamDeviceStatic()) {
return false;
@@ -863,8 +863,9 @@
return false;
}
// Limit number of managed profiles that can be created
- int managedProfilesCount = getProfiles(userId, true).size() - 1;
- if (managedProfilesCount >= MAX_MANAGED_PROFILES) {
+ final int managedProfilesCount = getProfiles(userId, true).size() - 1;
+ final int profilesRemovedCount = managedProfilesCount > 0 && allowedToRemoveOne ? 1 : 0;
+ if (managedProfilesCount - profilesRemovedCount >= MAX_MANAGED_PROFILES) {
return false;
}
synchronized(mUsersLock) {
@@ -872,9 +873,11 @@
if (!userInfo.canHaveProfile()) {
return false;
}
- int usersCount = getAliveUsersExcludingGuestsCountLU();
+ int usersCountAfterRemoving = getAliveUsersExcludingGuestsCountLU()
+ - profilesRemovedCount;
// We allow creating a managed profile in the special case where there is only one user.
- return usersCount == 1 || usersCount < UserManager.getMaxSupportedUsers();
+ return usersCountAfterRemoving == 1
+ || usersCountAfterRemoving < UserManager.getMaxSupportedUsers();
}
}
@@ -1450,7 +1453,7 @@
}
if (parent == null) return null;
}
- if (isManagedProfile && !canAddMoreManagedProfiles(parentId)) {
+ if (isManagedProfile && !canAddMoreManagedProfiles(parentId, false)) {
Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
return null;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index aea2ecf..cabebe7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1220,6 +1220,10 @@
Settings.Secure.putInt(mContext.getContentResolver(), name, value);
}
+ int settingsGlobalGetInt(String name, int def) {
+ return Settings.Global.getInt(mContext.getContentResolver(), name, def);
+ }
+
void settingsGlobalPutInt(String name, int value) {
Settings.Global.putInt(mContext.getContentResolver(), name, value);
}
@@ -6622,4 +6626,43 @@
throw new RuntimeException("Package manager has died", re);
}
}
+
+ @Override
+ public boolean isProvisioningAllowed(String action) {
+ if (mOwners.hasDeviceOwner()) {
+ return false;
+ }
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
+ try {
+ if (!mIPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
+ return false;
+ }
+ } catch (RemoteException e) {
+ return false;
+ }
+ final long ident = mInjector.binderClearCallingIdentity();
+ try {
+ if (!mUserManager.canAddMoreManagedProfiles(callingUserId, true)) {
+ return false;
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ return true;
+ } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE.equals(action)) {
+ if (getProfileOwner(callingUserId) != null) {
+ return false;
+ }
+ if (mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
+ return false;
+ }
+ if (callingUserId != UserHandle.USER_SYSTEM) {
+ // Device owner provisioning can only be initiated from system user.
+ return false;
+ }
+ return true;
+ }
+ throw new IllegalArgumentException("Unknown provisioning action " + action);
+ }
}