From 2c4a5939e71fa50733ee2072172825a63488a8a3 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 22 Dec 2022 07:20:02 +0000 Subject: [PATCH] UserVisibilityMediator: allow visible bg users on default display. So far only the current user is visible in the default display and other users could only be started visible on secondary displays, but that restriction must be lift for automotive builds that only support passengers (for example, when a 2nd instance of Android is run on the back seat of a car). This CL changes UserVisibilityMediator to allow that scenario, although it's not hooked with other parts of the system yet (which will require a new config and new CTS tests). Test: atest UserVisibilityMediatorMUPANDTest \ UserVisibilityMediatorMUMDTest \ UserVisibilityMediatorSUSDTest Fixes: 261538337 Change-Id: Ia7989f5ce2af41c7be2b1d578ab0e0e2aecc4e9d --- .../server/pm/UserVisibilityMediator.java | 168 +++++++++++++----- .../android/server/DumpableDumperRule.java | 11 +- .../pm/UserVisibilityMediatorMUMDTest.java | 17 +- .../pm/UserVisibilityMediatorMUPANDTest.java | 129 ++++++++++++++ .../pm/UserVisibilityMediatorSUSDTest.java | 15 +- .../pm/UserVisibilityMediatorTestCase.java | 34 ++-- ...MediatorVisibleBackgroundUserTestCase.java | 6 +- 7 files changed, 320 insertions(+), 60 deletions(-) create mode 100644 services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java index 66d390f4f3e99..1f935f901d5b9 100644 --- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java +++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java @@ -36,6 +36,7 @@ import android.annotation.UserIdInt; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; +import android.util.DebugUtils; import android.util.Dumpable; import android.util.EventLog; import android.util.IndentingPrintWriter; @@ -80,6 +81,7 @@ public final class UserVisibilityMediator implements Dumpable { private static final String TAG = UserVisibilityMediator.class.getSimpleName(); + 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; public static final int SECONDARY_DISPLAY_MAPPING_FAILED = -1; @@ -88,7 +90,7 @@ public final class UserVisibilityMediator implements Dumpable { * Whether a user / display assignment requires adding an entry to the * {@code mUsersOnSecondaryDisplays} map. */ - @IntDef(flag = false, prefix = {"SECONDARY_DISPLAY_MAPPING_"}, value = { + @IntDef(flag = false, prefix = {PREFIX_SECONDARY_DISPLAY_MAPPING}, value = { SECONDARY_DISPLAY_MAPPING_NEEDED, SECONDARY_DISPLAY_MAPPING_NOT_NEEDED, SECONDARY_DISPLAY_MAPPING_FAILED @@ -102,6 +104,7 @@ public final class UserVisibilityMediator implements Dumpable { private final Object mLock = new Object(); private final boolean mVisibleBackgroundUsersEnabled; + private final boolean mVisibleBackgroundUserOnDefaultDisplayAllowed; @UserIdInt @GuardedBy("mLock") @@ -110,7 +113,7 @@ public final class UserVisibilityMediator implements Dumpable { /** * Map of background users started visible on displays (key is user id, value is display id). * - *

Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}. + *

Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}. */ @Nullable @GuardedBy("mLock") @@ -121,7 +124,7 @@ public final class UserVisibilityMediator implements Dumpable { * {@link #assignUserToExtraDisplay(int, int)}) displays assigned to user (key is display id, * value is user id). * - *

Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}. + *

Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}. */ @Nullable @GuardedBy("mLock") @@ -143,12 +146,17 @@ public final class UserVisibilityMediator implements Dumpable { new CopyOnWriteArrayList<>(); UserVisibilityMediator(Handler handler) { - this(UserManager.isVisibleBackgroundUsersEnabled(), handler); + this(UserManager.isVisibleBackgroundUsersEnabled(), + // TODO(b/261538232): get visibleBackgroundUserOnDefaultDisplayAllowed from UM + /* visibleBackgroundUserOnDefaultDisplayAllowed= */ false, handler); } @VisibleForTesting - UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) { + UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, + boolean visibleBackgroundUserOnDefaultDisplayAllowed, Handler handler) { mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled; + mVisibleBackgroundUserOnDefaultDisplayAllowed = + visibleBackgroundUserOnDefaultDisplayAllowed; if (mVisibleBackgroundUsersEnabled) { mUsersAssignedToDisplayOnStart = new SparseIntArray(); mExtraDisplaysAssignedToUsers = new SparseIntArray(); @@ -203,7 +211,12 @@ public final class UserVisibilityMediator implements Dumpable { return result; } - int mappingResult = canAssignUserToDisplayLocked(userId, profileGroupId, displayId); + int mappingResult = canAssignUserToDisplayLocked(userId, profileGroupId, userStartMode, + displayId); + if (DBG) { + Slogf.d(TAG, "mapping result: %s", + secondaryDisplayMappingStatusToString(mappingResult)); + } if (mappingResult == SECONDARY_DISPLAY_MAPPING_FAILED) { return USER_ASSIGNMENT_RESULT_FAILURE; } @@ -263,14 +276,16 @@ public final class UserVisibilityMediator implements Dumpable { + "(it should be BACKGROUND_USER_VISIBLE", userId, displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } - if (userStartMode == USER_START_MODE_BACKGROUND_VISIBLE - && displayId == DEFAULT_DISPLAY && !isProfile(userId, profileGroupId)) { + + boolean visibleBackground = userStartMode == USER_START_MODE_BACKGROUND_VISIBLE; + if (displayId == DEFAULT_DISPLAY && visibleBackground + && !mVisibleBackgroundUserOnDefaultDisplayAllowed + && !isProfile(userId, profileGroupId)) { Slogf.wtf(TAG, "cannot start full user (%d) visible on default display", userId); return USER_ASSIGNMENT_RESULT_FAILURE; } boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; - if (displayId != DEFAULT_DISPLAY) { if (foreground) { Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start " @@ -309,26 +324,47 @@ public final class UserVisibilityMediator implements Dumpable { } return foreground || displayId != DEFAULT_DISPLAY - ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE - : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; + || (visibleBackground && mVisibleBackgroundUserOnDefaultDisplayAllowed) + ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE + : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; } @GuardedBy("mLock") @SecondaryDisplayMappingStatus private int canAssignUserToDisplayLocked(@UserIdInt int userId, - @UserIdInt int profileGroupId, int displayId) { - if (displayId == DEFAULT_DISPLAY - && (!mVisibleBackgroundUsersEnabled || !isProfile(userId, profileGroupId))) { - // Don't need to do anything because methods (such as isUserVisible()) already - // know that the current user (and its profiles) is assigned to the default display. - // But on MUMD devices, profiles are only supported in the default display, so it - // cannot return yet as it needs to check if the parent is also assigned to the - // DEFAULT_DISPLAY (this is done indirectly below when it checks that the profile parent - // is the current user, as the current user is always assigned to the DEFAULT_DISPLAY). - if (DBG) { - Slogf.d(TAG, "ignoring mapping for default display"); + @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId) { + if (displayId == DEFAULT_DISPLAY) { + boolean mappingNeeded = false; + 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" + + " default display because user %d already did so", userId, + userStartedOnDefaultDisplay); + return SECONDARY_DISPLAY_MAPPING_FAILED; + } + mappingNeeded = true; + } + if (!mappingNeeded && mVisibleBackgroundUsersEnabled + && isProfile(userId, profileGroupId)) { + mappingNeeded = true; + } + + if (!mappingNeeded) { + // Don't need to do anything because methods (such as isUserVisible()) already + // know that the current user (and its profiles) is assigned to the default display. + // But on MUMD devices, profiles are only supported in the default display, so it + // cannot return yet as it needs to check if the parent is also assigned to the + // DEFAULT_DISPLAY (this is done indirectly below when it checks that the profile + // parent is the current user, as the current user is always assigned to the + // DEFAULT_DISPLAY). + if (DBG) { + Slogf.d(TAG, "ignoring mapping for default display for user %d starting as %s", + userId, userStartModeToString(userStartMode)); + } + return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED; } - return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED; } if (userId == UserHandle.USER_SYSTEM) { @@ -421,13 +457,14 @@ public final class UserVisibilityMediator implements Dumpable { return false; } - int userAssignedToDisplay = getUserAssignedToDisplay(displayId, - /* returnCurrentUserByDefault= */ false); + // First check if the user started on display + int userAssignedToDisplay = getUserStartedOnDisplay(displayId); if (userAssignedToDisplay != USER_NULL) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because display was assigned" + " to user %d on start", userId, displayId, userAssignedToDisplay); return false; } + // Then if was assigned extra userAssignedToDisplay = mExtraDisplaysAssignedToUsers.get(userId, USER_NULL); if (userAssignedToDisplay != USER_NULL) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user %d was already " @@ -435,7 +472,8 @@ public final class UserVisibilityMediator implements Dumpable { return false; } if (DBG) { - Slogf.d(TAG, "addding %d -> %d to map", displayId, userId); + Slogf.d(TAG, "addding %d -> %d to mExtraDisplaysAssignedToUsers", displayId, + userId); } mExtraDisplaysAssignedToUsers.put(displayId, userId); } @@ -501,7 +539,7 @@ public final class UserVisibilityMediator implements Dumpable { mStartedProfileGroupIds.delete(userId); if (!mVisibleBackgroundUsersEnabled) { - // Don't need to do update mUsersOnSecondaryDisplays because methods (such as + // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as // isUserVisible()) already know that the current user (and their profiles) is // assigned to the default display. return; @@ -536,11 +574,10 @@ public final class UserVisibilityMediator implements Dumpable { return true; } - // Device doesn't support multiple users on multiple displays, so only users checked above - // can be visible if (!mVisibleBackgroundUsersEnabled) { if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): false for non-current user on MUMD", userId); + Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + + " device doesn't support visible background users", userId); } return false; } @@ -559,15 +596,29 @@ public final class UserVisibilityMediator implements Dumpable { * See {@link UserManagerInternal#isUserVisible(int, int)}. */ public boolean isUserVisible(@UserIdInt int userId, int displayId) { - if (displayId == Display.INVALID_DISPLAY) { + if (displayId == INVALID_DISPLAY) { return false; } - if (!mVisibleBackgroundUsersEnabled || displayId == Display.DEFAULT_DISPLAY) { - // TODO(b/245939659): will need to move the displayId == Display.DEFAULT_DISPLAY outside - // once it supports background users on DEFAULT_DISPLAY (for example, passengers in a - // no-driver configuration) - return isCurrentUserOrRunningProfileOfCurrentUser(userId); + // 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) + if (isCurrentUserOrRunningProfileOfCurrentUser(userId) + && (displayId == DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) { + if (VERBOSE) { + Slogf.v(TAG, "isUserVisible(%d, %d): returning true for current user/profile", + userId, displayId); + } + return true; + } + + if (!mVisibleBackgroundUsersEnabled) { + if (DBG) { + Slogf.d(TAG, "isUserVisible(%d, %d): returning false as device does not support" + + " visible background users", userId, displayId); + } + return false; } synchronized (mLock) { @@ -575,7 +626,8 @@ public final class UserVisibilityMediator implements Dumpable { // User assigned to display on start return true; } - // Check for extra assignment + + // Check for extra display assignment return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; } } @@ -585,15 +637,31 @@ public final class UserVisibilityMediator implements Dumpable { */ public int getDisplayAssignedToUser(@UserIdInt int userId) { if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { - return Display.DEFAULT_DISPLAY; + if (mVisibleBackgroundUserOnDefaultDisplayAllowed) { + // When device supports visible bg users on default display, the default display is + // assigned to the current user, unless a user is started visible on it + int userStartedOnDefaultDisplay; + synchronized (mLock) { + userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY); + } + if (userStartedOnDefaultDisplay != USER_NULL) { + if (DBG) { + Slogf.d(TAG, "getDisplayAssignedToUser(%d): returning INVALID_DISPLAY for " + + "current user user %d was started on DEFAULT_DISPLAY", + userId, userStartedOnDefaultDisplay); + } + return INVALID_DISPLAY; + } + } + return DEFAULT_DISPLAY; } if (!mVisibleBackgroundUsersEnabled) { - return Display.INVALID_DISPLAY; + return INVALID_DISPLAY; } synchronized (mLock) { - return mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY); + return mUsersAssignedToDisplayOnStart.get(userId, INVALID_DISPLAY); } } @@ -604,6 +672,13 @@ public final class UserVisibilityMediator implements Dumpable { return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ true); } + /** + * Gets the user explicitly assigned to a display. + */ + private @UserIdInt int getUserStartedOnDisplay(@UserIdInt int displayId) { + return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ false); + } + /** * Gets the user explicitly assigned to a display, or the current user when no user is assigned * to it (and {@code returnCurrentUserByDefault} is {@code true}). @@ -611,7 +686,8 @@ public final class UserVisibilityMediator implements Dumpable { private @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId, boolean returnCurrentUserByDefault) { if (returnCurrentUserByDefault - && (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) { + && ((displayId == DEFAULT_DISPLAY && !mVisibleBackgroundUserOnDefaultDisplayAllowed + || !mVisibleBackgroundUsersEnabled))) { return getCurrentUserId(); } @@ -763,8 +839,10 @@ public final class UserVisibilityMediator implements Dumpable { ipw.print("Supports visible background users on displays: "); ipw.println(mVisibleBackgroundUsersEnabled); - dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d"); + ipw.print("Allows visible background users on default display: "); + ipw.println(mVisibleBackgroundUserOnDefaultDisplayAllowed); + dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d"); dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user", "d", "u"); @@ -872,4 +950,10 @@ public final class UserVisibilityMediator implements Dumpable { return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } } + + private static String secondaryDisplayMappingStatusToString( + @SecondaryDisplayMappingStatus int status) { + return DebugUtils.constantToString(UserVisibilityMediator.class, + PREFIX_SECONDARY_DISPLAY_MAPPING, status); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java b/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java index 33275bd471f60..a0687f6c1ba96 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java +++ b/services/tests/mockingservicestests/src/com/android/server/DumpableDumperRule.java @@ -62,14 +62,21 @@ public final class DumpableDumperRule implements TestRule { }; } - private void dumpOnFailure(String testName) throws IOException { + /** + * Logs all dumpables. + */ + public void dump(String reason) { if (mDumpables.isEmpty()) { return; } - Log.w(TAG, "Dumping " + mDumpables.size() + " dumpables on failure of " + testName); + Log.w(TAG, "Dumping " + mDumpables.size() + " dumpable(s). Reason: " + reason); mDumpables.forEach(d -> logDumpable(d)); } + private void dumpOnFailure(String testName) throws IOException { + dump("failure of " + testName); + } + private void logDumpable(Dumpable dumpable) { try { try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java index 579621ca86b59..36c9f2ec869b3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java @@ -15,6 +15,8 @@ */ package com.android.server.pm; +import org.junit.Test; + /** * Tests for {@link UserVisibilityMediator} tests for devices that support concurrent Multiple * Users on Multiple Displays (A.K.A {@code MUMD}). @@ -26,6 +28,19 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediatorVisibleBackgroundUserTestCase { public UserVisibilityMediatorMUMDTest() throws Exception { - super(/* usersOnSecondaryDisplaysEnabled= */ true); + super(/* backgroundUsersOnDisplaysEnabled= */ true, + /* backgroundUserOnDefaultDisplayAllowed= */ false); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay() throws Exception { + int userId = visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + + assertInvisibleUserCannotBeAssignedExtraDisplay(userId, SECONDARY_DISPLAY_ID); + } + + @Test + public void testStartBgUser_onDefaultDisplay_visible() throws Exception { + visibleBgUserCannotBeStartedOnDefaultDisplayTest(); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java new file mode 100644 index 0000000000000..01ce696a1cbf6 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +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_VISIBLE; +import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible; +import static com.android.server.pm.UserVisibilityChangedEvent.onVisible; +import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID; + +import org.junit.Test; + +/** + * Tests for {@link UserVisibilityMediator} tests for devices that support not only concurrent + * Multiple Users on Multiple Displays, but also let background users to be visible in the default + * display (A.K.A {@code MUPAND} - MUltiple Passengers, No Driver). + * + *

Run as {@code +* atest FrameworksMockingServicesTests:com.android.server.pm.UserVisibilityMediatorMUPANDTest} + */ +public final class UserVisibilityMediatorMUPANDTest + extends UserVisibilityMediatorVisibleBackgroundUserTestCase { + + public UserVisibilityMediatorMUPANDTest() throws Exception { + super(/* backgroundUsersOnDisplaysEnabled= */ true, + /* backgroundUserOnDefaultDisplayAllowed= */ true); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay_initialCurrentUserId() + throws Exception { + int currentUserId = INITIAL_CURRENT_USER_ID; + int visibleBgUserId = USER_ID; + int otherUserId = OTHER_USER_ID; + + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(visibleBgUserId)); + + int result = mMediator.assignUserToDisplayOnStart(visibleBgUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectVisibleUsers(currentUserId, visibleBgUserId); + + // Assert bg user visibility + expectUserIsVisible(visibleBgUserId); + expectUserIsVisibleOnDisplay(visibleBgUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(visibleBgUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(visibleBgUserId, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, visibleBgUserId); + + // Assert current user visibility + expectUserIsVisible(currentUserId); + expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(currentUserId, INVALID_DISPLAY); + + 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); + assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, + "when user (%d) is starting on default display after it was started by user %d", + otherUserId, visibleBgUserId); + expectVisibleUsers(currentUserId, visibleBgUserId); + + listener.verify(); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay_nonInitialCurrentUserId() + throws Exception { + int currentUserId = OTHER_USER_ID; + int visibleBgUserId = USER_ID; + int otherUserId = YET_ANOTHER_USER_ID; + + AsyncUserVisibilityListener listener = addListenerForEvents( + onInvisible(INITIAL_CURRENT_USER_ID), + onVisible(currentUserId), + onVisible(visibleBgUserId)); + startForegroundUser(currentUserId); + + int result = mMediator.assignUserToDisplayOnStart(visibleBgUserId, visibleBgUserId, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectVisibleUsers(currentUserId, visibleBgUserId); + + // Assert bg user visibility + expectUserIsVisible(visibleBgUserId); + expectUserIsVisibleOnDisplay(visibleBgUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(visibleBgUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(visibleBgUserId, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, visibleBgUserId); + + // Assert current user visibility + expectUserIsVisible(currentUserId); + expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY); + expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY); + expectDisplayAssignedToUser(currentUserId, INVALID_DISPLAY); + + 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); + assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, + "when user (%d) is starting on default display after it was started by user %d", + otherUserId, visibleBgUserId); + expectVisibleUsers(currentUserId, visibleBgUserId); + + listener.verify(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java index b9ba780ff685a..c195064071f65 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java @@ -37,7 +37,15 @@ import org.junit.Test; public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediatorTestCase { public UserVisibilityMediatorSUSDTest() { - super(/* usersOnSecondaryDisplaysEnabled= */ false); + super(/* backgroundUsersOnDisplaysEnabled= */ false, + /* backgroundUserOnDefaultDisplayAllowed= */ false); + } + + @Test + public void testStartVisibleBgUser_onDefaultDisplay() throws Exception { + int userId = visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + + assertInvisibleUserCannotBeAssignedExtraDisplay(userId, SECONDARY_DISPLAY_ID); } @Test @@ -100,6 +108,11 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator listener.verify(); } + @Test + public void testStartBgUser_onDefaultDisplay_visible() throws Exception { + visibleBgUserCannotBeStartedOnDefaultDisplayTest(); + } + @Test public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() throws Exception { 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 c59834bea6cae..5176d684ace68 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java @@ -78,6 +78,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { */ protected static final int OTHER_USER_ID = 666; + /** + * Id for yeat another simple user. + */ + protected static final int YET_ANOTHER_USER_ID = 700; + /** * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}. * @@ -110,11 +115,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { protected AsyncUserVisibilityListener.Factory mListenerFactory; private final boolean mBackgroundUsersOnDisplaysEnabled; + private final boolean mBackgroundUserOnDefaultDisplayAllowed; protected UserVisibilityMediator mMediator; - protected UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled) { + protected UserVisibilityMediatorTestCase(boolean backgroundUsersOnDisplaysEnabled, + boolean backgroundUserOnDefaultDisplayAllowed) { mBackgroundUsersOnDisplaysEnabled = backgroundUsersOnDisplaysEnabled; + mBackgroundUserOnDefaultDisplayAllowed = backgroundUserOnDefaultDisplayAllowed; } @Before @@ -123,7 +131,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { Thread thread = mHandler.getLooper().getThread(); Log.i(TAG, "setFixtures(): using thread " + thread + " (from handler " + mHandler + ")"); mListenerFactory = new AsyncUserVisibilityListener.Factory(mExpect, thread); - mMediator = new UserVisibilityMediator(mBackgroundUsersOnDisplaysEnabled, mHandler); + mMediator = new UserVisibilityMediator(mBackgroundUsersOnDisplaysEnabled, + mBackgroundUserOnDefaultDisplayAllowed, mHandler); mDumpableDumperRule.addDumpable(mMediator); } @@ -170,14 +179,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { listener.verify(); } - @Test - public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception { - visibleBgUserCannotBeStartedOnDefaultDisplayTest(); - - assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID); - } - - protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception { + protected final @UserIdInt int visibleBgUserCannotBeStartedOnDefaultDisplayTest() + throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG_VISIBLE, @@ -188,6 +191,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { expectNoDisplayAssignedToUser(USER_ID); listener.verify(); + + return USER_ID; } @Test @@ -504,7 +509,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { } protected void assertStartUserResult(int actualResult, int expectedResult) { - assertWithMessage("startUser() result (where %s=%s and %s=%s)", + assertStartUserResult(actualResult, expectedResult, ""); + } + + @SuppressWarnings("AnnotateFormatMethod") + protected void assertStartUserResult(int actualResult, int expectedResult, + String extraMessageFormat, Object... extraMessageArguments) { + String extraMessage = String.format(extraMessageFormat, extraMessageArguments); + assertWithMessage("startUser() result %s(where %s=%s and %s=%s)", extraMessage, expectedResult, userAssignmentResultToString(expectedResult), actualResult, userAssignmentResultToString(actualResult)) .that(actualResult).isEqualTo(expectedResult); 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 627553bcfa185..49c6a8854c49a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java @@ -38,9 +38,9 @@ import org.junit.Test; abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase extends UserVisibilityMediatorTestCase { - UserVisibilityMediatorVisibleBackgroundUserTestCase(boolean backgroundUsersOnDisplaysEnabled) - throws Exception { - super(backgroundUsersOnDisplaysEnabled); + UserVisibilityMediatorVisibleBackgroundUserTestCase(boolean backgroundUsersOnDisplaysEnabled, + boolean backgroundUserOnDefaultDisplayAllowed) throws Exception { + super(backgroundUsersOnDisplaysEnabled, backgroundUserOnDefaultDisplayAllowed); } @Test