diff options
| -rw-r--r-- | services/core/java/com/android/server/am/UserController.java | 7 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/am/UserControllerTest.java | 82 |
2 files changed, 89 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c020a9ff1c27..c2613bc47eb2 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -993,6 +993,13 @@ class UserController implements Handler.Callback { if (isCurrentUserLU(userId)) { return USER_OP_IS_CURRENT; } + // TODO(b/324647580): Refactor the idea of "force" and clean up. In the meantime... + final int parentId = mUserProfileGroupIds.get(userId, UserInfo.NO_PROFILE_GROUP_ID); + if (parentId != UserInfo.NO_PROFILE_GROUP_ID && parentId != userId) { + if ((UserHandle.USER_SYSTEM == parentId || isCurrentUserLU(parentId)) && !force) { + return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP; + } + } TimingsTraceAndSlog t = new TimingsTraceAndSlog(); int[] usersToStop = getUsersToStopLU(userId); // If one of related users is system or current, no related users should be stopped diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 643dcec27bfd..0a2a855e9317 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -123,6 +123,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -678,6 +679,87 @@ public class UserControllerTest { } /** + * Test that, when exceeding the maximum number of running users, a profile of the current user + * is not stopped. + */ + @Test + public void testStoppingExcessRunningUsersAfterSwitch_currentProfileNotStopped() + throws Exception { + mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, + /* maxRunningUsers= */ 5, /* delayUserDataLocking= */ false); + + final int PARENT_ID = 200; + final int PROFILE1_ID = 201; + final int PROFILE2_ID = 202; + final int FG_USER_ID = 300; + final int BG_USER_ID = 400; + + setUpUser(PARENT_ID, 0).profileGroupId = PARENT_ID; + setUpUser(PROFILE1_ID, UserInfo.FLAG_PROFILE).profileGroupId = PARENT_ID; + setUpUser(PROFILE2_ID, UserInfo.FLAG_PROFILE).profileGroupId = PARENT_ID; + setUpUser(FG_USER_ID, 0).profileGroupId = FG_USER_ID; + setUpUser(BG_USER_ID, 0).profileGroupId = UserInfo.NO_PROFILE_GROUP_ID; + mUserController.onSystemReady(); // To set the profileGroupIds in UserController. + + assertEquals(newHashSet( + SYSTEM_USER_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + + int numberOfUserSwitches = 1; + addForegroundUserAndContinueUserSwitch(PARENT_ID, UserHandle.USER_SYSTEM, + numberOfUserSwitches, false); + mUserController.finishUserSwitch(mUserStates.get(PARENT_ID)); + waitForHandlerToComplete(mInjector.mHandler, HANDLER_WAIT_TIME_MS); + assertTrue(mUserController.canStartMoreUsers()); + assertEquals(newHashSet( + SYSTEM_USER_ID, PARENT_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + + assertThat(mUserController.startProfile(PROFILE1_ID, true, null)).isTrue(); + assertEquals(newHashSet( + SYSTEM_USER_ID, PROFILE1_ID, PARENT_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + + numberOfUserSwitches++; + addForegroundUserAndContinueUserSwitch(FG_USER_ID, PARENT_ID, + numberOfUserSwitches, false); + mUserController.finishUserSwitch(mUserStates.get(FG_USER_ID)); + waitForHandlerToComplete(mInjector.mHandler, HANDLER_WAIT_TIME_MS); + assertTrue(mUserController.canStartMoreUsers()); + assertEquals(newHashSet( + SYSTEM_USER_ID, PROFILE1_ID, PARENT_ID, FG_USER_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + + mUserController.startUser(BG_USER_ID, USER_START_MODE_BACKGROUND); + assertEquals(newHashSet( + SYSTEM_USER_ID, PROFILE1_ID, PARENT_ID, BG_USER_ID, FG_USER_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + + // Now we exceed the maxRunningUsers parameter (of 5): + assertThat(mUserController.startProfile(PROFILE2_ID, true, null)).isTrue(); + // Currently, starting a profile doesn't trigger evaluating whether we've exceeded max, so + // we expect no users to be stopped. This policy may change in the future. Log but no fail. + if (!newHashSet(SYSTEM_USER_ID, PROFILE1_ID, BG_USER_ID, PROFILE2_ID, PARENT_ID, FG_USER_ID) + .equals(new HashSet<>(mUserController.getRunningUsersLU()))) { + Log.w(TAG, "Starting a profile that exceeded max running users didn't lead to " + + "expectations: " + mUserController.getRunningUsersLU()); + } + + numberOfUserSwitches++; + addForegroundUserAndContinueUserSwitch(PARENT_ID, FG_USER_ID, + numberOfUserSwitches, false); + mUserController.finishUserSwitch(mUserStates.get(PARENT_ID)); + waitForHandlerToComplete(mInjector.mHandler, HANDLER_WAIT_TIME_MS); + // We've now done a user switch and should notice that we've exceeded the maximum number of + // users. The oldest background user should be stopped (BG_USER); even though PROFILE1 was + // older, it should not be stopped since it's a profile of the (new) current user. + assertFalse(mUserController.canStartMoreUsers()); + assertEquals(newHashSet( + SYSTEM_USER_ID, PROFILE1_ID, PROFILE2_ID, FG_USER_ID, PARENT_ID), + new HashSet<>(mUserController.getRunningUsersLU())); + } + + /** * Test that, in getRunningUsersLU, parents come after their profile, even if the profile was * started afterwards. */ |