diff options
5 files changed, 304 insertions, 116 deletions
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 9ef1bba16351..b4d467f96091 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -64,12 +64,11 @@ public abstract class UserManagerInternal { }) public @interface UserAssignmentResult {} - // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively. - @Keep public static final int USER_START_MODE_FOREGROUND = 1; - @Keep public static final int USER_START_MODE_BACKGROUND = 2; - @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3; - private static final String PREFIX_USER_START_MODE = "USER_START_MODE_"; + + /** + * Type used to indicate how a user started. + */ @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = { USER_START_MODE_FOREGROUND, USER_START_MODE_BACKGROUND, @@ -77,6 +76,32 @@ public abstract class UserManagerInternal { }) public @interface UserStartMode {} + // TODO(b/248408342): Move keep annotations below to the method referencing these fields + // reflectively. + + /** (Full) user started on foreground (a.k.a. "current user"). */ + @Keep public static final int USER_START_MODE_FOREGROUND = 1; + + /** + * User (full or profile) started on background and is + * {@link UserManager#isUserVisible() invisible}. + * + * <p>This is the "traditional" way of starting a background user, and can be used to start + * profiles as well, although starting an invisible profile is not common from the System UI + * (it could be done through APIs or adb, though). + */ + @Keep public static final int USER_START_MODE_BACKGROUND = 2; + + /** + * User (full or profile) started on background and is + * {@link UserManager#isUserVisible() visible}. + * + * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current + * user is the current foreground user), but it can also be used to start a full user associated + * with a display (which is the case on automotives with passenger displays). + */ + @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3; + public interface UserRestrictionsListener { /** * Called when a user restriction changes. diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java index 3f7502bfa613..f87f50add5be 100644 --- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java +++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java @@ -42,6 +42,7 @@ import android.util.Dumpable; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.IntArray; +import android.util.Log; import android.util.SparseIntArray; import android.view.Display; @@ -55,6 +56,8 @@ import com.android.server.pm.UserManagerInternal.UserVisibilityListener; import com.android.server.utils.Slogf; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -77,11 +80,11 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public final class UserVisibilityMediator implements Dumpable { - private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE - private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE - private static final String TAG = UserVisibilityMediator.class.getSimpleName(); + private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE + private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_"; public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1; public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2; @@ -98,7 +101,7 @@ public final class UserVisibilityMediator implements Dumpable { }) public @interface SecondaryDisplayMappingStatus {} - // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices + // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices @VisibleForTesting static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM; @@ -132,10 +135,23 @@ public final class UserVisibilityMediator implements Dumpable { private final SparseIntArray mExtraDisplaysAssignedToUsers; /** - * Mapping from each started user to its profile group. + * Mapping of each user that started visible (key) to its profile group id (value). + * + * <p>It's used to determine not just if the user is visible, but also + * {@link #isProfile(int, int) if it's a profile}. + */ + @GuardedBy("mLock") + private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray(); + + /** + * List of profiles that have explicitly started invisible. + * + * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we + * don't care about autoboxing. */ @GuardedBy("mLock") - private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray(); + @Nullable + private final List<Integer> mStartedInvisibleProfileUserIds; /** * Handler user to call listeners @@ -164,9 +180,14 @@ public final class UserVisibilityMediator implements Dumpable { mUsersAssignedToDisplayOnStart = null; mExtraDisplaysAssignedToUsers = null; } + mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null; mHandler = handler; - // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices - mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID); + // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices + mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID); + + if (DBG) { + Slogf.i(TAG, "UserVisibilityMediator created with DBG on"); + } } /** @@ -177,6 +198,8 @@ public final class UserVisibilityMediator implements Dumpable { int displayId) { Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d", userId); + validateUserStartMode(userStartMode); + // This method needs to perform 4 actions: // // 1. Check if the user can be started given the provided arguments @@ -224,14 +247,29 @@ public final class UserVisibilityMediator implements Dumpable { visibleUsersBefore = getVisibleUsers(); - // Set current user / profiles state - if (userStartMode == USER_START_MODE_FOREGROUND) { - mCurrentUserId = userId; - } - if (DBG) { - Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId); + // Set current user / started users state + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + mCurrentUserId = userId; + // Fallthrough + case USER_START_MODE_BACKGROUND_VISIBLE: + if (DBG) { + Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)", + userId, profileGroupId); + } + mStartedVisibleProfileGroupIds.put(userId, profileGroupId); + break; + case USER_START_MODE_BACKGROUND: + if (mStartedInvisibleProfileUserIds != null + && isProfile(userId, profileGroupId)) { + Slogf.d(TAG, "adding user %d to list of invisible profiles", userId); + mStartedInvisibleProfileUserIds.add(userId); + } + break; + default: + Slogf.wtf(TAG, "invalid userStartMode passed to assignUserToDisplayOnStart: " + + "%d", userStartMode); } - mStartedProfileGroupIds.put(userId, profileGroupId); // Set user / display state switch (mappingResult) { @@ -297,38 +335,44 @@ public final class UserVisibilityMediator implements Dumpable { boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; if (displayId != DEFAULT_DISPLAY) { if (foreground) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start " + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start " + "foreground user on secondary display", userId, profileGroupId, - foreground, displayId); + userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } if (!mVisibleBackgroundUsersEnabled) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on " + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on " + "device that doesn't support multiple users on multiple displays", - userId, profileGroupId, foreground, displayId); + userId, profileGroupId, userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } } if (isProfile(userId, profileGroupId)) { if (displayId != DEFAULT_DISPLAY) { - Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user " - + "on secondary display", userId, profileGroupId, foreground, - displayId); + Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user " + + "on secondary display", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } - if (foreground) { - Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in " - + "foreground", userId, profileGroupId, foreground, displayId); - return USER_ASSIGNMENT_RESULT_FAILURE; - } else { - boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId); - if (DBG) { - Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay); - } - return isParentVisibleOnDisplay - ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE - : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in " + + "foreground", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); + return USER_ASSIGNMENT_RESULT_FAILURE; + case USER_START_MODE_BACKGROUND_VISIBLE: + boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId); + if (!isParentVisibleOnDisplay) { + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot" + + " start profile user visible when its parent is not visible in " + + "that display", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); + return USER_ASSIGNMENT_RESULT_FAILURE; + } + return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; + case USER_START_MODE_BACKGROUND: + return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; } } else if (mUsersAssignedToDisplayOnStart != null && isUserAssignedToDisplayOnStartLocked(userId, displayId)) { @@ -353,8 +397,9 @@ public final class UserVisibilityMediator implements Dumpable { if (mVisibleBackgroundUserOnDefaultDisplayAllowed && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) { int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY); - if (userStartedOnDefaultDisplay != USER_NULL) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on" + if (userStartedOnDefaultDisplay != USER_NULL + && userStartedOnDefaultDisplay != profileGroupId) { + Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on" + " default display because user %d already did so", userId, userStartedOnDefaultDisplay); return SECONDARY_DISPLAY_MAPPING_FAILED; @@ -468,7 +513,7 @@ public final class UserVisibilityMediator implements Dumpable { userId, displayId); return false; } - if (isStartedProfile(userId)) { + if (isStartedVisibleProfileLocked(userId)) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile", userId, displayId); return false; @@ -556,10 +601,14 @@ public final class UserVisibilityMediator implements Dumpable { @GuardedBy("mLock") private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) { if (DBG) { - Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId, - mStartedProfileGroupIds); + Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId, + mStartedVisibleProfileGroupIds); + } + mStartedVisibleProfileGroupIds.delete(userId); + if (mStartedInvisibleProfileUserIds != null) { + Slogf.d(TAG, "Removing %d from list of invisible profiles", userId); + mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId)); } - mStartedProfileGroupIds.delete(userId); if (!mVisibleBackgroundUsersEnabled) { // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as @@ -589,7 +638,8 @@ public final class UserVisibilityMediator implements Dumpable { * See {@link UserManagerInternal#isUserVisible(int)}. */ public boolean isUserVisible(@UserIdInt int userId) { - // First check current foreground user and their profiles (on main display) + // For optimization (as most devices don't support visible background users), check for + // current foreground user and their profiles first if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { if (VERBOSE) { Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId); @@ -598,19 +648,31 @@ public final class UserVisibilityMediator implements Dumpable { } if (!mVisibleBackgroundUsersEnabled) { - if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + if (VERBOSE) { + Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + " device doesn't support visible background users", userId); } return false; } - boolean visible; + synchronized (mLock) { - visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0; + int profileGroupId; + synchronized (mLock) { + profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); + } + if (isProfile(userId, profileGroupId)) { + return isUserAssignedToDisplayOnStartLocked(profileGroupId); + } + return isUserAssignedToDisplayOnStartLocked(userId); } - if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible); + } + + @GuardedBy("mLock") + private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) { + boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0; + if (VERBOSE) { + Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible); } return visible; } @@ -640,7 +702,8 @@ public final class UserVisibilityMediator implements Dumpable { return false; } - // Current user is always visible on: + // For optimization (as most devices don't support visible background users), check for + // current user and profile first. Current user is always visible on: // - Default display // - Secondary displays when device doesn't support visible bg users // - Or when explicitly added (which is checked below) @@ -662,14 +725,26 @@ public final class UserVisibilityMediator implements Dumpable { } synchronized (mLock) { - if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) { - // User assigned to display on start - return true; + int profileGroupId; + synchronized (mLock) { + profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } + if (isProfile(userId, profileGroupId)) { + return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId); + } + return isFullUserVisibleOnBackgroundLocked(userId, displayId); + } + } - // Check for extra display assignment - return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; + // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that + @GuardedBy("mLock") + private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) { + if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) { + // User assigned to display on start + return true; } + // Check for extra display assignment + return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; } /** @@ -737,7 +812,7 @@ public final class UserVisibilityMediator implements Dumpable { continue; } int userId = mUsersAssignedToDisplayOnStart.keyAt(i); - if (!isStartedProfile(userId)) { + if (!isStartedVisibleProfileLocked(userId)) { return userId; } else if (DBG) { Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's " @@ -770,8 +845,8 @@ public final class UserVisibilityMediator implements Dumpable { // number of users is too small, the gain is probably not worth the increase on complexity. IntArray visibleUsers = new IntArray(); synchronized (mLock) { - for (int i = 0; i < mStartedProfileGroupIds.size(); i++) { - int userId = mStartedProfileGroupIds.keyAt(i); + for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) { + int userId = mStartedVisibleProfileGroupIds.keyAt(i); if (isUserVisible(userId)) { visibleUsers.add(userId); } @@ -804,7 +879,7 @@ public final class UserVisibilityMediator implements Dumpable { } } - // TODO(b/242195409): remove this method if not needed anymore + // TODO(b/266158156): remove this method if not needed anymore /** * Nofify all listeners that the system user visibility changed. */ @@ -866,6 +941,9 @@ public final class UserVisibilityMediator implements Dumpable { ipw.println("UserVisibilityMediator"); ipw.increaseIndent(); + ipw.print("DBG: "); + ipw.println(DBG); + synchronized (mLock) { ipw.print("Current user id: "); ipw.println(mCurrentUserId); @@ -873,8 +951,12 @@ public final class UserVisibilityMediator implements Dumpable { ipw.print("Visible users: "); ipw.println(getVisibleUsers()); - dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group", - "u", "pg"); + dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds, + "started visible user / profile group", "u", "pg"); + if (mStartedInvisibleProfileUserIds != null) { + ipw.print("Profiles started invisible: "); + ipw.println(mStartedInvisibleProfileUserIds); + } ipw.print("Supports visible background users on displays: "); ipw.println(mVisibleBackgroundUsersEnabled); @@ -982,22 +1064,25 @@ public final class UserVisibilityMediator implements Dumpable { if (mCurrentUserId == userId) { return true; } - return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId; + return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) + == mCurrentUserId; } } - private boolean isStartedProfile(@UserIdInt int userId) { - int profileGroupId; - synchronized (mLock) { - profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); - } + @GuardedBy("mLock") + private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) { + int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); return isProfile(userId, profileGroupId); } - private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { - synchronized (mLock) { - return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); + private void validateUserStartMode(@UserStartMode int userStartMode) { + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + case USER_START_MODE_BACKGROUND: + case USER_START_MODE_BACKGROUND_VISIBLE: + return; } + throw new IllegalArgumentException("Invalid user start mode: " + userStartMode); } private static String secondaryDisplayMappingStatusToString( diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java index 9aa53db6fe1b..8979585d9235 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java @@ -20,6 +20,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; +import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE; +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.android.server.pm.UserVisibilityChangedEvent.onInvisible; import static com.android.server.pm.UserVisibilityChangedEvent.onVisible; @@ -73,8 +75,8 @@ public final class UserVisibilityMediatorMUPANDTest assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); // Make sure another user cannot be started on default display - int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, - BG_VISIBLE, DEFAULT_DISPLAY); + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE, + DEFAULT_DISPLAY); assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, "when user (%d) is starting on default display after it was started by user %d", otherUserId, visibleBgUserId); @@ -117,8 +119,8 @@ public final class UserVisibilityMediatorMUPANDTest assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); // Make sure another user cannot be started on default display - int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, - BG_VISIBLE, DEFAULT_DISPLAY); + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE, + DEFAULT_DISPLAY); assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, "when user (%d) is starting on default display after it was started by user %d", otherUserId, visibleBgUserId); @@ -127,8 +129,6 @@ public final class UserVisibilityMediatorMUPANDTest listener.verify(); } - /* TODO(b/261538337): re-add after the reverted CL is merged again - @Test public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBgOnSecondaryDisplay() @@ -226,5 +226,4 @@ public final class UserVisibilityMediatorMUPANDTest listener.verify(); } - */ } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java index 1bf921c503d8..277480316c66 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java @@ -44,7 +44,6 @@ import android.text.TextUtils; import android.util.IntArray; import android.util.Log; -import com.android.internal.util.Preconditions; import com.android.server.DumpableDumperRule; import com.android.server.ExpectableTestCase; @@ -152,6 +151,12 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { } @Test + public final void testAssignUserToDisplayOnStart_invalidUserStartMode() { + assertThrows(IllegalArgumentException.class, () -> mMediator + .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY)); + } + + @Test public final void testStartFgUser_onSecondaryDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -286,7 +291,7 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); @@ -302,14 +307,14 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY); - assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); listener.verify(); } @@ -335,6 +340,41 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { } @Test + public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForNoEvents(); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + + listener.verify(); + } + + @Test + public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForNoEvents(); + startBackgroundUser(PARENT_USER_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY); + + assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test public final void testStartBgProfile_onSecondaryDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -488,8 +528,6 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { * se. */ protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) { - Preconditions.checkArgument(displayId != INVALID_DISPLAY && displayId != DEFAULT_DISPLAY, - "must pass a secondary display, not %d", displayId); Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")"); int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId); if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java index af85ef4b6b87..e82910f25a2c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java @@ -109,34 +109,6 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase } @Test - public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() - throws Exception { - AsyncUserVisibilityListener listener = addListenerForEvents( - onInvisible(INITIAL_CURRENT_USER_ID), - onVisible(PARENT_USER_ID), - onVisible(PROFILE_USER_ID)); - startForegroundUser(PARENT_USER_ID); - - int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, - BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); - expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); - - expectUserIsVisible(PROFILE_USER_ID); - expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY); - expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); - expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); - expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID); - - expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY); - expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID); - - assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); - - listener.verify(); - } - - @Test public final void testStartFgUser_onInvalidDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -301,14 +273,83 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase } @Test + public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents( + onInvisible(INITIAL_CURRENT_USER_ID), + onVisible(PARENT_USER_ID), + onVisible(PROFILE_USER_ID)); + startForegroundUser(PARENT_USER_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); + + expectUserIsVisible(PROFILE_USER_ID); + expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY); + expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); + expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID); + + expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID); + + assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test public final void - testStartVisibleBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay() - throws Exception { + testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnAnotherDisplay() + throws Exception { AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); + + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + // Not supported - profiles can only be started on default display + @Test + public final void + testStartVisibleBgProfile_onSecondaryDisplay_whenParentIsStartedVisibleOnThatDisplay() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); + startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); + + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test + public final void + testStartProfile_onDefaultDisplay_whenParentIsStartedVisibleOnSecondaryDisplay() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); + startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); |