From 7d38aca0a7007c5401c95f791bfa89961b0e3763 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Fri, 18 Nov 2022 18:28:20 +0000 Subject: [PATCH] Add a system API to get the main user. This adds a system API to get the designated main user on the device. The documentation for the existing isMainUser API is updated to make clear that a main user might not exist on the device, particular for non-phone/tablet form factors, but there will always be at most one main user. The CTS tests for isMainUser are updated to reflect that documentation, and to no longer enforce that the main user is the first user on the device Bug: 259476886 Bug: 256624031 Test: atest UserManagerTest Change-Id: Id1739b188d7c1c0f9006bc473de35a88d09cad95 --- core/api/system-current.txt | 1 + core/java/android/os/IUserManager.aidl | 1 + core/java/android/os/UserManager.java | 37 ++++++++++++++++--- .../server/pm/UserManagerInternal.java | 8 ++++ .../android/server/pm/UserManagerService.java | 25 +++++++++++++ 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 802e61403fc39..8887686d5d40b 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10042,6 +10042,7 @@ package android.os { 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 public java.util.List getAllProfiles(); method @NonNull public java.util.List getEnabledProfiles(); + method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getMainUser(); 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); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index a887f2a6ef29d..eae7ce06008c7 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -58,6 +58,7 @@ interface IUserManager { void setUserIcon(int userId, in Bitmap icon); ParcelFileDescriptor getUserIcon(int userId); UserInfo getPrimaryUser(); + int getMainUserId(); List getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated); List getProfiles(int userId, boolean enabledOnly); int[] getProfileIds(int userId, boolean enabledOnly); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1f21bfe6cd729..954d1fca4ce07 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2377,14 +2377,16 @@ public class UserManager { } /** - * Returns true if the context user is the designated "main user" of the device. This user may - * have access to certain features which are limited to at most one user. + * Returns {@code true} if the context user is the designated "main user" of the device. This + * user may have access to certain features which are limited to at most one user. There will + * never be more than one main user on a device. * - *

Currently, the first human user on the device will be the main user; in the future, the - * concept may be transferable, so a different user (or even no user at all) may be designated - * the main user instead. + *

Currently, on most form factors the first human user on the device will be the main user; + * in the future, the concept may be transferable, so a different user (or even no user at all) + * may be designated the main user instead. On other form factors there might not be a main + * user. * - *

Note that this will be the not be the system user on devices for which + *

Note that this will not be the system user on devices for which * {@link #isHeadlessSystemUserMode()} returns true. * @hide */ @@ -2399,6 +2401,29 @@ public class UserManager { return user != null && user.isMain(); } + /** + * Returns the designated "main user" of the device, or {@code null} if there is no main user. + * + * @see #isMainUser() + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS, + Manifest.permission.QUERY_USERS}) + public @Nullable UserHandle getMainUser() { + try { + final int mainUserId = mService.getMainUserId(); + if (mainUserId == UserHandle.USER_NULL) { + return null; + } + return UserHandle.of(mainUserId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Used to check if the context user is an admin user. An admin user is allowed to * modify or configure certain settings that aren't available to non-admin users, diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 1027f4c031277..df132a97418a0 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -441,4 +441,12 @@ public abstract class UserManagerInternal { /** Return the integer types of the given user IDs. Only used for reporting metrics to statsd. */ public abstract int[] getUserTypesForStatsd(@UserIdInt int[] userIds); + + /** + * Returns the user id of the main user, or {@link android.os.UserHandle#USER_NULL} if there is + * no main user. + * + * @see UserManager#isMainUser() + */ + public abstract @UserIdInt int getMainUserId(); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 88e12fa9a6045..c8dffedfd1419 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -901,6 +901,25 @@ public class UserManagerService extends IUserManager.Stub { return null; } + @Override + public @UserIdInt int getMainUserId() { + checkQueryOrCreateUsersPermission("get main user id"); + return getMainUserIdUnchecked(); + } + + private @UserIdInt int getMainUserIdUnchecked() { + synchronized (mUsersLock) { + final int userSize = mUsers.size(); + for (int i = 0; i < userSize; i++) { + final UserInfo user = mUsers.valueAt(i).info; + if (user.isMain() && !mRemovingUserIds.get(user.id)) { + return user.id; + } + } + } + return UserHandle.USER_NULL; + } + public @NonNull List getUsers(boolean excludeDying) { return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */ true); @@ -6898,6 +6917,12 @@ public class UserManagerService extends IUserManager.Stub { } return userTypes; } + + @Override + public @UserIdInt int getMainUserId() { + return getMainUserIdUnchecked(); + } + } // class LocalService