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

Commit f8a6722a authored by Oli Lan's avatar Oli Lan
Browse files

Add isMainUser system API.

This adds an API to determine if the context user is the designated
main user on the device. This user may have access to features which
are limited to a single user on the device.

In Android U, this will be the first user to go through setup.

On regular devices, this will be the system user, but on devices in
No Primary User / Headless System User Mode, it will be a different
user.

The isPrimaryUser System API is confusing because it actually always
returns the system user, even in headless mode. That API is deprecated
in this change.

On devices that are upgrading, if they are non-headless, the system user
will be the main user. If they are headless, the full user with the
earliest creation date will be given the flag.

Bug: 256624031
Test: atest UserManagerTest
Change-Id: Ib36f3b372f9bf33cbb097c4af63eb43515ac835b
parent 4469363d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -9968,9 +9968,10 @@ package android.os {
    method public boolean isCloneProfile();
    method public boolean isCredentialSharableWithParent();
    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.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isMainUser();
    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 public boolean isMediaSharedWithParent();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
    method public static boolean isRemoveResultSuccessful(int);
    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);
+2 −0
Original line number Diff line number Diff line
@@ -904,6 +904,7 @@ package android.content.pm {
    method public boolean isFull();
    method public boolean isGuest();
    method public boolean isInitialized();
    method public boolean isMain();
    method public boolean isManagedProfile();
    method public boolean isPrimary();
    method public boolean isProfile();
@@ -922,6 +923,7 @@ package android.content.pm {
    field public static final int FLAG_FULL = 1024; // 0x400
    field @Deprecated public static final int FLAG_GUEST = 4; // 0x4
    field public static final int FLAG_INITIALIZED = 16; // 0x10
    field public static final int FLAG_MAIN = 16384; // 0x4000
    field @Deprecated public static final int FLAG_MANAGED_PROFILE = 32; // 0x20
    field public static final int FLAG_PRIMARY = 1; // 0x1
    field public static final int FLAG_PROFILE = 4096; // 0x1000
+21 −1
Original line number Diff line number Diff line
@@ -158,6 +158,18 @@ public class UserInfo implements Parcelable {
     */
    public static final int FLAG_EPHEMERAL_ON_CREATE = 0x00002000;

    /**
     * Indicates that this user is the designated main user on the device. This user may have access
     * to certain features which are limited to at most one user.
     *
     * <p>Currently, this will be the first user to go through setup on the device, but in future
     * releases this status may be transferable or may even not be given to any users.
     *
     * <p>This is not necessarily the system user. For example, it will not be the system user on
     * devices for which {@link UserManager#isHeadlessSystemUserMode()} returns true.
     */
    public static final int FLAG_MAIN = 0x00004000;

    /**
     * @hide
     */
@@ -175,7 +187,8 @@ public class UserInfo implements Parcelable {
            FLAG_FULL,
            FLAG_SYSTEM,
            FLAG_PROFILE,
            FLAG_EPHEMERAL_ON_CREATE
            FLAG_EPHEMERAL_ON_CREATE,
            FLAG_MAIN
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface UserInfoFlag {
@@ -368,6 +381,13 @@ public class UserInfo implements Parcelable {
        return (flags & FLAG_FULL) == FLAG_FULL;
    }

    /**
     * @see #FLAG_MAIN
     */
    public boolean isMain() {
        return (flags & FLAG_MAIN) == FLAG_MAIN;
    }

    /**
     * Returns true if the user is a split system user.
     * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
+31 −2
Original line number Diff line number Diff line
@@ -2306,12 +2306,18 @@ public class UserManager {
    }

    /**
     * Used to check if the context user is the primary user. The primary user
     * is the first human user on a device. This is not supported in headless system user mode.
     * Used to check if the context user is the primary user. The primary user is the first human
     * user on a device. This is not supported in headless system user mode.
     *
     * @return whether the context user is the primary user.
     *
     * @deprecated This method always returns true for the system user, who may not be a full user
     * if {@link #isHeadlessSystemUserMode} is true. Use {@link #isSystemUser}, {@link #isAdminUser}
     * or {@link #isMainUser} instead.
     *
     * @hide
     */
    @Deprecated
    @SystemApi
    @RequiresPermission(anyOf = {
            Manifest.permission.MANAGE_USERS,
@@ -2335,6 +2341,29 @@ public class UserManager {
        return getContextUserIfAppropriate() == UserHandle.USER_SYSTEM;
    }

    /**
     * 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.
     *
     * <p>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.
     *
     * <p>Note that this will be the not be the system user on devices for which
     * {@link #isHeadlessSystemUserMode()} returns true.
     * @hide
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            Manifest.permission.MANAGE_USERS,
            Manifest.permission.CREATE_USERS,
            Manifest.permission.QUERY_USERS})
    @UserHandleAware
    public boolean isMainUser() {
        final UserInfo user = getUserInfo(mUserId);
        return user != null && user.isMain();
    }

    /**
     * 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,
+33 −1
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ public class UserManagerService extends IUserManager.Stub {
    @VisibleForTesting
    static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;

    private static final int USER_VERSION = 10;
    private static final int USER_VERSION = 11;

    private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms

@@ -3330,6 +3330,7 @@ public class UserManagerService extends IUserManager.Stub {
                final int oldFlags = systemUserData.info.flags;
                final int newFlags;
                final String newUserType;
                // TODO(b/256624031): Also handle FLAG_MAIN
                if (newHeadlessSystemUserMode) {
                    newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
                    newFlags = oldFlags & ~UserInfo.FLAG_FULL;
@@ -3622,6 +3623,22 @@ public class UserManagerService extends IUserManager.Stub {
            userVersion = 10;
        }

        if (userVersion < 11) {
            // Add FLAG_MAIN
            if (isHeadlessSystemUserMode()) {
                final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
                earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
                userIdsToWrite.add(earliestCreatedUser.id);
            } else {
                synchronized (mUsersLock) {
                    final UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
                    userData.info.flags |= UserInfo.FLAG_MAIN;
                    userIdsToWrite.add(userData.info.id);
                }
            }
            userVersion = 11;
        }

        // Reminder: If you add another upgrade, make sure to increment USER_VERSION too.

        // Done with userVersion changes, moving on to deal with userTypeVersion upgrades
@@ -3751,6 +3768,21 @@ public class UserManagerService extends IUserManager.Stub {
        userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
    }

    private UserInfo getEarliestCreatedFullUser() {
        final List<UserInfo> users = getUsersInternal(true, true, true);
        UserInfo earliestUser = users.get(0);
        long earliestCreationTime = earliestUser.creationTime;
        for (int i = 0; i < users.size(); i++) {
            final UserInfo info = users.get(i);
            if (info.isFull() && info.creationTime > 0
                    && info.creationTime < earliestCreationTime) {
                earliestCreationTime = info.creationTime;
                earliestUser = info;
            }
        }
        return earliestUser;
    }

    @GuardedBy({"mPackagesLock"})
    private void fallbackToSingleUserLP() {
        int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN
Loading