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

Commit 27fc6918 authored by Adam Bookatz's avatar Adam Bookatz
Browse files

UserManager more consistently @UserHandleAware

Some methods in UserManager are @UserHandleAware but some are not, which
is confusing and sometimes means that no userId-version of the API
exists.

Here, we make them more consistently @UserHandleAware.

Since this is a behaviour-breaking change, we gate it by SDK version.

We introduce annotation parameters to help explain this gating and any
permission requirements that only apply when the context user differs
from the calling using.

We change the documentation to say "context user" rather than "calling
user", as is done for all @UserHandleAware methods. Note, however, that
this also applies to public APIs (which have no concept of context-based
userIds), but that is consistent with current usage.

For hidden APIs, where feasible, we do not gate.

Test: atest com.android.server.pm.UserManagerTest
Test: atest android.multiuser.cts.UserManagerTest
Bug: 183155436
Change-Id: Ief94abc321bb243ce25b9baae95e554ef015d180
parent afb99dd5
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -8681,15 +8681,15 @@ package android.os {
    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(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
    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.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.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(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
    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.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String);
+6 −6
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ interface IUserManager {
    String getUserAccount(int userId);
    void setUserAccount(int userId, String accountName);
    long getUserCreationTime(int userId);
    boolean isRestricted();
    boolean isRestricted(int userId);
    boolean canHaveRestrictedProfile(int userId);
    int getUserSerialNumber(int userId);
    int getUserHandle(int userSerialNumber);
@@ -93,10 +93,10 @@ interface IUserManager {
    boolean isQuietModeEnabled(int userId);
    void setSeedAccountData(int userId, in String accountName,
            in String accountType, in PersistableBundle accountOptions, boolean persist);
    String getSeedAccountName();
    String getSeedAccountType();
    PersistableBundle getSeedAccountOptions();
    void clearSeedAccountData();
    String getSeedAccountName(int userId);
    String getSeedAccountType(int userId);
    PersistableBundle getSeedAccountOptions(int userId);
    void clearSeedAccountData(int userId);
    boolean someUserHasSeedAccount(in String accountName, in String accountType);
    boolean isProfile(int userId);
    boolean isManagedProfile(int userId);
@@ -118,7 +118,7 @@ interface IUserManager {
    boolean isUserRunning(int userId);
    boolean isUserForeground(int userId);
    boolean isUserNameSet(int userId);
    boolean hasRestrictedProfiles();
    boolean hasRestrictedProfiles(int userId);
    boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
    String getUserName();
    long getUserStartRealtime();
+295 −111

File changed.

Preview size limit exceeded, changes collapsed.

+32 −22
Original line number Diff line number Diff line
@@ -858,11 +858,12 @@ public class UserManagerService extends IUserManager.Stub {

    @Override
    public List<UserInfo> getProfiles(@UserIdInt int userId, boolean enabledOnly) {
        boolean returnFullInfo = true;
        boolean returnFullInfo;
        if (userId != UserHandle.getCallingUserId()) {
            checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
            returnFullInfo = true;
        } else {
            returnFullInfo = hasManageUsersPermission();
            returnFullInfo = hasManageOrCreateUsersPermission();
        }
        final long ident = Binder.clearCallingIdentity();
        try {
@@ -1659,9 +1660,13 @@ public class UserManagerService extends IUserManager.Stub {
    }

    @Override
    public boolean isRestricted() {
    public boolean isRestricted(@UserIdInt int userId) {
        if (userId != UserHandle.getCallingUserId()) {
            checkManageOrCreateUsersPermission("query isRestricted for user " + userId);
        }
        synchronized (mUsersLock) {
            return getUserInfoLU(UserHandle.getCallingUserId()).isRestricted();
            final UserInfo userInfo = getUserInfoLU(userId);
            return userInfo == null ? false : userInfo.isRestricted();
        }
    }

@@ -1682,15 +1687,14 @@ public class UserManagerService extends IUserManager.Stub {
    }

    @Override
    public boolean hasRestrictedProfiles() {
    public boolean hasRestrictedProfiles(@UserIdInt int userId) {
        checkManageUsersPermission("hasRestrictedProfiles");
        final int callingUserId = UserHandle.getCallingUserId();
        synchronized (mUsersLock) {
            final int userSize = mUsers.size();
            for (int i = 0; i < userSize; i++) {
                UserInfo profile = mUsers.valueAt(i).info;
                if (callingUserId != profile.id
                        && profile.restrictedProfileParentId == callingUserId) {
                if (userId != profile.id
                        && profile.restrictedProfileParentId == userId) {
                    return true;
                }
            }
@@ -2541,6 +2545,14 @@ public class UserManagerService extends IUserManager.Stub {
     */
    private static final boolean hasManageUsersPermission() {
        final int callingUid = Binder.getCallingUid();
        return hasManageUsersPermission(callingUid);
    }

    /**
     * @return whether the given UID is system UID or root's UID or the has the permission
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
     */
    private static boolean hasManageUsersPermission(int callingUid) {
        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
                || callingUid == Process.ROOT_UID
                || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid);
@@ -2552,9 +2564,7 @@ public class UserManagerService extends IUserManager.Stub {
     */
    private static final boolean hasManageUsersOrPermission(String alternativePermission) {
        final int callingUid = Binder.getCallingUid();
        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
                || callingUid == Process.ROOT_UID
                || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)
        return hasManageUsersPermission(callingUid)
                || hasPermissionGranted(alternativePermission, callingUid);
    }

@@ -4939,39 +4949,39 @@ public class UserManagerService extends IUserManager.Stub {
    }

    @Override
    public String getSeedAccountName() throws RemoteException {
    public String getSeedAccountName(@UserIdInt int userId) throws RemoteException {
        checkManageUsersPermission("Cannot get seed account information");
        synchronized (mUsersLock) {
            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
            return userData.seedAccountName;
            final UserData userData = getUserDataLU(userId);
            return userData == null ? null : userData.seedAccountName;
        }
    }

    @Override
    public String getSeedAccountType() throws RemoteException {
    public String getSeedAccountType(@UserIdInt int userId) throws RemoteException {
        checkManageUsersPermission("Cannot get seed account information");
        synchronized (mUsersLock) {
            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
            return userData.seedAccountType;
            final UserData userData = getUserDataLU(userId);
            return userData == null ? null : userData.seedAccountType;
        }
    }

    @Override
    public PersistableBundle getSeedAccountOptions() throws RemoteException {
    public PersistableBundle getSeedAccountOptions(@UserIdInt int userId) throws RemoteException {
        checkManageUsersPermission("Cannot get seed account information");
        synchronized (mUsersLock) {
            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
            return userData.seedAccountOptions;
            final UserData userData = getUserDataLU(userId);
            return userData == null ? null : userData.seedAccountOptions;
        }
    }

    @Override
    public void clearSeedAccountData() throws RemoteException {
    public void clearSeedAccountData(@UserIdInt int userId) throws RemoteException {
        checkManageUsersPermission("Cannot clear seed account information");
        synchronized (mPackagesLock) {
            UserData userData;
            synchronized (mUsersLock) {
                userData = getUserDataLU(UserHandle.getCallingUserId());
                userData = getUserDataLU(userId);
                if (userData == null) return;
                userData.clearSeedAccountData();
            }