Revert "Revert "Fixed UserVisibilityMediator profile scenario.""
This reverts commit8b9cd55728, which in turn reverted commit6638c3c491, as the latter broke work profiles (they could not be created or enabled, as they wouldn't be visible); it's now safe to revert this CL as the underlying UMS and DPMS calls (which caused the breakage) were changed by commit fb7bb3f3d8d1bbbcb98ce2fca7c5fc2a093eff83. Anyways, here's the "real" description: 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 Test: manual verification with TestDpc (set a managed profile and used QS to turn it on / off) Bug: 261538337 Bug: 268198860 Change-Id: Ibf0c9aa62c8aaf938dbea27a486325c4b68ce5eb
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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 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
|
||||
@@ -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;
|
||||
// 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) {
|
||||
@@ -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,16 +725,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)}.
|
||||
*/
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -151,6 +150,12 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase {
|
||||
.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();
|
||||
@@ -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();
|
||||
}
|
||||
@@ -334,6 +339,41 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase {
|
||||
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();
|
||||
@@ -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) {
|
||||
|
||||
@@ -108,34 +108,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();
|
||||
@@ -300,15 +272,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