Merge "Add APIs to UserManager for getting remaining user/profile counts."

This commit is contained in:
Yasin Kilicdere
2022-01-27 16:27:24 +00:00
committed by Android (Google) Code Review
4 changed files with 139 additions and 16 deletions

View File

@@ -9324,6 +9324,8 @@ package android.os {
method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles();
method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getRestrictedProfileParent();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();

View File

@@ -62,6 +62,8 @@ interface IUserManager {
int[] getProfileIds(int userId, boolean enabledOnly);
boolean isUserTypeEnabled(in String userType);
boolean canAddMoreUsersOfType(in String userType);
int getRemainingCreatableUserCount(in String userType);
int getRemainingCreatableProfileCount(in String userType, int userId, boolean allowedToRemoveOne);
boolean canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne);
boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
UserInfo getProfileParent(int userId);

View File

@@ -4028,6 +4028,58 @@ public class UserManager {
}
}
/**
* Returns the remaining number of users of the given type that can be created.
*
* @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_SECONDARY}.
* @return how many additional users can be created.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS,
android.Manifest.permission.QUERY_USERS
})
public int getRemainingCreatableUserCount(@NonNull String userType) {
Objects.requireNonNull(userType, "userType must not be null");
try {
return mService.getRemainingCreatableUserCount(userType);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
* Returns the remaining number of profiles that can be added to the context user.
* <p>Note that is applicable to any profile type (currently not including Restricted profiles).
*
* @param userType the type of profile, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}.
* @param allowedToRemoveOne whether removing an existing profile of given type -if there is-
* from the context user to make up space should be taken into account
* for the calculation.
* @return how many additional profiles can be created.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS,
android.Manifest.permission.QUERY_USERS
})
@UserHandleAware
public int getRemainingCreatableProfileCount(@NonNull String userType,
boolean allowedToRemoveOne) {
Objects.requireNonNull(userType, "userType must not be null");
try {
// TODO(b/142482943): Perhaps let the following code apply to restricted users too.
return mService.getRemainingCreatableProfileCount(userType, mUserId,
allowedToRemoveOne);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
* Checks whether it's possible to add more managed profiles.
* if allowedToRemoveOne is true and if the user already has a managed profile, then return if
@@ -4038,6 +4090,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS,
android.Manifest.permission.QUERY_USERS
})
public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
@@ -4057,6 +4110,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS,
android.Manifest.permission.QUERY_USERS
})
public boolean canAddMoreProfilesToUser(@NonNull String userType, @UserIdInt int userId) {
@@ -4904,8 +4958,8 @@ public class UserManager {
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
return Math.max(1, SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)));
}
/**

View File

@@ -2417,6 +2417,51 @@ public class UserManagerService extends IUserManager.Stub {
return getNumberOfUsersOfType(userTypeDetails.getName()) < max;
}
/**
* Returns the remaining number of users of the given type that can be created. (taking into
* account the total number of users on the device as well as how many exist of that type)
*/
@Override
public int getRemainingCreatableUserCount(String userType) {
checkQueryOrCreateUsersPermission("get the remaining number of users that can be added.");
final UserTypeDetails type = mUserTypes.get(userType);
if (type == null || !type.isEnabled()) {
return 0;
}
synchronized (mUsersLock) {
final int userCount = getAliveUsersExcludingGuestsCountLU();
// Limit total number of users that can be created (except for guest and demo)
int result =
UserManager.isUserTypeGuest(userType) || UserManager.isUserTypeDemo(userType)
? Integer.MAX_VALUE
: (UserManager.getMaxSupportedUsers() - userCount);
// Managed profiles have their own specific rules.
if (type.isManagedProfile()) {
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MANAGED_USERS)) {
return 0;
}
// Special case: Allow creating a managed profile anyway if there's only 1 user
if (result <= 0 & userCount == 1) {
result = 1;
}
}
if (result <= 0) {
return 0;
}
// Limit against max allowed for type
result = Math.min(result,
type.getMaxAllowed() == UserTypeDetails.UNLIMITED_NUMBER_OF_USERS
? Integer.MAX_VALUE
: (type.getMaxAllowed() - getNumberOfUsersOfType(userType)));
return Math.max(0, result);
}
}
/**
* Gets the number of users of the given user type.
* Does not include users that are about to die.
@@ -2467,24 +2512,36 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public boolean canAddMoreProfilesToUser(String userType, @UserIdInt int userId,
boolean allowedToRemoveOne) {
checkQueryUsersPermission("check if more profiles can be added.");
return 0 < getRemainingCreatableProfileCount(userType, userId, allowedToRemoveOne);
}
/**
* Returns the remaining number of profiles of the given type that can be added to the given
* user. (taking into account the total number of users on the device as well as how many
* profiles exist of that type both in general and for the given user)
*/
@Override
public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId,
boolean allowedToRemoveOne) {
checkQueryOrCreateUsersPermission(
"get the remaining number of profiles that can be added to the given user.");
final UserTypeDetails type = mUserTypes.get(userType);
if (type == null || !type.isEnabled()) {
return false;
return 0;
}
// Managed profiles have their own specific rules.
final boolean isManagedProfile = type.isManagedProfile();
if (isManagedProfile) {
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MANAGED_USERS)) {
return false;
return 0;
}
}
synchronized (mUsersLock) {
// Check if the parent exists and its type is even allowed to have a profile.
UserInfo userInfo = getUserInfoLU(userId);
if (userInfo == null || !userInfo.canHaveProfile()) {
return false;
return 0;
}
final int userTypeCount = getProfileIds(userId, userType, false).length;
@@ -2493,23 +2550,30 @@ public class UserManagerService extends IUserManager.Stub {
- profilesRemovedCount;
// Limit total number of users that can be created
if (usersCountAfterRemoving >= UserManager.getMaxSupportedUsers()) {
// Special case: Allow creating a managed profile anyway if there's only 1 user
// Otherwise, disallow.
if (!(isManagedProfile && usersCountAfterRemoving == 1)) {
return false;
}
int result = UserManager.getMaxSupportedUsers() - usersCountAfterRemoving;
// Special case: Allow creating a managed profile anyway if there's only 1 user
if (result <= 0 && isManagedProfile && usersCountAfterRemoving == 1) {
result = 1;
}
// Limit the number of profiles of this type that can be created.
final int maxUsersOfType = getMaxUsersOfTypePerParent(type);
if (maxUsersOfType != UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) {
if (userTypeCount - profilesRemovedCount >= maxUsersOfType) {
return false;
}
result = Math.min(result, maxUsersOfType - (userTypeCount - profilesRemovedCount));
}
if (result <= 0) {
return 0;
}
// Limit against max allowed for type (beyond max allowed per parent)
if (type.getMaxAllowed() != UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) {
result = Math.min(result, type.getMaxAllowed()
- (getNumberOfUsersOfType(userType) - profilesRemovedCount));
}
return Math.max(0, result);
}
return true;
}
@GuardedBy("mUsersLock")
@@ -3791,6 +3855,7 @@ public class UserManagerService extends IUserManager.Stub {
+ ". Maximum number of that type already exists.",
UserManager.USER_OPERATION_ERROR_MAX_USERS);
}
// Keep logic in sync with getRemainingCreatableUserCount()
if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
// If the user limit has been reached, we cannot add a user (except guest/demo).
// Note that managed profiles can bypass it in certain circumstances (taken