Loading core/java/android/os/UserManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -2301,6 +2301,12 @@ public class UserManager { */ public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 3; /** * Indicates that user cannot logout because logout is not supported on the device. * @hide */ public static final int LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED = 4; /** * Result returned in {@link #getUserLogoutability()} indicating user logoutability. * @hide Loading @@ -2310,7 +2316,8 @@ public class UserManager { LOGOUTABILITY_STATUS_OK, LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER, LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO, LOGOUTABILITY_STATUS_CANNOT_SWITCH LOGOUTABILITY_STATUS_CANNOT_SWITCH, LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED }) public @interface UserLogoutability {} Loading Loading @@ -2807,6 +2814,7 @@ public class UserManager { * {@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 */ @RequiresPermission(Manifest.permission.MANAGE_USERS) Loading services/core/java/com/android/server/am/UserController.java +37 −8 Original line number Diff line number Diff line Loading @@ -286,6 +286,12 @@ class UserController implements Handler.Callback { @GuardedBy("mLock") private final SparseArray<UserState> mStartedUsers = new SparseArray<>(); // If logging out of a user cannot be immediately done, because we are in the process of // 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; /** * LRU list of history of running users, in order of when we last needed to start them. * Loading Loading @@ -987,27 +993,40 @@ class UserController implements Handler.Callback { * <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. */ boolean logoutUser(@UserIdInt int userId) { // TODO(b/380125011): To handle the edge case of trying to logout the user that the device // is in the process of switching to (i.e. userId == mTargetUserId), we had to logout to the // 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. if (mInjector.isHeadlessSystemUserMode() && !mInjector.getUserManager().canSwitchToHeadlessSystemUser()) { throw new UnsupportedOperationException("device does not support logoutUser"); } boolean shouldSwitchUser = false; synchronized (mLock) { if (userId == UserHandle.USER_SYSTEM) { Slogf.e(TAG, "Cannot logout system user %d", userId); return false; } if (userId == mTargetUserId) { // TODO(b/380125011): Properly handle this case, rather than returning failure. Slogf.e(TAG, "Cannot logout user %d as we're in the process of switching to it, and" + " therefore logout has failed.", userId); return false; } // Since we are logging out of userId, let's not switch to userId (after possible // ongoing user switch). 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," + " 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; } Loading Loading @@ -1036,7 +1055,8 @@ class UserController implements Handler.Callback { } // Now, userId is not current, so we can simply stop it. Attempting to stop system user // will fail. final int result = stopUser(userId, false, null, null); final int result = stopUser(userId, /* allowDelayedLocking= */ false, /* stopUserCallback= */ null, /* keyEvictedCallback */ null); if (result != USER_OP_SUCCESS) { Slogf.e(TAG, "Cannot logout user %d; stop user failed with result %d", userId, result); return false; Loading Loading @@ -2435,14 +2455,22 @@ class UserController implements Handler.Callback { mInjector.setPerformancePowerMode(false); } final int nextUserId; final int stopUserId; synchronized (mLock) { nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL); nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), mPendingLogoutTargetUser ? UserHandle.USER_SYSTEM : UserHandle.USER_NULL); stopUserId = mPendingLogoutTargetUser ? mTargetUserId : UserHandle.USER_NULL; mPendingLogoutTargetUser = false; mTargetUserId = UserHandle.USER_NULL; ActivityManager.invalidateGetCurrentUserIdCache(); } if (nextUserId != UserHandle.USER_NULL) { switchUser(nextUserId); } if (stopUserId != UserHandle.USER_NULL) { stopUser(stopUserId, /* allowDelayedLocking= */ false, /* stopUserCallback= */ null, /* keyEvictedCallback= */ null); } } private void dispatchLockedBootComplete(@UserIdInt int userId) { Loading Loading @@ -3588,6 +3616,7 @@ class UserController implements Handler.Callback { pw.println(" mCurrentProfileIds:" + Arrays.toString(mCurrentProfileIds)); pw.println(" mCurrentUserId:" + mCurrentUserId); pw.println(" mTargetUserId:" + mTargetUserId); pw.println(" mPendingLogoutTargetUser:" + mPendingLogoutTargetUser); pw.println(" mLastActiveUsersForDelayedLocking:" + mLastActiveUsersForDelayedLocking); pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking); pw.println(" mAllowUserUnlocking:" + mAllowUserUnlocking); Loading services/core/java/com/android/server/pm/UserManagerService.java +4 −7 Original line number Diff line number Diff line Loading @@ -3052,15 +3052,12 @@ public class UserManagerService extends IUserManager.Stub { checkManageUsersPermission("getUserLogoutability"); if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; if (isHeadlessSystemUserMode() && !canSwitchToHeadlessSystemUser()) { return UserManager.LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED; } if (userId != getCurrentUserId()) { // TODO(b/393656514): Decide what to do with non-current/background users. // As of now, we are not going to logout a background user. A background user should // simply be stopped instead. return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; } if (getUserSwitchability(userId) != UserManager.SWITCHABILITY_STATUS_OK) { Loading services/tests/mockingservicestests/src/com/android/server/am/UserControllerMockedTest.java +24 −5 Original line number Diff line number Diff line Loading @@ -78,6 +78,8 @@ public final class UserControllerMockedTest { @Test public void testLogoutUser_HsumAndInteractiveUser0_CanLogoutCurrentUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(TEST_USER_1); when(mUserManagerInternal.getUserToLogoutCurrentUserTo()) .thenReturn(UserHandle.USER_SYSTEM); Loading @@ -85,33 +87,41 @@ public final class UserControllerMockedTest { boolean result = mSpiedUserController.logoutUser(TEST_USER_1); assertThat(result).isTrue(); verify(mSpiedUserController).switchUser(anyInt()); verify(mSpiedUserController).switchUser(UserHandle.USER_SYSTEM); verify(mSpiedUserController).stopUser(TEST_USER_1, false, null, null); } @Test public void testLogoutUser_NonHsumOrNonInteractiveUser0_CanLogoutCurrentUser() { public void testLogoutUser_NonHsum_CanLogoutCurrentUser() { mockSystemUserHeadlessMode(false); mockCurrentUser(TEST_USER_1); when(mUserManagerInternal.getUserToLogoutCurrentUserTo()).thenReturn(TEST_USER_2); boolean result = mSpiedUserController.logoutUser(TEST_USER_1); assertThat(result).isTrue(); verify(mSpiedUserController).switchUser(anyInt()); verify(mSpiedUserController).switchUser(TEST_USER_2); verify(mSpiedUserController).stopUser(TEST_USER_1, false, null, null); } @Test public void testLogoutUser_LogoutNonCurrentUser_NoSwitchUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(TEST_USER_1); boolean result = mSpiedUserController.logoutUser(TEST_USER_2); assertThat(result).isTrue(); // Logout of non-current user does not need switch user. verify(mSpiedUserController, never()).switchUser(anyInt()); // Logout of non-current user does not need switch user, but only stop user. verify(mSpiedUserController, never()).switchUser(UserHandle.USER_SYSTEM); verify(mSpiedUserController).stopUser(TEST_USER_2, false, null, null); } @Test public void testLogoutUser_CannotLogoutSystemUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(UserHandle.USER_SYSTEM); boolean result = mSpiedUserController.logoutUser(UserHandle.USER_SYSTEM); Loading @@ -119,9 +129,18 @@ public final class UserControllerMockedTest { assertThat(result).isFalse(); // No switch user should have happened. verify(mSpiedUserController, never()).switchUser(anyInt()); verify(mSpiedUserController, never()).stopUser(UserHandle.USER_SYSTEM, false, null, null); } private void mockCurrentUser(@UserIdInt int userId) { when(mSpiedUserController.getCurrentUserId()).thenReturn(userId); } private void mockCanSwitchToHeadlessSystemUser(boolean canSwitch) { doReturn(canSwitch).when(mUserManagerService).canSwitchToHeadlessSystemUser(); } private void mockSystemUserHeadlessMode(boolean headless) { when(mSpiedUserControllerInjector.isHeadlessSystemUserMode()).thenReturn(headless); } } services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java +8 −4 Original line number Diff line number Diff line Loading @@ -964,7 +964,7 @@ public final class UserManagerServiceMockedTest { @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystem_UserCanLogout() public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystemUser_UserCanLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); Loading @@ -980,7 +980,7 @@ public final class UserManagerServiceMockedTest { @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystem_UserCannotLogout() public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystemUser_UserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(false); Loading @@ -990,13 +990,16 @@ public final class UserManagerServiceMockedTest { mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO); .isEqualTo(UserManager.LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED); } @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_Hsum_SystemUserCannotLogout() throws Exception { public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystemUser_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat(mUms.getUserLogoutability(UserHandle.USER_SYSTEM)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); Loading @@ -1016,6 +1019,7 @@ public final class UserManagerServiceMockedTest { @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_CannotSwitch_CannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(true); addUser(USER_ID); addUser(OTHER_USER_ID); setLastForegroundTime(OTHER_USER_ID, 1_000_000L); Loading Loading
core/java/android/os/UserManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -2301,6 +2301,12 @@ public class UserManager { */ public static final int LOGOUTABILITY_STATUS_CANNOT_SWITCH = 3; /** * Indicates that user cannot logout because logout is not supported on the device. * @hide */ public static final int LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED = 4; /** * Result returned in {@link #getUserLogoutability()} indicating user logoutability. * @hide Loading @@ -2310,7 +2316,8 @@ public class UserManager { LOGOUTABILITY_STATUS_OK, LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER, LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO, LOGOUTABILITY_STATUS_CANNOT_SWITCH LOGOUTABILITY_STATUS_CANNOT_SWITCH, LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED }) public @interface UserLogoutability {} Loading Loading @@ -2807,6 +2814,7 @@ public class UserManager { * {@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 */ @RequiresPermission(Manifest.permission.MANAGE_USERS) Loading
services/core/java/com/android/server/am/UserController.java +37 −8 Original line number Diff line number Diff line Loading @@ -286,6 +286,12 @@ class UserController implements Handler.Callback { @GuardedBy("mLock") private final SparseArray<UserState> mStartedUsers = new SparseArray<>(); // If logging out of a user cannot be immediately done, because we are in the process of // 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; /** * LRU list of history of running users, in order of when we last needed to start them. * Loading Loading @@ -987,27 +993,40 @@ class UserController implements Handler.Callback { * <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. */ boolean logoutUser(@UserIdInt int userId) { // TODO(b/380125011): To handle the edge case of trying to logout the user that the device // is in the process of switching to (i.e. userId == mTargetUserId), we had to logout to the // 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. if (mInjector.isHeadlessSystemUserMode() && !mInjector.getUserManager().canSwitchToHeadlessSystemUser()) { throw new UnsupportedOperationException("device does not support logoutUser"); } boolean shouldSwitchUser = false; synchronized (mLock) { if (userId == UserHandle.USER_SYSTEM) { Slogf.e(TAG, "Cannot logout system user %d", userId); return false; } if (userId == mTargetUserId) { // TODO(b/380125011): Properly handle this case, rather than returning failure. Slogf.e(TAG, "Cannot logout user %d as we're in the process of switching to it, and" + " therefore logout has failed.", userId); return false; } // Since we are logging out of userId, let's not switch to userId (after possible // ongoing user switch). 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," + " 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; } Loading Loading @@ -1036,7 +1055,8 @@ class UserController implements Handler.Callback { } // Now, userId is not current, so we can simply stop it. Attempting to stop system user // will fail. final int result = stopUser(userId, false, null, null); final int result = stopUser(userId, /* allowDelayedLocking= */ false, /* stopUserCallback= */ null, /* keyEvictedCallback */ null); if (result != USER_OP_SUCCESS) { Slogf.e(TAG, "Cannot logout user %d; stop user failed with result %d", userId, result); return false; Loading Loading @@ -2435,14 +2455,22 @@ class UserController implements Handler.Callback { mInjector.setPerformancePowerMode(false); } final int nextUserId; final int stopUserId; synchronized (mLock) { nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL); nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), mPendingLogoutTargetUser ? UserHandle.USER_SYSTEM : UserHandle.USER_NULL); stopUserId = mPendingLogoutTargetUser ? mTargetUserId : UserHandle.USER_NULL; mPendingLogoutTargetUser = false; mTargetUserId = UserHandle.USER_NULL; ActivityManager.invalidateGetCurrentUserIdCache(); } if (nextUserId != UserHandle.USER_NULL) { switchUser(nextUserId); } if (stopUserId != UserHandle.USER_NULL) { stopUser(stopUserId, /* allowDelayedLocking= */ false, /* stopUserCallback= */ null, /* keyEvictedCallback= */ null); } } private void dispatchLockedBootComplete(@UserIdInt int userId) { Loading Loading @@ -3588,6 +3616,7 @@ class UserController implements Handler.Callback { pw.println(" mCurrentProfileIds:" + Arrays.toString(mCurrentProfileIds)); pw.println(" mCurrentUserId:" + mCurrentUserId); pw.println(" mTargetUserId:" + mTargetUserId); pw.println(" mPendingLogoutTargetUser:" + mPendingLogoutTargetUser); pw.println(" mLastActiveUsersForDelayedLocking:" + mLastActiveUsersForDelayedLocking); pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking); pw.println(" mAllowUserUnlocking:" + mAllowUserUnlocking); Loading
services/core/java/com/android/server/pm/UserManagerService.java +4 −7 Original line number Diff line number Diff line Loading @@ -3052,15 +3052,12 @@ public class UserManagerService extends IUserManager.Stub { checkManageUsersPermission("getUserLogoutability"); if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; if (isHeadlessSystemUserMode() && !canSwitchToHeadlessSystemUser()) { return UserManager.LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED; } if (userId != getCurrentUserId()) { // TODO(b/393656514): Decide what to do with non-current/background users. // As of now, we are not going to logout a background user. A background user should // simply be stopped instead. return UserManager.LOGOUTABILITY_STATUS_CANNOT_SWITCH; if (userId == UserHandle.USER_SYSTEM) { return UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER; } if (getUserSwitchability(userId) != UserManager.SWITCHABILITY_STATUS_OK) { Loading
services/tests/mockingservicestests/src/com/android/server/am/UserControllerMockedTest.java +24 −5 Original line number Diff line number Diff line Loading @@ -78,6 +78,8 @@ public final class UserControllerMockedTest { @Test public void testLogoutUser_HsumAndInteractiveUser0_CanLogoutCurrentUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(TEST_USER_1); when(mUserManagerInternal.getUserToLogoutCurrentUserTo()) .thenReturn(UserHandle.USER_SYSTEM); Loading @@ -85,33 +87,41 @@ public final class UserControllerMockedTest { boolean result = mSpiedUserController.logoutUser(TEST_USER_1); assertThat(result).isTrue(); verify(mSpiedUserController).switchUser(anyInt()); verify(mSpiedUserController).switchUser(UserHandle.USER_SYSTEM); verify(mSpiedUserController).stopUser(TEST_USER_1, false, null, null); } @Test public void testLogoutUser_NonHsumOrNonInteractiveUser0_CanLogoutCurrentUser() { public void testLogoutUser_NonHsum_CanLogoutCurrentUser() { mockSystemUserHeadlessMode(false); mockCurrentUser(TEST_USER_1); when(mUserManagerInternal.getUserToLogoutCurrentUserTo()).thenReturn(TEST_USER_2); boolean result = mSpiedUserController.logoutUser(TEST_USER_1); assertThat(result).isTrue(); verify(mSpiedUserController).switchUser(anyInt()); verify(mSpiedUserController).switchUser(TEST_USER_2); verify(mSpiedUserController).stopUser(TEST_USER_1, false, null, null); } @Test public void testLogoutUser_LogoutNonCurrentUser_NoSwitchUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(TEST_USER_1); boolean result = mSpiedUserController.logoutUser(TEST_USER_2); assertThat(result).isTrue(); // Logout of non-current user does not need switch user. verify(mSpiedUserController, never()).switchUser(anyInt()); // Logout of non-current user does not need switch user, but only stop user. verify(mSpiedUserController, never()).switchUser(UserHandle.USER_SYSTEM); verify(mSpiedUserController).stopUser(TEST_USER_2, false, null, null); } @Test public void testLogoutUser_CannotLogoutSystemUser() { mockSystemUserHeadlessMode(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(UserHandle.USER_SYSTEM); boolean result = mSpiedUserController.logoutUser(UserHandle.USER_SYSTEM); Loading @@ -119,9 +129,18 @@ public final class UserControllerMockedTest { assertThat(result).isFalse(); // No switch user should have happened. verify(mSpiedUserController, never()).switchUser(anyInt()); verify(mSpiedUserController, never()).stopUser(UserHandle.USER_SYSTEM, false, null, null); } private void mockCurrentUser(@UserIdInt int userId) { when(mSpiedUserController.getCurrentUserId()).thenReturn(userId); } private void mockCanSwitchToHeadlessSystemUser(boolean canSwitch) { doReturn(canSwitch).when(mUserManagerService).canSwitchToHeadlessSystemUser(); } private void mockSystemUserHeadlessMode(boolean headless) { when(mSpiedUserControllerInjector.isHeadlessSystemUserMode()).thenReturn(headless); } }
services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java +8 −4 Original line number Diff line number Diff line Loading @@ -964,7 +964,7 @@ public final class UserManagerServiceMockedTest { @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystem_UserCanLogout() public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystemUser_UserCanLogout() throws Exception { setSystemUserHeadless(true); addUser(USER_ID); Loading @@ -980,7 +980,7 @@ public final class UserManagerServiceMockedTest { @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystem_UserCannotLogout() public void testGetUserLogoutability_HsumAndNonInteractiveHeadlessSystemUser_UserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(false); Loading @@ -990,13 +990,16 @@ public final class UserManagerServiceMockedTest { mockUserIsInCall(false); assertThat(mUms.getUserLogoutability(USER_ID)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_NO_SUITABLE_USER_TO_LOGOUT_TO); .isEqualTo(UserManager.LOGOUTABILITY_STATUS_DEVICE_NOT_SUPPORTED); } @Test @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_Hsum_SystemUserCannotLogout() throws Exception { public void testGetUserLogoutability_HsumAndInteractiveHeadlessSystemUser_SystemUserCannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(true); mockCurrentUser(UserHandle.USER_SYSTEM); assertThat(mUms.getUserLogoutability(UserHandle.USER_SYSTEM)) .isEqualTo(UserManager.LOGOUTABILITY_STATUS_CANNOT_LOGOUT_SYSTEM_USER); Loading @@ -1016,6 +1019,7 @@ public final class UserManagerServiceMockedTest { @EnableFlags(FLAG_LOGOUT_USER_API) public void testGetUserLogoutability_CannotSwitch_CannotLogout() throws Exception { setSystemUserHeadless(true); mockCanSwitchToHeadlessSystemUser(true); addUser(USER_ID); addUser(OTHER_USER_ID); setLastForegroundTime(OTHER_USER_ID, 1_000_000L); Loading