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

Commit 189b76c2 authored by Yasin Kilicdere's avatar Yasin Kilicdere Committed by Android (Google) Code Review
Browse files

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

parents b89f428f e7a1b7b9
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -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> getAllProfiles();
    method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
    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 @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 @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 String getSeedAccountName();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
+2 −0
Original line number Original line Diff line number Diff line
@@ -62,6 +62,8 @@ interface IUserManager {
    int[] getProfileIds(int userId, boolean enabledOnly);
    int[] getProfileIds(int userId, boolean enabledOnly);
    boolean isUserTypeEnabled(in String userType);
    boolean isUserTypeEnabled(in String userType);
    boolean canAddMoreUsersOfType(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 canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne);
    boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
    boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
    UserInfo getProfileParent(int userId);
    UserInfo getProfileParent(int userId);
+56 −2
Original line number Original line 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.
     * 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
     * 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 = {
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.CREATE_USERS,
            android.Manifest.permission.QUERY_USERS
            android.Manifest.permission.QUERY_USERS
    })
    })
    public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
    public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
@@ -4057,6 +4110,7 @@ public class UserManager {
     */
     */
    @RequiresPermission(anyOf = {
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.CREATE_USERS,
            android.Manifest.permission.QUERY_USERS
            android.Manifest.permission.QUERY_USERS
    })
    })
    public boolean canAddMoreProfilesToUser(@NonNull String userType, @UserIdInt int userId) {
    public boolean canAddMoreProfilesToUser(@NonNull String userType, @UserIdInt int userId) {
@@ -4904,8 +4958,8 @@ public class UserManager {
    public static int getMaxSupportedUsers() {
    public static int getMaxSupportedUsers() {
        // Don't allow multiple users on certain builds
        // Don't allow multiple users on certain builds
        if (android.os.Build.ID.startsWith("JVP")) return 1;
        if (android.os.Build.ID.startsWith("JVP")) return 1;
        return SystemProperties.getInt("fw.max_users",
        return Math.max(1, SystemProperties.getInt("fw.max_users",
                Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
                Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)));
    }
    }


    /**
    /**
+79 −14
Original line number Original line Diff line number Diff line
@@ -2417,6 +2417,51 @@ public class UserManagerService extends IUserManager.Stub {
        return getNumberOfUsersOfType(userTypeDetails.getName()) < max;
        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.
     * Gets the number of users of the given user type.
     * Does not include users that are about to die.
     * Does not include users that are about to die.
@@ -2467,24 +2512,36 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    @Override
    public boolean canAddMoreProfilesToUser(String userType, @UserIdInt int userId,
    public boolean canAddMoreProfilesToUser(String userType, @UserIdInt int userId,
            boolean allowedToRemoveOne) {
            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);
        final UserTypeDetails type = mUserTypes.get(userType);
        if (type == null || !type.isEnabled()) {
        if (type == null || !type.isEnabled()) {
            return false;
            return 0;
        }
        }
        // Managed profiles have their own specific rules.
        // Managed profiles have their own specific rules.
        final boolean isManagedProfile = type.isManagedProfile();
        final boolean isManagedProfile = type.isManagedProfile();
        if (isManagedProfile) {
        if (isManagedProfile) {
            if (!mContext.getPackageManager().hasSystemFeature(
            if (!mContext.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_MANAGED_USERS)) {
                    PackageManager.FEATURE_MANAGED_USERS)) {
                return false;
                return 0;
            }
            }
        }
        }
        synchronized (mUsersLock) {
        synchronized (mUsersLock) {
            // Check if the parent exists and its type is even allowed to have a profile.
            // Check if the parent exists and its type is even allowed to have a profile.
            UserInfo userInfo = getUserInfoLU(userId);
            UserInfo userInfo = getUserInfoLU(userId);
            if (userInfo == null || !userInfo.canHaveProfile()) {
            if (userInfo == null || !userInfo.canHaveProfile()) {
                return false;
                return 0;
            }
            }


            final int userTypeCount = getProfileIds(userId, userType, false).length;
            final int userTypeCount = getProfileIds(userId, userType, false).length;
@@ -2493,23 +2550,30 @@ public class UserManagerService extends IUserManager.Stub {
                    - profilesRemovedCount;
                    - profilesRemovedCount;


            // Limit total number of users that can be created
            // 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
            // Special case: Allow creating a managed profile anyway if there's only 1 user
                // Otherwise, disallow.
            if (result <= 0 && isManagedProfile && usersCountAfterRemoving == 1) {
                if (!(isManagedProfile && usersCountAfterRemoving == 1)) {
                result = 1;
                    return false;
                }
            }
            }


            // Limit the number of profiles of this type that can be created.
            // Limit the number of profiles of this type that can be created.
            final int maxUsersOfType = getMaxUsersOfTypePerParent(type);
            final int maxUsersOfType = getMaxUsersOfTypePerParent(type);
            if (maxUsersOfType != UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) {
            if (maxUsersOfType != UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) {
                if (userTypeCount - profilesRemovedCount >= maxUsersOfType) {
                result = Math.min(result, maxUsersOfType - (userTypeCount - profilesRemovedCount));
                    return false;
            }
            }
            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")
    @GuardedBy("mUsersLock")
@@ -3791,6 +3855,7 @@ public class UserManagerService extends IUserManager.Stub {
                                    + ". Maximum number of that type already exists.",
                                    + ". Maximum number of that type already exists.",
                            UserManager.USER_OPERATION_ERROR_MAX_USERS);
                            UserManager.USER_OPERATION_ERROR_MAX_USERS);
                }
                }
                // Keep logic in sync with getRemainingCreatableUserCount()
                if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
                if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
                    // If the user limit has been reached, we cannot add a user (except guest/demo).
                    // 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
                    // Note that managed profiles can bypass it in certain circumstances (taken