Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7a1b7b9 authored by Yasin Kilicdere's avatar Yasin Kilicdere
Browse files

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

Add UM.getRemainingCreatableUserCount(userType) method as a system API.
Add UM.getRemainingCreatableProfileCount(userType, allowedToRemoveOne) method as a system API.

Bug: 208842920
Bug: 142482943
Test: atest android.multiuser.cts.UserManagerTest

Change-Id: I286fe10b2c8448aeb03ee6c791d415ef62f50451
parent c5900ec5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9637,6 +9637,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();
+2 −0
Original line number Diff line number Diff line
@@ -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);
+56 −2
Original line number Diff line number Diff line
@@ -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) {
@@ -4931,8 +4985,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)));
    }

    /**
+79 −14
Original line number Diff line number Diff line
@@ -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()) {
            int result = UserManager.getMaxSupportedUsers() - usersCountAfterRemoving;

            // Special case: Allow creating a managed profile anyway if there's only 1 user
                // Otherwise, disallow.
                if (!(isManagedProfile && usersCountAfterRemoving == 1)) {
                    return false;
                }
            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