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

Commit 2d7bded7 authored by kholoud mohamed's avatar kholoud mohamed Committed by Kholoud Mohamed
Browse files

Add QUERY_USERS permission to some UserManager APIs

The followings APIs now accept QUERY_USERS
(and any other APIs that depends on them):

* getUserRestrictionSources
* isSameProfileGroup
* getAllProfiles
* isManagedProfile
* canAddMoreManagedProfiles

Also exposed isProfile as public, and deprecated getEnabledProfiles

Test: atest android.multiuser.cts.UserManagerTest
Bug: 188410712
Bug: 205707885
Bug: 206106797
Change-Id: I4cc4f7078271e42a2bcaa6965c107a6e249e00fc
parent d0fe35e8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32477,7 +32477,7 @@ package android.os {
    method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public int getUserCount();
    method public long getUserCreationTime(android.os.UserHandle);
    method public android.os.UserHandle getUserForSerialNumber(long);
    method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, "android.permission.CREATE_USERS"}, conditional=true) public String getUserName();
    method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS", "android.permission.QUERY_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public String getUserName();
    method public java.util.List<android.os.UserHandle> getUserProfiles();
    method public android.os.Bundle getUserRestrictions();
    method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
+11 −11
Original line number Diff line number Diff line
@@ -9018,31 +9018,31 @@ package android.os {
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.NewUserResponse createUser(@NonNull android.os.NewUserRequest);
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
    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 @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_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 android.os.PersistableBundle getSeedAccountOptions();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public long[] getSerialNumbersOfUsers(boolean);
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
    method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
    method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
    method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isAdminUser();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isCloneProfile();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isGuestUser();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isPrimaryUser();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isProfile();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
    method public boolean isProfile();
    method public boolean isRestrictedProfile();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
+1 −1
Original line number Diff line number Diff line
@@ -1823,7 +1823,7 @@ package android.os {
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String);
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public String getUserType();
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
    method public static boolean isGuestUserEphemeral();
+126 −67

File changed.

Preview size limit exceeded, changes collapsed.

+109 −14
Original line number Diff line number Diff line
@@ -865,7 +865,7 @@ public class UserManagerService extends IUserManager.Stub {
    public List<UserInfo> getProfiles(@UserIdInt int userId, boolean enabledOnly) {
        boolean returnFullInfo;
        if (userId != UserHandle.getCallingUserId()) {
            checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
            checkQueryOrCreateUsersPermission("getting profiles related to user " + userId);
            returnFullInfo = true;
        } else {
            returnFullInfo = hasManageOrCreateUsersPermission();
@@ -898,7 +898,7 @@ public class UserManagerService extends IUserManager.Stub {
    public int[] getProfileIds(@UserIdInt int userId, @Nullable String userType,
            boolean enabledOnly) {
        if (userId != UserHandle.getCallingUserId()) {
            checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
            checkQueryOrCreateUsersPermission("getting profiles related to user " + userId);
        }
        final long ident = Binder.clearCallingIdentity();
        try {
@@ -987,7 +987,7 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) {
        if (userId == otherUserId) return true;
        checkManageUsersPermission("check if in the same profile group");
        checkQueryUsersPermission("check if in the same profile group");
        return isSameProfileGroupNoChecks(userId, otherUserId);
    }

@@ -1388,7 +1388,7 @@ public class UserManagerService extends IUserManager.Stub {

    @Override
    public UserInfo getUserInfo(@UserIdInt int userId) {
        checkManageOrCreateUsersPermission("query user");
        checkQueryOrCreateUsersPermission("query user");
        synchronized (mUsersLock) {
            return userWithName(getUserInfoLU(userId));
        }
@@ -1519,7 +1519,7 @@ public class UserManagerService extends IUserManager.Stub {

    @Override
    public boolean isProfile(@UserIdInt int userId) {
        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isProfile");
        checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isProfile");
        synchronized (mUsersLock) {
            UserInfo userInfo = getUserInfoLU(userId);
            return userInfo != null && userInfo.isProfile();
@@ -1528,7 +1528,7 @@ public class UserManagerService extends IUserManager.Stub {

    @Override
    public boolean isManagedProfile(@UserIdInt int userId) {
        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isManagedProfile");
        checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isManagedProfile");
        synchronized (mUsersLock) {
            UserInfo userInfo = getUserInfoLU(userId);
            return userInfo != null && userInfo.isManagedProfile();
@@ -1592,7 +1592,7 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public String getUserName() {
        final int callingUid = Binder.getCallingUid();
        if (!hasManageOrCreateUsersPermission()
        if (!hasQueryOrCreateUsersPermission()
                && !hasPermissionGranted(
                        android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid)) {
            throw new SecurityException("You need MANAGE_USERS or CREATE_USERS or "
@@ -1628,18 +1628,59 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    /**
     * Enforces that the calling user is in the same profile group as {@code userId} or that only
     * the system UID or root's UID or apps that have the
     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS INTERACT_ACROSS_USERS}
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
     * can make certain calls to the UserManager.
     *
     * @param name used as message if SecurityException is thrown
     * @throws SecurityException if the caller lacks the required permissions.
     */
    private void checkManageOrInteractPermissionIfCallerInOtherProfileGroup(@UserIdInt int userId,
            String name) {
        final int callingUserId = UserHandle.getCallingUserId();
        if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) ||
                hasManageUsersPermission()) {
        if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId)) {
            return;
        }
        if (hasManageUsersPermission()) {
            return;
        }
        if (!hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS,
        if (hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS,
                Binder.getCallingUid())) {
            return;
        }
        throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS permission "
                + "to: check " + name);
    }

    /**
     * Enforces that the calling user is in the same profile group as {@code userId} or that only
     * the system UID or root's UID or apps that have the
     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS INTERACT_ACROSS_USERS}
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}
     * can make certain calls to the UserManager.
     *
     * @param name used as message if SecurityException is thrown
     * @throws SecurityException if the caller lacks the required permissions.
     */
    private void checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(
            @UserIdInt int userId, String name) {
        final int callingUserId = UserHandle.getCallingUserId();
        if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId)) {
            return;
        }
        if (hasQueryUsersPermission()) {
            return;
        }
        if (hasPermissionGranted(
                Manifest.permission.INTERACT_ACROSS_USERS, Binder.getCallingUid())) {
            return;
        }
        throw new SecurityException("You need INTERACT_ACROSS_USERS, MANAGE_USERS, or QUERY_USERS "
                + "permission to: check " + name);
    }

    @Override
@@ -2147,7 +2188,7 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public List<EnforcingUser> getUserRestrictionSources(
            String restrictionKey, @UserIdInt int userId) {
        checkManageUsersPermission("getUserRestrictionSource");
        checkQueryUsersPermission("call getUserRestrictionSources.");

        // Shortcut for the most common case
        if (!hasUserRestriction(restrictionKey, userId)) {
@@ -2426,7 +2467,7 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public boolean canAddMoreProfilesToUser(String userType, @UserIdInt int userId,
            boolean allowedToRemoveOne) {
        checkManageUsersPermission("check if more profiles can be added.");
        checkQueryUsersPermission("check if more profiles can be added.");
        final UserTypeDetails type = mUserTypes.get(userType);
        if (type == null || !type.isEnabled()) {
            return false;
@@ -2545,6 +2586,40 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    /**
    * Enforces that only the system UID or root's UID or apps that have the
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}
     * can make certain calls to the UserManager.
     *
     * @param message used as message if SecurityException is thrown
     * @throws SecurityException if the caller lacks the required permissions.
     */
    private static final void checkQueryUsersPermission(String message) {
        if (!hasQueryUsersPermission()) {
            throw new SecurityException(
                    "You either need MANAGE_USERS or QUERY_USERS permission to: " + message);
        }
    }

    /**
     * Enforces that only the system UID or root's UID or apps that have the
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} or
     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}
     * can make certain calls to the UserManager.
     *
     * @param message used as message if SecurityException is thrown
     * @throws SecurityException if the caller lacks the required permissions.
     */
    private static final void checkQueryOrCreateUsersPermission(String message) {
        if (!hasQueryOrCreateUsersPermission()) {
            throw new SecurityException(
                    "You either need MANAGE_USERS, CREATE_USERS, or QUERY_USERS permission to: "
                            + message);
        }
    }

    /**
     * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
     * to create user/profiles other than what is allowed for
@@ -2601,6 +2676,26 @@ public class UserManagerService extends IUserManager.Stub {
        return hasManageUsersOrPermission(android.Manifest.permission.CREATE_USERS);
    }

    /**
     * @return whether the calling UID is system UID or root's UID or the calling app has the
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}.
     */
    private static final boolean hasQueryUsersPermission() {
        return hasManageUsersOrPermission(android.Manifest.permission.QUERY_USERS);
    }

    /**
     * @return whether the calling UID is system UID or root's UID or the calling app has
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} or
     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}.
     */
    private static final boolean hasQueryOrCreateUsersPermission() {
        return hasManageOrCreateUsersPermission()
                || hasPermissionGranted(Manifest.permission.QUERY_USERS, Binder.getCallingUid());
    }

    /**
     * Enforces that only the system UID or root's UID (on any user) can make certain calls to the
     * UserManager.