Fixed UserVisibilityMediator profile scenario.
A profile should not started visible when its parent is not visible. Also made some cosmetic improvements (like javadoc clarification and setting DBG dynamically). Test: atest UserVisibilityMediatorSUSDTest UserVisibilityMediatorMUMDTest UserVisibilityMediatorMUPANDTest Test: atest android.server.wm.StartActivityAsUserTests#startActivityAsValidUserWithOptions Bug: 261538337 Change-Id: Ib29d1230eb592eb2583fb7878acb2eb7b0c7cf73
This commit is contained in:
@@ -62,12 +62,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,
|
||||
@@ -75,6 +74,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.
|
||||
|
||||
@@ -41,6 +41,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;
|
||||
|
||||
@@ -54,6 +55,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;
|
||||
|
||||
/**
|
||||
@@ -76,11 +79,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;
|
||||
@@ -97,7 +100,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;
|
||||
|
||||
@@ -131,10 +134,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 mStartedProfileGroupIds = new SparseIntArray();
|
||||
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")
|
||||
@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
|
||||
@@ -223,14 +246,29 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
|
||||
visibleUsersBefore = getVisibleUsers();
|
||||
|
||||
// Set current user / profiles state
|
||||
if (userStartMode == USER_START_MODE_FOREGROUND) {
|
||||
mCurrentUserId = userId;
|
||||
// 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);
|
||||
}
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId);
|
||||
}
|
||||
mStartedProfileGroupIds.put(userId, profileGroupId);
|
||||
|
||||
// Set user / display state
|
||||
switch (mappingResult) {
|
||||
@@ -288,39 +326,46 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return foreground || displayId != DEFAULT_DISPLAY
|
||||
@@ -338,8 +383,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;
|
||||
@@ -445,7 +491,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;
|
||||
@@ -533,10 +579,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
|
||||
@@ -566,7 +616,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);
|
||||
@@ -575,19 +626,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;
|
||||
}
|
||||
@@ -600,7 +663,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)
|
||||
@@ -622,16 +686,28 @@ 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);
|
||||
}
|
||||
|
||||
// Check for extra display assignment
|
||||
return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
|
||||
if (isProfile(userId, profileGroupId)) {
|
||||
return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
|
||||
}
|
||||
return isFullUserVisibleOnBackgroundLocked(userId, displayId);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link UserManagerInternal#getDisplayAssignedToUser(int)}.
|
||||
*/
|
||||
@@ -697,7 +773,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 "
|
||||
@@ -730,8 +806,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);
|
||||
}
|
||||
@@ -764,7 +840,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.
|
||||
*/
|
||||
@@ -826,6 +902,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);
|
||||
@@ -833,8 +912,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);
|
||||
@@ -933,22 +1016,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(
|
||||
|
||||
@@ -20,6 +20,7 @@ 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_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 +74,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 +118,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);
|
||||
@@ -126,4 +127,60 @@ public final class UserVisibilityMediatorMUPANDTest
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBg()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onVisible(PARENT_USER_ID),
|
||||
onVisible(PROFILE_USER_ID));
|
||||
startUserInSecondaryDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
|
||||
BG_VISIBLE, DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
|
||||
|
||||
// Assert parent user visibility
|
||||
expectUserIsVisible(PARENT_USER_ID);
|
||||
expectUserIsVisibleOnDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, INVALID_DISPLAY);
|
||||
expectDisplayAssignedToUser(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
|
||||
assertUserCanBeAssignedExtraDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
|
||||
// Assert profile user visibility
|
||||
expectUserIsVisible(PROFILE_USER_ID);
|
||||
expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
|
||||
// Only full user (parent) is assigned to the display
|
||||
expectDisplayAssignedToUser(PROFILE_USER_ID, INVALID_DISPLAY);
|
||||
assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBg()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
|
||||
startUserInSecondaryDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
|
||||
|
||||
// Assert parent user visibility
|
||||
expectUserIsVisible(PARENT_USER_ID);
|
||||
expectUserIsVisibleOnDisplay(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, INVALID_DISPLAY);
|
||||
expectDisplayAssignedToUser(PARENT_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
|
||||
assertUserCanBeAssignedExtraDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
|
||||
// Assert profile user visibility
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
listener.verify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.ExtendedMockitoTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -148,6 +147,12 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
.assignUserToDisplayOnStart(USER_CURRENT_OR_SELF, USER_ID, FG, DEFAULT_DISPLAY));
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -283,7 +288,7 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
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);
|
||||
@@ -299,14 +304,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -331,6 +336,41 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -485,8 +525,6 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
* 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) {
|
||||
|
||||
@@ -107,34 +107,6 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -267,15 +239,84 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase
|
||||
listener2.verify();
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
Reference in New Issue
Block a user