Loading services/core/java/com/android/server/pm/UserManagerService.java +3 −3 Original line number Diff line number Diff line Loading @@ -6835,13 +6835,13 @@ public class UserManagerService extends IUserManager.Stub { @Override public int assignUserToDisplayOnStart(@UserIdInt int userId, @UserIdInt int profileGroupId, boolean foreground, int displayId) { return mUserVisibilityMediator.startUser(userId, profileGroupId, foreground, displayId); return mUserVisibilityMediator.assignUserToDisplayOnStart(userId, profileGroupId, foreground, displayId); } @Override public void unassignUserFromDisplayOnStop(@UserIdInt int userId) { mUserVisibilityMediator.stopUser(userId); mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId); } @Override Loading services/core/java/com/android/server/pm/UserVisibilityMediator.java +29 −26 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.server.pm.UserManagerInternal.UserAssignmentResult; import com.android.server.utils.Slogf; Loading Loading @@ -121,8 +122,10 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#assignUserToDisplayOnStart(int, int, boolean, int)}. */ public @UserAssignmentResult int startUser(@UserIdInt int userId, public @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId, @UserIdInt int unResolvedProfileGroupId, boolean foreground, int displayId) { Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d", userId); // This method needs to perform 4 actions: // // 1. Check if the user can be started given the provided arguments Loading @@ -139,7 +142,7 @@ public final class UserVisibilityMediator implements Dumpable { ? userId : unResolvedProfileGroupId; if (DBG) { Slogf.d(TAG, "startUser(%d, %d, %b, %d): actualProfileGroupId=%d", Slogf.d(TAG, "assignUserToDisplayOnStart(%d, %d, %b, %d): actualProfileGroupId=%d", userId, unResolvedProfileGroupId, foreground, displayId, profileGroupId); } Loading Loading @@ -181,11 +184,11 @@ public final class UserVisibilityMediator implements Dumpable { // Don't need to do set state because methods (such as isUserVisible()) // already know that the current user (and their profiles) is assigned to // the default display. Slogf.d(TAG, "Don't need to update mUsersOnSecondaryDisplays"); Slogf.d(TAG, "don't need to update mUsersOnSecondaryDisplays"); } break; default: Slogf.wtf(TAG, "Invalid resut from canAssignUserToDisplayLocked: %d", Slogf.wtf(TAG, "invalid resut from canAssignUserToDisplayLocked: %d", mappingResult); } } Loading Loading @@ -313,9 +316,9 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}. */ public void stopUser(int userId) { public void unassignUserFromDisplayOnStop(int userId) { if (DBG) { Slogf.d(TAG, "stopUser(%d)", userId); Slogf.d(TAG, "unassignUserFromDisplayOnStop(%d)", userId); } synchronized (mLock) { if (DBG) { Loading @@ -341,7 +344,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#isUserVisible(int)}. */ public boolean isUserVisible(int userId) { public boolean isUserVisible(@UserIdInt int userId) { // First check current foreground user and their profiles (on main display) if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { return true; Loading @@ -361,7 +364,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#isUserVisible(int, int)}. */ public boolean isUserVisible(int userId, int displayId) { public boolean isUserVisible(@UserIdInt int userId, int displayId) { if (displayId == Display.INVALID_DISPLAY) { return false; } Loading Loading @@ -410,7 +413,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#getDisplayAssignedToUser(int)}. */ public int getDisplayAssignedToUser(int userId) { public int getDisplayAssignedToUser(@UserIdInt int userId) { if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { return Display.DEFAULT_DISPLAY; } Loading @@ -427,7 +430,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#getUserAssignedToDisplay(int)}. */ public int getUserAssignedToDisplay(int displayId) { public int getUserAssignedToDisplay(@UserIdInt int displayId) { if (displayId == Display.DEFAULT_DISPLAY || !mUsersOnSecondaryDisplaysEnabled) { return getCurrentUserId(); } Loading Loading @@ -506,6 +509,18 @@ public final class UserVisibilityMediator implements Dumpable { dump(new IndentingPrintWriter(pw)); } private static boolean isSpecialUserId(@UserIdInt int userId) { switch (userId) { case UserHandle.USER_ALL: case UserHandle.USER_CURRENT: case UserHandle.USER_CURRENT_OR_SELF: case UserHandle.USER_NULL: return true; default: return false; } } private static boolean isProfile(@UserIdInt int userId, @UserIdInt int profileGroupId) { return profileGroupId != NO_PROFILE_GROUP_ID && profileGroupId != userId; } Loading @@ -514,15 +529,13 @@ public final class UserVisibilityMediator implements Dumpable { // state to decide whether a user is visible or not. If we decide to always store that info into // mUsersOnSecondaryDisplays, we should remove them. @VisibleForTesting @UserIdInt int getCurrentUserId() { private @UserIdInt int getCurrentUserId() { synchronized (mLock) { return mCurrentUserId; } } @VisibleForTesting boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) { private boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) { synchronized (mLock) { // Special case as NO_PROFILE_GROUP_ID == USER_NULL if (userId == USER_NULL || mCurrentUserId == USER_NULL) { Loading @@ -535,16 +548,7 @@ public final class UserVisibilityMediator implements Dumpable { } } @VisibleForTesting boolean isStartedUser(@UserIdInt int userId) { synchronized (mLock) { return mStartedProfileGroupIds.get(userId, INITIAL_CURRENT_USER_ID) != INITIAL_CURRENT_USER_ID; } } @VisibleForTesting boolean isStartedProfile(@UserIdInt int userId) { private boolean isStartedProfile(@UserIdInt int userId) { int profileGroupId; synchronized (mLock) { profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); Loading @@ -552,8 +556,7 @@ public final class UserVisibilityMediator implements Dumpable { return isProfile(userId, profileGroupId); } @VisibleForTesting @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { synchronized (mLock) { return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } Loading services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java +18 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,13 @@ import android.util.Log; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.google.common.truth.Expect; import com.google.common.truth.StandardSubjectBuilder; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.RuleChain; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; Loading @@ -39,8 +43,13 @@ public abstract class ExtendedMockitoTestCase { private MockitoSession mSession; private final Expect mExpect = Expect.create(); protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); @Rule public final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); public final RuleChain mTwoRingsOfPowerAndOneChainToRuleThemAll = RuleChain .outerRule(mDumpableDumperRule) .around(mExpect); @Before public void startSession() { Loading Loading @@ -82,4 +91,12 @@ public abstract class ExtendedMockitoTestCase { mSession.finishMocking(); } } protected final StandardSubjectBuilder expectWithMessage(String msg) { return mExpect.withMessage(msg); } protected final StandardSubjectBuilder expectWithMessage(String format, Object...args) { return mExpect.withMessage(format, args); } } services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java +50 −156 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.server.pm; import static android.os.UserHandle.USER_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; Loading @@ -23,8 +22,6 @@ import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_F import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; import static com.google.common.truth.Truth.assertWithMessage; import org.junit.Test; /** Loading @@ -41,196 +38,93 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator } @Test public void testStartUser_systemUser() { int result = mMediator.startUser(USER_SYSTEM, USER_SYSTEM, FG, SECONDARY_DISPLAY_ID); public void testStartFgUser_onInvalidDisplay() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG, INVALID_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); } @Test public void testStartUser_invalidDisplay() { int result = mMediator.startUser(USER_ID, USER_ID, FG, INVALID_DISPLAY); public void testStartBgUser_onInvalidDisplay() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, INVALID_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(USER_ID); } @Test public void testStartUser_displayAvailable() { int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_displayAvailable() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); assertIsNotCurrentUserOrRunningProfileOfCurrentUser(USER_ID); assertStartedProfileGroupIdOf(USER_ID, USER_ID); expectUserIsVisible(USER_ID); expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY); expectUserIsNotVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY); stopUserAndAssertState(USER_ID); expectDisplayAssignedToUser(USER_ID, SECONDARY_DISPLAY_ID); expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID); } @Test public void testStartUser_displayAlreadyAssigned() { startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); public void testVisibilityOfCurrentUserAndProfilesOnDisplayAssignedToAnotherUser() { startDefaultProfile(); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); // Make sure they were visible before expectUserIsVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID); expectUserIsVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); stopUserAndAssertState(PROFILE_USER_ID); } @Test public void testStartUser_userAlreadyAssigned() { startUserInSecondaryDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); } @Test public void testStartUser_profileOnSameDisplayAsParent() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_displayAlreadyAssigned() { startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); stopUserAndAssertState(PROFILE_USER_ID); expectUserIsNotVisibleAtAll(USER_ID); expectNoDisplayAssignedToUser(USER_ID); expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, OTHER_USER_ID); } @Test public void testStartUser_profileOnDifferentDisplayAsParent() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, OTHER_SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_userAlreadyAssigned() { startUserInSecondaryDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); stopUserAndAssertState(PROFILE_USER_ID); expectUserIsVisible(USER_ID); expectUserIsVisibleOnDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY); expectUserIsNotVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY); expectDisplayAssignedToUser(USER_ID, OTHER_SECONDARY_DISPLAY_ID); expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, USER_ID); } @Test public void testStartUser_profileDefaultDisplayParentOnSecondaryDisplay() { public void testStartBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY); int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); stopUserAndAssertState(PROFILE_USER_ID); } @Test public void testIsUserVisible_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s)", USER_ID) .that(mMediator.isUserVisible(USER_ID)).isTrue(); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // isUserVisible() for bg users relies only on the user / display assignments @Test public void testIsUserVisibleOnDisplay_currentUserUnassignedSecondaryDisplay() { startForegroundUser(USER_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_currentUserSecondaryDisplayAssignedToAnotherUser() { startForegroundUser(USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() { startDefaultProfile(); startForegroundUser(PARENT_USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_stoppedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() { startForegroundUser(PARENT_USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserOnUnassignedSecondaryDisplay() { startDefaultProfile(); startForegroundUser(PARENT_USER_ID); // TODO(b/244644281): change it to isFalse() once isUserVisible() is fixed (see note there) assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_bgUserOnAnotherSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, OTHER_SECONDARY_DISPLAY_ID)).isFalse(); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // the tests for isUserVisible(userId, display) for non-current users relies on the explicit // user / display assignments // TODO(b/244644281): add such tests if the logic change @Test public void testGetDisplayAssignedToUser_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID) .that(mMediator.getDisplayAssignedToUser(USER_ID)) .isEqualTo(SECONDARY_DISPLAY_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // getDisplayAssignedToUser() for bg users relies only on the user / display assignments @Test public void testGetUserAssignedToDisplay_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID) .that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID); } @Test public void testGetUserAssignedToDisplay_noUserOnSecondaryDisplay() { startForegroundUser(USER_ID); assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID) .that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // getUserAssignedToDisplay() for bg users relies only on the user / display assignments } services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ */ package com.android.server.pm; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; import android.annotation.UserIdInt; import org.junit.Test; /** * Tests for {@link UserVisibilityMediator} tests for devices that DO NOT support concurrent * multiple users on multiple displays (A.K.A {@code SUSD} - Single User on Single Device). Loading @@ -27,4 +33,28 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator public UserVisibilityMediatorSUSDTest() { super(/* usersOnSecondaryDisplaysEnabled= */ false); } @Test public void testStartBgUser_onSecondaryDisplay() { startUserInBackgroundOnSecondaryDisplayAndAssertFailure(USER_ID, USER_ID); expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID); } @Test public void testStartBgProfileUser_onSecondaryDisplay() { startForegroundUser(PARENT_USER_ID); startUserInBackgroundOnSecondaryDisplayAndAssertFailure(PROFILE_USER_ID, PARENT_USER_ID); } private void startUserInBackgroundOnSecondaryDisplayAndAssertFailure(@UserIdInt int userId, @UserIdInt int profileGroupId) { int result = mMediator.assignUserToDisplayOnStart(userId, profileGroupId, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(userId); expectNoDisplayAssignedToUser(userId); } } Loading
services/core/java/com/android/server/pm/UserManagerService.java +3 −3 Original line number Diff line number Diff line Loading @@ -6835,13 +6835,13 @@ public class UserManagerService extends IUserManager.Stub { @Override public int assignUserToDisplayOnStart(@UserIdInt int userId, @UserIdInt int profileGroupId, boolean foreground, int displayId) { return mUserVisibilityMediator.startUser(userId, profileGroupId, foreground, displayId); return mUserVisibilityMediator.assignUserToDisplayOnStart(userId, profileGroupId, foreground, displayId); } @Override public void unassignUserFromDisplayOnStop(@UserIdInt int userId) { mUserVisibilityMediator.stopUser(userId); mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId); } @Override Loading
services/core/java/com/android/server/pm/UserVisibilityMediator.java +29 −26 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.server.pm.UserManagerInternal.UserAssignmentResult; import com.android.server.utils.Slogf; Loading Loading @@ -121,8 +122,10 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#assignUserToDisplayOnStart(int, int, boolean, int)}. */ public @UserAssignmentResult int startUser(@UserIdInt int userId, public @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId, @UserIdInt int unResolvedProfileGroupId, boolean foreground, int displayId) { Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d", userId); // This method needs to perform 4 actions: // // 1. Check if the user can be started given the provided arguments Loading @@ -139,7 +142,7 @@ public final class UserVisibilityMediator implements Dumpable { ? userId : unResolvedProfileGroupId; if (DBG) { Slogf.d(TAG, "startUser(%d, %d, %b, %d): actualProfileGroupId=%d", Slogf.d(TAG, "assignUserToDisplayOnStart(%d, %d, %b, %d): actualProfileGroupId=%d", userId, unResolvedProfileGroupId, foreground, displayId, profileGroupId); } Loading Loading @@ -181,11 +184,11 @@ public final class UserVisibilityMediator implements Dumpable { // Don't need to do set state because methods (such as isUserVisible()) // already know that the current user (and their profiles) is assigned to // the default display. Slogf.d(TAG, "Don't need to update mUsersOnSecondaryDisplays"); Slogf.d(TAG, "don't need to update mUsersOnSecondaryDisplays"); } break; default: Slogf.wtf(TAG, "Invalid resut from canAssignUserToDisplayLocked: %d", Slogf.wtf(TAG, "invalid resut from canAssignUserToDisplayLocked: %d", mappingResult); } } Loading Loading @@ -313,9 +316,9 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}. */ public void stopUser(int userId) { public void unassignUserFromDisplayOnStop(int userId) { if (DBG) { Slogf.d(TAG, "stopUser(%d)", userId); Slogf.d(TAG, "unassignUserFromDisplayOnStop(%d)", userId); } synchronized (mLock) { if (DBG) { Loading @@ -341,7 +344,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#isUserVisible(int)}. */ public boolean isUserVisible(int userId) { public boolean isUserVisible(@UserIdInt int userId) { // First check current foreground user and their profiles (on main display) if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { return true; Loading @@ -361,7 +364,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#isUserVisible(int, int)}. */ public boolean isUserVisible(int userId, int displayId) { public boolean isUserVisible(@UserIdInt int userId, int displayId) { if (displayId == Display.INVALID_DISPLAY) { return false; } Loading Loading @@ -410,7 +413,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#getDisplayAssignedToUser(int)}. */ public int getDisplayAssignedToUser(int userId) { public int getDisplayAssignedToUser(@UserIdInt int userId) { if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { return Display.DEFAULT_DISPLAY; } Loading @@ -427,7 +430,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * See {@link UserManagerInternal#getUserAssignedToDisplay(int)}. */ public int getUserAssignedToDisplay(int displayId) { public int getUserAssignedToDisplay(@UserIdInt int displayId) { if (displayId == Display.DEFAULT_DISPLAY || !mUsersOnSecondaryDisplaysEnabled) { return getCurrentUserId(); } Loading Loading @@ -506,6 +509,18 @@ public final class UserVisibilityMediator implements Dumpable { dump(new IndentingPrintWriter(pw)); } private static boolean isSpecialUserId(@UserIdInt int userId) { switch (userId) { case UserHandle.USER_ALL: case UserHandle.USER_CURRENT: case UserHandle.USER_CURRENT_OR_SELF: case UserHandle.USER_NULL: return true; default: return false; } } private static boolean isProfile(@UserIdInt int userId, @UserIdInt int profileGroupId) { return profileGroupId != NO_PROFILE_GROUP_ID && profileGroupId != userId; } Loading @@ -514,15 +529,13 @@ public final class UserVisibilityMediator implements Dumpable { // state to decide whether a user is visible or not. If we decide to always store that info into // mUsersOnSecondaryDisplays, we should remove them. @VisibleForTesting @UserIdInt int getCurrentUserId() { private @UserIdInt int getCurrentUserId() { synchronized (mLock) { return mCurrentUserId; } } @VisibleForTesting boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) { private boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) { synchronized (mLock) { // Special case as NO_PROFILE_GROUP_ID == USER_NULL if (userId == USER_NULL || mCurrentUserId == USER_NULL) { Loading @@ -535,16 +548,7 @@ public final class UserVisibilityMediator implements Dumpable { } } @VisibleForTesting boolean isStartedUser(@UserIdInt int userId) { synchronized (mLock) { return mStartedProfileGroupIds.get(userId, INITIAL_CURRENT_USER_ID) != INITIAL_CURRENT_USER_ID; } } @VisibleForTesting boolean isStartedProfile(@UserIdInt int userId) { private boolean isStartedProfile(@UserIdInt int userId) { int profileGroupId; synchronized (mLock) { profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); Loading @@ -552,8 +556,7 @@ public final class UserVisibilityMediator implements Dumpable { return isProfile(userId, profileGroupId); } @VisibleForTesting @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { synchronized (mLock) { return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } Loading
services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java +18 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,13 @@ import android.util.Log; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.google.common.truth.Expect; import com.google.common.truth.StandardSubjectBuilder; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.RuleChain; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; Loading @@ -39,8 +43,13 @@ public abstract class ExtendedMockitoTestCase { private MockitoSession mSession; private final Expect mExpect = Expect.create(); protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); @Rule public final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); public final RuleChain mTwoRingsOfPowerAndOneChainToRuleThemAll = RuleChain .outerRule(mDumpableDumperRule) .around(mExpect); @Before public void startSession() { Loading Loading @@ -82,4 +91,12 @@ public abstract class ExtendedMockitoTestCase { mSession.finishMocking(); } } protected final StandardSubjectBuilder expectWithMessage(String msg) { return mExpect.withMessage(msg); } protected final StandardSubjectBuilder expectWithMessage(String format, Object...args) { return mExpect.withMessage(format, args); } }
services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java +50 −156 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.server.pm; import static android.os.UserHandle.USER_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; Loading @@ -23,8 +22,6 @@ import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_F import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; import static com.google.common.truth.Truth.assertWithMessage; import org.junit.Test; /** Loading @@ -41,196 +38,93 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator } @Test public void testStartUser_systemUser() { int result = mMediator.startUser(USER_SYSTEM, USER_SYSTEM, FG, SECONDARY_DISPLAY_ID); public void testStartFgUser_onInvalidDisplay() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG, INVALID_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); } @Test public void testStartUser_invalidDisplay() { int result = mMediator.startUser(USER_ID, USER_ID, FG, INVALID_DISPLAY); public void testStartBgUser_onInvalidDisplay() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, INVALID_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(USER_ID); } @Test public void testStartUser_displayAvailable() { int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_displayAvailable() { int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); assertIsNotCurrentUserOrRunningProfileOfCurrentUser(USER_ID); assertStartedProfileGroupIdOf(USER_ID, USER_ID); expectUserIsVisible(USER_ID); expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY); expectUserIsNotVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY); stopUserAndAssertState(USER_ID); expectDisplayAssignedToUser(USER_ID, SECONDARY_DISPLAY_ID); expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID); } @Test public void testStartUser_displayAlreadyAssigned() { startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); public void testVisibilityOfCurrentUserAndProfilesOnDisplayAssignedToAnotherUser() { startDefaultProfile(); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); // Make sure they were visible before expectUserIsVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID); expectUserIsVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); stopUserAndAssertState(PROFILE_USER_ID); } @Test public void testStartUser_userAlreadyAssigned() { startUserInSecondaryDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); } @Test public void testStartUser_profileOnSameDisplayAsParent() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_displayAlreadyAssigned() { startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); stopUserAndAssertState(PROFILE_USER_ID); expectUserIsNotVisibleAtAll(USER_ID); expectNoDisplayAssignedToUser(USER_ID); expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, OTHER_USER_ID); } @Test public void testStartUser_profileOnDifferentDisplayAsParent() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, OTHER_SECONDARY_DISPLAY_ID); public void testStartBgUser_onSecondaryDisplay_userAlreadyAssigned() { startUserInSecondaryDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); stopUserAndAssertState(PROFILE_USER_ID); expectUserIsVisible(USER_ID); expectUserIsVisibleOnDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID); expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY); expectUserIsNotVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY); expectDisplayAssignedToUser(USER_ID, OTHER_SECONDARY_DISPLAY_ID); expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, USER_ID); } @Test public void testStartUser_profileDefaultDisplayParentOnSecondaryDisplay() { public void testStartBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay() { startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.startUser(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY); int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, DEFAULT_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); stopUserAndAssertState(PROFILE_USER_ID); } @Test public void testIsUserVisible_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s)", USER_ID) .that(mMediator.isUserVisible(USER_ID)).isTrue(); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // isUserVisible() for bg users relies only on the user / display assignments @Test public void testIsUserVisibleOnDisplay_currentUserUnassignedSecondaryDisplay() { startForegroundUser(USER_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_currentUserSecondaryDisplayAssignedToAnotherUser() { startForegroundUser(USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() { startDefaultProfile(); startForegroundUser(PARENT_USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_stoppedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() { startForegroundUser(PARENT_USER_ID); startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse(); } @Test public void testIsUserVisibleOnDisplay_startedProfileOfCurrentUserOnUnassignedSecondaryDisplay() { startDefaultProfile(); startForegroundUser(PARENT_USER_ID); // TODO(b/244644281): change it to isFalse() once isUserVisible() is fixed (see note there) assertWithMessage("isUserVisible(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, SECONDARY_DISPLAY_ID)).isTrue(); } @Test public void testIsUserVisibleOnDisplay_bgUserOnAnotherSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("isUserVisible(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID) .that(mMediator.isUserVisible(USER_ID, OTHER_SECONDARY_DISPLAY_ID)).isFalse(); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // the tests for isUserVisible(userId, display) for non-current users relies on the explicit // user / display assignments // TODO(b/244644281): add such tests if the logic change @Test public void testGetDisplayAssignedToUser_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID) .that(mMediator.getDisplayAssignedToUser(USER_ID)) .isEqualTo(SECONDARY_DISPLAY_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // getDisplayAssignedToUser() for bg users relies only on the user / display assignments @Test public void testGetUserAssignedToDisplay_bgUserOnSecondaryDisplay() { startForegroundUser(OTHER_USER_ID); startUserInSecondaryDisplay(USER_ID, SECONDARY_DISPLAY_ID); assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID) .that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID); } @Test public void testGetUserAssignedToDisplay_noUserOnSecondaryDisplay() { startForegroundUser(USER_ID); assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID) .that(mMediator.getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID); } // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as // getUserAssignedToDisplay() for bg users relies only on the user / display assignments }
services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ */ package com.android.server.pm; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; import android.annotation.UserIdInt; import org.junit.Test; /** * Tests for {@link UserVisibilityMediator} tests for devices that DO NOT support concurrent * multiple users on multiple displays (A.K.A {@code SUSD} - Single User on Single Device). Loading @@ -27,4 +33,28 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator public UserVisibilityMediatorSUSDTest() { super(/* usersOnSecondaryDisplaysEnabled= */ false); } @Test public void testStartBgUser_onSecondaryDisplay() { startUserInBackgroundOnSecondaryDisplayAndAssertFailure(USER_ID, USER_ID); expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID); } @Test public void testStartBgProfileUser_onSecondaryDisplay() { startForegroundUser(PARENT_USER_ID); startUserInBackgroundOnSecondaryDisplayAndAssertFailure(PROFILE_USER_ID, PARENT_USER_ID); } private void startUserInBackgroundOnSecondaryDisplayAndAssertFailure(@UserIdInt int userId, @UserIdInt int profileGroupId) { int result = mMediator.assignUserToDisplayOnStart(userId, profileGroupId, BG, SECONDARY_DISPLAY_ID); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(userId); expectNoDisplayAssignedToUser(userId); } }