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

Commit e8c6190e authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "logoutUser always switches to system user" into main

parents bf86ce66 b9ec140b
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -5333,20 +5333,20 @@ public class ActivityManager {

    /**
     * Logs out the specified user by stopping it. If that user is the foreground user, we first
     * switch to another appropriate user. The system will determine the next user to switch to
     * based on the device configuration:
     * switch to another appropriate user. The current implementation (which is subject to change)
     * depends on the device configuration, as follows:
     *
     * <ul>
     *   <li>On a device in headless system user mode (HSUM), if {@code
     *       config_canSwitchToHeadlessSystemUser} is {@code true}, the system will switch to the
     *       headless system user.
     *   <li>On other devices, the system will switch to an appropriate user, which is typically the
     *       previously active foreground user.
     *   <li>On a device that can switch to the system user, it will do so.
     *   <li>On a device that cannot switch to the system user, this method will fail since we are
     *       unable to logout the user.
     *   <li>Note that attempts to logout the system user will fail, since the system user cannot be
     *       stopped.
     * </ul>
     *
     * @param userId the user to logout.
     * @return true if logout is successfully initiated. Reason for failure could be that no
     *     suitable user can be found to switch to, or any underlying operations fails.
     * @return true if logout is successfully initiated. Reason for failure could be that logout
     *     does not support this type of device, or any underlying operations fails.
     * @hide
     */
    @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+2 −12
Original line number Diff line number Diff line
@@ -2287,25 +2287,17 @@ public class UserManager {
     */
    public static final int LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER = 1;

    /**
     * Indicates that user cannot logout because there is no suitable user to logout to. This is
     * generally applicable to Headless System User Mode devices that do not have an interactive
     * system user.
     * @hide
     */
    public static final int LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO = 2;

    /**
     * Indicates that user cannot logout because user switch cannot happen.
     * @hide
     */
    public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 3;
    public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 2;

    /**
     * Indicates that user cannot logout because logout is not supported on the device.
     * @hide
     */
    public static final int LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED = 4;
    public static final int LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED = 3;

    /**
     * Result returned in {@link #getUserLogoutability()} indicating user logoutability.
@@ -2315,7 +2307,6 @@ public class UserManager {
    @IntDef(flag = false, prefix = { "LOGOUTABILITY_STATUS_" }, value = {
            LOGOUTABILITY_STATUS_OK,
            LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER,
            LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO,
            LOGOUTABILITY_STATUS_CANNOT_SWITCH,
            LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED
    })
@@ -2812,7 +2803,6 @@ public class UserManager {
     * @return A {@link UserLogoutability} flag indicating if the user can logout,
     * one of {@link #LOGOUTABILITY_STATUS_OK},
     * {@link #LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER},
     * {@link #LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO},
     * {@link #LOGOUTABILITY_STATUS_CANNOT_SWITCH}.
     * {@link #LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED}.
     * @hide
+12 −27
Original line number Diff line number Diff line
@@ -290,7 +290,7 @@ class UserController implements Handler.Callback {
    // switching to that same user and cannot stop that user, then we flip this flag to true, so
    // that when the ongoing user-switch is finished, we would stop the user then.
    @GuardedBy("mLock")
    private boolean mPendingLogoutTargetUser = false;
    private boolean mPendingLogoutTargetUser;

    /**
     * LRU list of history of running users, in order of when we last needed to start them.
@@ -981,23 +981,23 @@ class UserController implements Handler.Callback {
     *
     * <ol>
     *   <li>If {@code userId} is the foreground user, first switching to an appropriate, active
     *       user.
     *       user. Currently it's always switching to the system user.
     *   <li>Stopping the specified {@code userId}.
     * </ol>
     *
     * <p>The logout operation will fail under the following conditions:
     *
     * <ul>
     *   <li>No suitable user can be found to switch to, when user switch is needed.
     *   <li>Trying to logout the system user.
     *   <li>Device cannot switch to the system user.
     *   <li>The user switch operation fails for any reason.
     *   <li>The stop user operation fails for any reason.
     * </ul>
     *
     * <p>The logoutUser API does not support HSUM devices that cannot switch to system user.
     *
     * @see ActivityManager#logoutUser(int)
     * @param userId The ID of the user to log out.
     * @return true if logout is successfully initiated.
     * @throws UnsupportedOperationException if device is in HSUM and cannot switch to system user.
     */
    boolean logoutUser(@UserIdInt int userId) {
        // TODO(b/380125011): To handle the edge case of trying to logout the user that the device
@@ -1005,6 +1005,8 @@ class UserController implements Handler.Callback {
        // system user (not the previous foreground user). Thus we cannot support HSUM devices
        // without interactive headless system user. To solve it for the long term, a refactor might
        // be needed, see more details in the bug.
        // TODO(b/411696141): Use the more proper API to check if headless system user is
        // interactive, once it's ready.
        if (mInjector.isHeadlessSystemUserMode()
                && !mInjector.getUserManager().canSwitchToHeadlessSystemUser()) {
            throw new UnsupportedOperationException("device does not support logoutUser");
@@ -1020,41 +1022,24 @@ class UserController implements Handler.Callback {
            mPendingTargetUserIds.removeIf(id -> id == userId);

            if (userId == mTargetUserId) {
                Slogf.i(TAG, "Cannot logout user %d now as we're in the process of switching to it,"
                Slogf.w(TAG, "Cannot logout user %d now as we're in the process of switching to it,"
                        + " it will be logged out when the ongoing user-switch is complete.",
                        userId);
                mPendingLogoutTargetUser = true;
                return true;
            }

            if (userId == getCurrentUserId() && mTargetUserId == UserHandle.USER_NULL) {
                shouldSwitchUser = true;
            }
        }

        if (shouldSwitchUser) {
            final int switchToUserId =
                    mInjector.getUserManagerInternal().getUserToLogoutCurrentUserTo();
            if (switchToUserId == UserHandle.USER_NULL) {
                Slogf.w(TAG, "Logout has no suitable user to switch to, to logout user %d.",
                        userId);
            if (!switchUser(UserHandle.USER_SYSTEM)) {
                Slogf.e(TAG, "Cannot logout user %d; switch to system user failed", userId);
                return false;
            }
            // Due to possible race condition, switchToUserId could be equal to userId. When this is
            // true:
            // 1. if they are the current user (due to race condition), then we cannot logout
            // userId, as we can't switch to another user.
            // 2. if they are not the current user, we simply need to stop this userId (without
            // switch user).
            if (switchToUserId != userId) {
                if (!switchUser(switchToUserId)) {
                    Slogf.e(TAG, "Cannot logout user %d; switch to user %d failed", userId,
                            switchToUserId);
                    return false;
                }
            }
        }
        // Now, userId is not current, so we can simply stop it. Attempting to stop system user
        // will fail.
        // Now, userId is not current, so we can simply stop it.
        final int result = stopUser(userId, /* allowDelayedLocking= */ false,
                /* stopUserCallback= */ null, /* keyEvictedCallback */ null);
        if (result != USER_OP_SUCCESS) {
+0 −8
Original line number Diff line number Diff line
@@ -537,14 +537,6 @@ public abstract class UserManagerInternal {
     */
    public abstract @UserIdInt int getUserAssignedToDisplay(int displayId);

    /**
     * Returns the user to switch to, when logging out current user. If in HSUM and has interactive
     * system user, then logout would switch to the system user. Otherwise, logout would switch to
     * the previous foreground user. Will return USER_NULL if the current user is the SYSTEM or if
     * no suitable user can be found.
     */
    public abstract @UserIdInt int getUserToLogoutCurrentUserTo();

    /**
     * Gets the user-friendly representation of the {@code result} of a
     * {@link #assignUserToDisplayOnStart(int, int, boolean, int)} call.
+0 −29
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_EMBEDDED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserManager.DEV_CREATE_OVERRIDE_PROPERTY;
import static android.os.UserManager.DISALLOW_USER_SWITCH;
@@ -1487,10 +1486,6 @@ public class UserManagerService extends IUserManager.Stub {
    @Override
    public @CanBeNULL @UserIdInt int getPreviousFullUserToEnterForeground() {
        checkQueryOrCreateUsersPermission("get previous user");
        return getPreviousFullUserToEnterForegroundUnchecked();
    }

    private int getPreviousFullUserToEnterForegroundUnchecked() {
        int previousUser = UserHandle.USER_NULL;
        long latestEnteredTime = 0;
        final int currentUser = getCurrentUserId();
@@ -3096,10 +3091,6 @@ public class UserManagerService extends IUserManager.Stub {
            return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH;
        }

        if (mLocalService.getUserToLogoutCurrentUserTo() == UserHandle.USER_NULL) {
            return UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO;
        }

        return UserManager.LOGOUTABILITY_STATUS_OK;
    }

@@ -8316,26 +8307,6 @@ public class UserManagerService extends IUserManager.Stub {
            return mUserVisibilityMediator.getUserAssignedToDisplay(displayId);
        }

        /**
         * Returns the ID of the user to switch to, when logging out the current user. If the
         * current user is the system user, it cannot be logged out, thus USER_NULL is returned.
         * For HSUM devices with interactive headless system user, logging out should switch to the
         * system user. Otherwise, we currently return the last foreground full user. Beware of
         * potential race condition, as the result of getCurrentUserId() can be changed by other
         * threads.
         */
        @Override
        public @CanBeNULL @UserIdInt int getUserToLogoutCurrentUserTo() {
            if (getCurrentUserId() == USER_SYSTEM) {
                return USER_NULL;
            }
            if (UserManagerService.this.isHeadlessSystemUserMode()
                    && UserManagerService.this.canSwitchToHeadlessSystemUser()) {
                return USER_SYSTEM;
            }
            return UserManagerService.this.getPreviousFullUserToEnterForegroundUnchecked();
        }

        @Override
        public void addUserVisibilityListener(UserVisibilityListener listener) {
            mUserVisibilityMediator.addListener(listener);
Loading