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