Loading core/java/android/app/ActivityManager.java +9 −9 Original line number Diff line number Diff line Loading @@ -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) Loading core/java/android/os/UserManager.java +2 −12 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 }) Loading Loading @@ -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 Loading services/core/java/com/android/server/am/UserController.java +12 −27 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading @@ -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"); Loading @@ -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) { Loading services/core/java/com/android/server/pm/UserManagerInternal.java +0 −8 Original line number Diff line number Diff line Loading @@ -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. Loading services/core/java/com/android/server/pm/UserManagerService.java +0 −29 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; } Loading Loading @@ -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 Loading
core/java/android/app/ActivityManager.java +9 −9 Original line number Diff line number Diff line Loading @@ -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) Loading
core/java/android/os/UserManager.java +2 −12 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 }) Loading Loading @@ -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 Loading
services/core/java/com/android/server/am/UserController.java +12 −27 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading @@ -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"); Loading @@ -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) { Loading
services/core/java/com/android/server/pm/UserManagerInternal.java +0 −8 Original line number Diff line number Diff line Loading @@ -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. Loading
services/core/java/com/android/server/pm/UserManagerService.java +0 −29 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; } Loading Loading @@ -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