1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.pm;
17 
18 import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID;
19 import static android.os.UserHandle.USER_NULL;
20 import static android.os.UserHandle.USER_SYSTEM;
21 import static android.view.Display.DEFAULT_DISPLAY;
22 import static android.view.Display.INVALID_DISPLAY;
23 
24 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
25 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE;
26 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
27 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
28 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND;
29 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_BACKGROUND_VISIBLE;
30 import static com.android.server.pm.UserManagerInternal.USER_START_MODE_FOREGROUND;
31 import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
32 import static com.android.server.pm.UserManagerInternal.userStartModeToString;
33 
34 import android.annotation.IntDef;
35 import android.annotation.Nullable;
36 import android.annotation.UserIdInt;
37 import android.os.Handler;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.util.DebugUtils;
41 import android.util.Dumpable;
42 import android.util.EventLog;
43 import android.util.IndentingPrintWriter;
44 import android.util.IntArray;
45 import android.util.Log;
46 import android.util.SparseIntArray;
47 import android.view.Display;
48 
49 import com.android.internal.annotations.GuardedBy;
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.util.Preconditions;
52 import com.android.server.am.EventLogTags;
53 import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
54 import com.android.server.pm.UserManagerInternal.UserStartMode;
55 import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
56 import com.android.server.utils.Slogf;
57 
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.concurrent.CopyOnWriteArrayList;
62 
63 /**
64  * Class responsible for deciding whether a user is visible (or visible for a given display).
65  *
66  * <p>Currently, it has 3 "modes" (set on constructor), which defines the class behavior (i.e, the
67  * logic that dictates the result of methods such as {@link #isUserVisible(int)} and
68  * {@link #isUserVisible(int, int)}):
69  *
70  * <ul>
71  *   <li>default (A.K.A {@code SUSD} - Single User on Single Display): this is the most common mode
72  *   (used by phones, tablets, foldables, cars with just cluster and driver displays, etc.),
73  *   where just the current foreground user and its profiles are visible; hence, most methods are
74  *   optimized to just check for the current user / profile. This mode is unit tested by
75  *   {@link com.android.server.pm.UserVisibilityMediatorSUSDTest} and CTS tested by
76  *   {@link android.multiuser.cts.UserVisibilityTest}.
77  *   <li>concurrent users (A.K.A. {@code MUMD} - Multiple Users on Multiple Displays): typically
78  *   used on automotive builds where the car has additional displays for passengers, it allows users
79  *   to be started in the background but visible on these displays; hence, it contains additional
80  *   maps to account for the visibility state. This mode is unit tested by
81  *   {@link com.android.server.pm.UserVisibilityMediatorMUMDTest} and CTS tested by
82  *   {@link android.multiuser.cts.UserVisibilityTest}.
83  *   <li>no driver (A.K.A. {@code MUPAND} - MUltiple PAssengers, No Driver): extension of the
84  *   previous mode and typically used on automotive builds where the car has additional displays for
85  *   passengers but uses a secondary Android system for the back passengers, so all "human" users
86  *   are started in the background (and the current foreground user is the system user), hence the
87  *   "no driver name". This mode is unit tested by
88  *   {@link com.android.server.pm.UserVisibilityMediatorMUPANDTest} and CTS tested by
89  *   {@link android.multiuser.cts.UserVisibilityVisibleBackgroundUsersOnDefaultDisplayTest}.
90  * </ul>
91  *
92  * <p>When you make changes in this class, you should run at least the 3 unit tests and
93  * {@link android.multiuser.cts.UserVisibilityTest} (which actually applies for all modes); for
94  * example, by calling {@code atest UserVisibilityMediatorSUSDTest UserVisibilityMediatorMUMDTest
95  * UserVisibilityMediatorMUPANDTest UserVisibilityTest}. Ideally, you should run the other 2 CTS
96  * tests as well (you can emulate these modes using {@code adb} commands; their javadoc provides
97  * instructions on how to do so).
98  *
99  * <p>This class is thread safe.
100  */
101 public final class UserVisibilityMediator implements Dumpable {
102 
103     private static final String TAG = UserVisibilityMediator.class.getSimpleName();
104 
105     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
106     private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
107 
108     private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_";
109     public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1;
110     public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2;
111     public static final int SECONDARY_DISPLAY_MAPPING_FAILED = -1;
112 
113     /**
114      * Whether a user / display assignment requires adding an entry to the
115      * {@code mUsersOnSecondaryDisplays} map.
116      */
117     @IntDef(flag = false, prefix = {PREFIX_SECONDARY_DISPLAY_MAPPING}, value = {
118             SECONDARY_DISPLAY_MAPPING_NEEDED,
119             SECONDARY_DISPLAY_MAPPING_NOT_NEEDED,
120             SECONDARY_DISPLAY_MAPPING_FAILED
121     })
122     public @interface SecondaryDisplayMappingStatus {}
123 
124     // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
125     @VisibleForTesting
126     static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM;
127 
128     private final Object mLock = new Object();
129 
130     private final boolean mVisibleBackgroundUsersEnabled;
131     private final boolean mVisibleBackgroundUserOnDefaultDisplayEnabled;
132 
133     @UserIdInt
134     @GuardedBy("mLock")
135     private int mCurrentUserId = INITIAL_CURRENT_USER_ID;
136 
137     /**
138      * Map of background users started visible on displays (key is user id, value is display id).
139      *
140      * <p>Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}.
141      */
142     @Nullable
143     @GuardedBy("mLock")
144     private final SparseIntArray mUsersAssignedToDisplayOnStart;
145 
146     /**
147      * Map of extra (i.e., not assigned on start, but by explicit calls to
148      * {@link #assignUserToExtraDisplay(int, int)}) displays assigned to user (key is display id,
149      * value is user id).
150      *
151      * <p>Only set when {@code mVisibleBackgroundUsersEnabled} is {@code true}.
152      */
153     @Nullable
154     @GuardedBy("mLock")
155     private final SparseIntArray mExtraDisplaysAssignedToUsers;
156 
157     /**
158      * Mapping of each user that started visible (key) to its profile group id (value).
159      *
160      * <p>It's used to determine not just if the user is visible, but also
161      * {@link #isProfile(int, int) if it's a profile}.
162      */
163     @GuardedBy("mLock")
164     private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray();
165 
166     /**
167      * List of profiles that have explicitly started invisible.
168      *
169      * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we
170      * don't care about autoboxing.
171      */
172     @GuardedBy("mLock")
173     @Nullable
174     private final List<Integer> mStartedInvisibleProfileUserIds;
175 
176     /**
177      * Handler user to call listeners
178      */
179     private final Handler mHandler;
180 
181     // @GuardedBy("mLock") - hold lock for writes, no lock necessary for simple reads
182     final CopyOnWriteArrayList<UserVisibilityListener> mListeners =
183             new CopyOnWriteArrayList<>();
184 
UserVisibilityMediator(Handler handler)185     UserVisibilityMediator(Handler handler) {
186         this(UserManager.isVisibleBackgroundUsersEnabled(),
187                 UserManager.isVisibleBackgroundUsersOnDefaultDisplayEnabled(), handler);
188     }
189 
190     @VisibleForTesting
UserVisibilityMediator(boolean visibleBackgroundUsersOnDisplaysEnabled, boolean visibleBackgroundUserOnDefaultDisplayEnabled, Handler handler)191     UserVisibilityMediator(boolean visibleBackgroundUsersOnDisplaysEnabled,
192             boolean visibleBackgroundUserOnDefaultDisplayEnabled, Handler handler) {
193         mVisibleBackgroundUsersEnabled = visibleBackgroundUsersOnDisplaysEnabled;
194         if (visibleBackgroundUserOnDefaultDisplayEnabled
195                 && !visibleBackgroundUsersOnDisplaysEnabled) {
196             throw new IllegalArgumentException("Cannot have "
197                     + "visibleBackgroundUserOnDefaultDisplayEnabled without "
198                     + "visibleBackgroundUsersOnDisplaysEnabled");
199         }
200         mVisibleBackgroundUserOnDefaultDisplayEnabled =
201                 visibleBackgroundUserOnDefaultDisplayEnabled;
202         if (mVisibleBackgroundUsersEnabled) {
203             mUsersAssignedToDisplayOnStart = new SparseIntArray();
204             mExtraDisplaysAssignedToUsers = new SparseIntArray();
205         } else {
206             mUsersAssignedToDisplayOnStart = null;
207             mExtraDisplaysAssignedToUsers = null;
208         }
209         mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null;
210         mHandler = handler;
211         // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
212         mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
213 
214         if (DBG) {
215             Slogf.i(TAG, "UserVisibilityMediator created with DBG on");
216         }
217     }
218 
219     /**
220      * See {@link UserManagerInternal#assignUserToDisplayOnStart(int, int, int, int)}.
221      */
assignUserToDisplayOnStart(@serIdInt int userId, @UserIdInt int unResolvedProfileGroupId, @UserStartMode int userStartMode, int displayId)222     public @UserAssignmentResult int assignUserToDisplayOnStart(@UserIdInt int userId,
223             @UserIdInt int unResolvedProfileGroupId, @UserStartMode int userStartMode,
224             int displayId) {
225         Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d",
226                 userId);
227         validateUserStartMode(userStartMode);
228 
229         // This method needs to perform 4 actions:
230         //
231         // 1. Check if the user can be started given the provided arguments
232         // 2. If it can, decide whether it's visible or not (which is the return value)
233         // 3. Update the current user / profiles state
234         // 4. Update the users on secondary display state (if applicable)
235         //
236         // Notice that steps 3 and 4 should be done atomically (i.e., while holding mLock), so the
237         // previous steps are delegated to other methods (canAssignUserToDisplayLocked() and
238         // getUserVisibilityOnStartLocked() respectively).
239 
240 
241         int profileGroupId = unResolvedProfileGroupId == NO_PROFILE_GROUP_ID
242                 ? userId
243                 : unResolvedProfileGroupId;
244         if (DBG) {
245             Slogf.d(TAG, "assignUserToDisplayOnStart(%d, %d, %s, %d): actualProfileGroupId=%d",
246                     userId, unResolvedProfileGroupId, userStartModeToString(userStartMode),
247                     displayId, profileGroupId);
248         }
249 
250         int result;
251         IntArray visibleUsersBefore, visibleUsersAfter;
252         synchronized (mLock) {
253             result = getUserVisibilityOnStartLocked(userId, profileGroupId, userStartMode,
254                     displayId);
255             if (DBG) {
256                 Slogf.d(TAG, "result of getUserVisibilityOnStartLocked(%s)",
257                         userAssignmentResultToString(result));
258             }
259             if (result == USER_ASSIGNMENT_RESULT_FAILURE
260                     || result == USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE) {
261                 return result;
262             }
263 
264             int mappingResult = canAssignUserToDisplayLocked(userId, profileGroupId, userStartMode,
265                     displayId);
266             if (DBG) {
267                 Slogf.d(TAG, "mapping result: %s",
268                         secondaryDisplayMappingStatusToString(mappingResult));
269             }
270             if (mappingResult == SECONDARY_DISPLAY_MAPPING_FAILED) {
271                 return USER_ASSIGNMENT_RESULT_FAILURE;
272             }
273 
274             visibleUsersBefore = getVisibleUsers();
275 
276             // Set current user / started users state
277             switch (userStartMode) {
278                 case USER_START_MODE_FOREGROUND:
279                     mCurrentUserId = userId;
280                     // Fallthrough
281                 case USER_START_MODE_BACKGROUND_VISIBLE:
282                     if (DBG) {
283                         Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)",
284                                 userId, profileGroupId);
285                     }
286                     mStartedVisibleProfileGroupIds.put(userId, profileGroupId);
287                     break;
288                 case USER_START_MODE_BACKGROUND:
289                     if (mStartedInvisibleProfileUserIds != null
290                             && isProfile(userId, profileGroupId)) {
291                         Slogf.d(TAG, "adding user %d to list of invisible profiles", userId);
292                         mStartedInvisibleProfileUserIds.add(userId);
293                     }
294                     break;
295                 default:
296                     Slogf.wtf(TAG,  "invalid userStartMode passed to assignUserToDisplayOnStart: "
297                             + "%d", userStartMode);
298             }
299 
300             //  Set user / display state
301             switch (mappingResult) {
302                 case SECONDARY_DISPLAY_MAPPING_NEEDED:
303                     if (DBG) {
304                         Slogf.d(TAG, "adding user / display mapping (%d -> %d)", userId, displayId);
305                     }
306                     mUsersAssignedToDisplayOnStart.put(userId, displayId);
307                     break;
308                 case SECONDARY_DISPLAY_MAPPING_NOT_NEEDED:
309                     if (DBG) {
310                         // Don't need to do set state because methods (such as isUserVisible())
311                         // already know that the current user (and their profiles) is assigned to
312                         // the default display.
313                         Slogf.d(TAG, "don't need to update mUsersOnSecondaryDisplays");
314                     }
315                     break;
316                 default:
317                     Slogf.wtf(TAG,  "invalid resut from canAssignUserToDisplayLocked: %d",
318                             mappingResult);
319             }
320 
321             visibleUsersAfter = getVisibleUsers();
322         }
323 
324         dispatchVisibilityChanged(visibleUsersBefore, visibleUsersAfter);
325 
326         if (DBG) {
327             Slogf.d(TAG, "returning %s", userAssignmentResultToString(result));
328         }
329 
330         return result;
331     }
332 
333     @GuardedBy("mLock")
334     @UserAssignmentResult
getUserVisibilityOnStartLocked(@serIdInt int userId, @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId)335     private int getUserVisibilityOnStartLocked(@UserIdInt int userId, @UserIdInt int profileGroupId,
336             @UserStartMode int userStartMode, int displayId) {
337 
338         // Check for invalid combinations first
339         if (userStartMode == USER_START_MODE_BACKGROUND && displayId != DEFAULT_DISPLAY) {
340             Slogf.wtf(TAG, "cannot start user (%d) as BACKGROUND_USER on secondary display (%d) "
341                     + "(it should be BACKGROUND_USER_VISIBLE", userId, displayId);
342             return USER_ASSIGNMENT_RESULT_FAILURE;
343         }
344 
345         boolean visibleBackground = userStartMode == USER_START_MODE_BACKGROUND_VISIBLE;
346         if (displayId == DEFAULT_DISPLAY && visibleBackground) {
347             if (mVisibleBackgroundUserOnDefaultDisplayEnabled && isCurrentUserLocked(userId)) {
348                 // Shouldn't happen - UserController returns before calling this method
349                 Slogf.wtf(TAG, "trying to start current user (%d) visible in background on default"
350                         + " display", userId);
351                 return USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE;
352 
353             }
354             if (!mVisibleBackgroundUserOnDefaultDisplayEnabled
355                     && !isProfile(userId, profileGroupId)) {
356                 Slogf.wtf(TAG, "cannot start full user (%d) visible on default display", userId);
357                 return USER_ASSIGNMENT_RESULT_FAILURE;
358             }
359         }
360 
361         boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
362         if (displayId != DEFAULT_DISPLAY) {
363             if (foreground) {
364                 Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start "
365                         + "foreground user on secondary display", userId, profileGroupId,
366                         userStartModeToString(userStartMode), displayId);
367                 return USER_ASSIGNMENT_RESULT_FAILURE;
368             }
369             if (!mVisibleBackgroundUsersEnabled) {
370                 Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on "
371                         + "device that doesn't support multiple users on multiple displays",
372                         userId, profileGroupId, userStartModeToString(userStartMode), displayId);
373                 return USER_ASSIGNMENT_RESULT_FAILURE;
374             }
375         }
376 
377         if (isProfile(userId, profileGroupId)) {
378             if (displayId != DEFAULT_DISPLAY) {
379                 Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user "
380                         + "on secondary display", userId, profileGroupId,
381                         userStartModeToString(userStartMode), displayId);
382                 return USER_ASSIGNMENT_RESULT_FAILURE;
383             }
384             switch (userStartMode) {
385                 case USER_START_MODE_FOREGROUND:
386                     Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in "
387                             + "foreground", userId, profileGroupId,
388                             userStartModeToString(userStartMode), displayId);
389                     return USER_ASSIGNMENT_RESULT_FAILURE;
390                 case USER_START_MODE_BACKGROUND_VISIBLE:
391                     boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
392                     if (!isParentVisibleOnDisplay) {
393                         Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot"
394                                 + " start profile user visible when its parent is not visible in "
395                                 + "that display", userId, profileGroupId,
396                                 userStartModeToString(userStartMode), displayId);
397                         return USER_ASSIGNMENT_RESULT_FAILURE;
398                     }
399                     return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
400                 case USER_START_MODE_BACKGROUND:
401                     return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
402             }
403         } else if (mUsersAssignedToDisplayOnStart != null
404                 && isUserAssignedToDisplayOnStartLocked(userId, displayId)) {
405             if (DBG) {
406                 Slogf.d(TAG, "full user %d is already visible on display %d", userId, displayId);
407             }
408             return USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE;
409         }
410 
411         return foreground || displayId != DEFAULT_DISPLAY
412                 || (visibleBackground && mVisibleBackgroundUserOnDefaultDisplayEnabled)
413                         ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE
414                         : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
415     }
416 
417     @GuardedBy("mLock")
418     @SecondaryDisplayMappingStatus
canAssignUserToDisplayLocked(@serIdInt int userId, @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId)419     private int canAssignUserToDisplayLocked(@UserIdInt int userId,
420             @UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId) {
421         if (displayId == DEFAULT_DISPLAY) {
422             boolean mappingNeeded = false;
423             if (mVisibleBackgroundUserOnDefaultDisplayEnabled
424                     && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) {
425                 int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY);
426                 if (userStartedOnDefaultDisplay != USER_NULL
427                         && userStartedOnDefaultDisplay != profileGroupId) {
428                     Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on"
429                             + " default display because user %d already did so", userId,
430                             userStartedOnDefaultDisplay);
431                     return SECONDARY_DISPLAY_MAPPING_FAILED;
432                 }
433                 mappingNeeded = true;
434             }
435             if (!mappingNeeded && mVisibleBackgroundUsersEnabled
436                     && isProfile(userId, profileGroupId)) {
437                 mappingNeeded = true;
438             }
439 
440             if (!mappingNeeded) {
441                 // Don't need to do anything because methods (such as isUserVisible()) already
442                 // know that the current user (and its profiles) is assigned to the default display.
443                 // But on MUMD devices, profiles are only supported in the default display, so it
444                 // cannot return yet as it needs to check if the parent is also assigned to the
445                 // DEFAULT_DISPLAY (this is done indirectly below when it checks that the profile
446                 // parent is the current user, as the current user is always assigned to the
447                 // DEFAULT_DISPLAY).
448                 if (DBG) {
449                     Slogf.d(TAG, "Ignoring mapping for default display for user %d starting as %s",
450                             userId, userStartModeToString(userStartMode));
451                 }
452                 return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED;
453             }
454         }
455 
456         if (userId == UserHandle.USER_SYSTEM) {
457             Slogf.w(TAG, "Cannot assign system user to secondary display (%d)", displayId);
458             return SECONDARY_DISPLAY_MAPPING_FAILED;
459         }
460         if (displayId == Display.INVALID_DISPLAY) {
461             Slogf.w(TAG, "Cannot assign to INVALID_DISPLAY (%d)", displayId);
462             return SECONDARY_DISPLAY_MAPPING_FAILED;
463         }
464         if (userId == mCurrentUserId) {
465             Slogf.w(TAG, "Cannot assign current user (%d) to other displays", userId);
466             return SECONDARY_DISPLAY_MAPPING_FAILED;
467         }
468 
469         if (isProfile(userId, profileGroupId)) {
470             // Profile can only start in the same display as parent. And for simplicity,
471             // that display must be the DEFAULT_DISPLAY.
472             if (displayId != Display.DEFAULT_DISPLAY) {
473                 Slogf.w(TAG, "Profile user can only be started in the default display");
474                 return SECONDARY_DISPLAY_MAPPING_FAILED;
475 
476             }
477             if (DBG) {
478                 Slogf.d(TAG, "Don't need to map profile user %d to default display", userId);
479             }
480             return SECONDARY_DISPLAY_MAPPING_NOT_NEEDED;
481         }
482 
483         if (mUsersAssignedToDisplayOnStart == null) {
484             // Should never have reached this point
485             Slogf.wtf(TAG, "canAssignUserToDisplayLocked(%d, %d, %d, %d) is trying to check "
486                     + "mUsersAssignedToDisplayOnStart when it's not set",
487                     userId, profileGroupId, userStartMode, displayId);
488             return SECONDARY_DISPLAY_MAPPING_FAILED;
489         }
490 
491         // Check if display is available and user is not assigned to any display
492         for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
493             int assignedUserId = mUsersAssignedToDisplayOnStart.keyAt(i);
494             int assignedDisplayId = mUsersAssignedToDisplayOnStart.valueAt(i);
495             if (DBG) {
496                 Slogf.d(TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
497                         i, assignedUserId, assignedDisplayId);
498             }
499             if (displayId == assignedDisplayId) {
500                 Slogf.w(TAG, "Cannot assign user %d to display %d because such display is already "
501                         + "assigned to user %d", userId, displayId, assignedUserId);
502                 return SECONDARY_DISPLAY_MAPPING_FAILED;
503             }
504             if (userId == assignedUserId) {
505                 Slogf.w(TAG, "Cannot assign user %d to display %d because such user is as already "
506                         + "assigned to display %d", userId, displayId, assignedUserId);
507                 return SECONDARY_DISPLAY_MAPPING_FAILED;
508             }
509         }
510         return SECONDARY_DISPLAY_MAPPING_NEEDED;
511     }
512 
513     /**
514      * See {@link UserManagerInternal#assignUserToExtraDisplay(int, int)}.
515      */
assignUserToExtraDisplay(@serIdInt int userId, int displayId)516     public boolean assignUserToExtraDisplay(@UserIdInt int userId, int displayId) {
517         if (DBG) {
518             Slogf.d(TAG, "assignUserToExtraDisplay(%d, %d)", userId, displayId);
519         }
520         if (!mVisibleBackgroundUsersEnabled) {
521             Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called when not supported", userId,
522                     displayId);
523             return false;
524         }
525         if (displayId == INVALID_DISPLAY) {
526             Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called with INVALID_DISPLAY", userId,
527                     displayId);
528             return false;
529         }
530         if (displayId == DEFAULT_DISPLAY) {
531             Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): DEFAULT_DISPLAY is automatically "
532                     + "assigned to current user", userId, displayId);
533             return false;
534         }
535 
536         synchronized (mLock) {
537             if (!isUserVisible(userId)) {
538                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is not visible",
539                         userId, displayId);
540                 return false;
541             }
542             if (isStartedVisibleProfileLocked(userId)) {
543                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
544                         userId, displayId);
545                 return false;
546             }
547 
548             if (mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId) {
549                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is already "
550                         + "assigned to that display", userId, displayId);
551                 return false;
552             }
553 
554             // First check if the user started on display
555             int userAssignedToDisplay = getUserStartedOnDisplay(displayId);
556             if (userAssignedToDisplay != USER_NULL) {
557                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because display was assigned"
558                         + " to user %d on start", userId, displayId, userAssignedToDisplay);
559                 return false;
560             }
561             // Then if was assigned extra
562             userAssignedToDisplay = mExtraDisplaysAssignedToUsers.get(userId, USER_NULL);
563             if (userAssignedToDisplay != USER_NULL) {
564                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user %d was already "
565                         + "assigned that extra display", userId, displayId, userAssignedToDisplay);
566                 return false;
567             }
568             if (DBG) {
569                 Slogf.d(TAG, "addding %d -> %d to mExtraDisplaysAssignedToUsers", displayId,
570                         userId);
571             }
572             mExtraDisplaysAssignedToUsers.put(displayId, userId);
573         }
574         return true;
575     }
576 
577     /**
578      * See {@link UserManagerInternal#unassignUserFromExtraDisplay(int, int)}.
579      */
unassignUserFromExtraDisplay(@serIdInt int userId, int displayId)580     public boolean unassignUserFromExtraDisplay(@UserIdInt int userId, int displayId) {
581         if (DBG) {
582             Slogf.d(TAG, "unassignUserFromExtraDisplay(%d, %d)", userId, displayId);
583         }
584         if (!mVisibleBackgroundUsersEnabled) {
585             Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): called when not supported",
586                     userId, displayId);
587             return false;
588         }
589         synchronized (mLock) {
590             int assignedUserId = mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL);
591             if (assignedUserId == USER_NULL) {
592                 Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): not assigned to any user",
593                         userId, displayId);
594                 return false;
595             }
596             if (assignedUserId != userId) {
597                 Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): was assigned to user %d",
598                         userId, displayId, assignedUserId);
599                 return false;
600             }
601             if (DBG) {
602                 Slogf.d(TAG, "removing %d from map", displayId);
603             }
604             mExtraDisplaysAssignedToUsers.delete(displayId);
605         }
606         return true;
607     }
608 
609     /**
610      * See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}.
611      */
unassignUserFromDisplayOnStop(@serIdInt int userId)612     public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
613         if (DBG) {
614             Slogf.d(TAG, "unassignUserFromDisplayOnStop(%d)", userId);
615         }
616         IntArray visibleUsersBefore, visibleUsersAfter;
617         synchronized (mLock) {
618             visibleUsersBefore = getVisibleUsers();
619 
620             unassignUserFromAllDisplaysOnStopLocked(userId);
621 
622             visibleUsersAfter = getVisibleUsers();
623         }
624         dispatchVisibilityChanged(visibleUsersBefore, visibleUsersAfter);
625     }
626 
627     @GuardedBy("mLock")
unassignUserFromAllDisplaysOnStopLocked(@serIdInt int userId)628     private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
629         if (DBG) {
630             Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId,
631                     mStartedVisibleProfileGroupIds);
632         }
633         mStartedVisibleProfileGroupIds.delete(userId);
634         if (mStartedInvisibleProfileUserIds != null) {
635             Slogf.d(TAG, "Removing %d from list of invisible profiles", userId);
636             mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId));
637         }
638 
639         if (!mVisibleBackgroundUsersEnabled) {
640             // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as
641             // isUserVisible()) already know that the current user (and their profiles) is
642             // assigned to the default display.
643             return;
644         }
645         if (DBG) {
646             Slogf.d(TAG, "Removing user %d from mUsersOnDisplaysMap (%s)", userId,
647                     mUsersAssignedToDisplayOnStart);
648         }
649         mUsersAssignedToDisplayOnStart.delete(userId);
650 
651         // Remove extra displays as well
652         for (int i = mExtraDisplaysAssignedToUsers.size() - 1; i >= 0; i--) {
653             if (mExtraDisplaysAssignedToUsers.valueAt(i) == userId) {
654                 if (DBG) {
655                     Slogf.d(TAG, "Removing display %d from mExtraDisplaysAssignedToUsers (%s)",
656                             mExtraDisplaysAssignedToUsers.keyAt(i), mExtraDisplaysAssignedToUsers);
657                 }
658                 mExtraDisplaysAssignedToUsers.removeAt(i);
659             }
660         }
661     }
662 
663     /**
664      * See {@link UserManagerInternal#isUserVisible(int)}.
665      */
isUserVisible(@serIdInt int userId)666     public boolean isUserVisible(@UserIdInt int userId) {
667         // For optimization (as most devices don't support visible background users), check for
668         // current foreground user and their profiles first
669         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
670             if (VERBOSE) {
671                 Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
672             }
673             return true;
674         }
675 
676         if (!mVisibleBackgroundUsersEnabled) {
677             if (VERBOSE) {
678                 Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
679                         + " device doesn't support visible background users", userId);
680             }
681             return false;
682         }
683 
684 
685         synchronized (mLock) {
686             int profileGroupId;
687             synchronized (mLock) {
688                 profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
689             }
690             if (isProfile(userId, profileGroupId)) {
691                 return isUserAssignedToDisplayOnStartLocked(profileGroupId);
692             }
693             return isUserAssignedToDisplayOnStartLocked(userId);
694         }
695     }
696 
697     @GuardedBy("mLock")
isUserAssignedToDisplayOnStartLocked(@serIdInt int userId)698     private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) {
699         boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
700         if (VERBOSE) {
701             Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible);
702         }
703         return visible;
704     }
705 
706     @GuardedBy("mLock")
isUserAssignedToDisplayOnStartLocked(@serIdInt int userId, int displayId)707     private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId, int displayId) {
708         if (mUsersAssignedToDisplayOnStart == null) {
709             // Shouldn't have been called in this case
710             Slogf.wtf(TAG, "isUserAssignedToDisplayOnStartLocked(%d, %d): called when "
711                     + "mUsersAssignedToDisplayOnStart is null", userId, displayId);
712             return false;
713         }
714         boolean isIt = displayId != INVALID_DISPLAY
715                 && mUsersAssignedToDisplayOnStart.get(userId, INVALID_DISPLAY) == displayId;
716         if (VERBOSE) {
717             Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d, %d): %b", userId, displayId,
718                     isIt);
719         }
720         return isIt;
721     }
722 
723     /**
724      * See {@link UserManagerInternal#isUserVisible(int, int)}.
725      */
isUserVisible(@serIdInt int userId, int displayId)726     public boolean isUserVisible(@UserIdInt int userId, int displayId) {
727         if (displayId == INVALID_DISPLAY) {
728             return false;
729         }
730 
731         // For optimization (as most devices don't support visible background users), check for
732         // current user and profile first. Current user is always visible on:
733         // - Default display
734         // - Secondary displays when device doesn't support visible bg users
735         //   - Or when explicitly added (which is checked below)
736         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)
737                 && (displayId == DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) {
738             if (VERBOSE) {
739                 Slogf.v(TAG, "isUserVisible(%d, %d): returning true for current user/profile",
740                         userId, displayId);
741             }
742             return true;
743         }
744 
745         if (!mVisibleBackgroundUsersEnabled) {
746             if (DBG) {
747                 Slogf.d(TAG, "isUserVisible(%d, %d): returning false as device does not support"
748                         + " visible background users", userId, displayId);
749             }
750             return false;
751         }
752 
753         synchronized (mLock) {
754             int profileGroupId;
755             synchronized (mLock) {
756                 profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
757             }
758             if (isProfile(userId, profileGroupId)) {
759                 return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
760             }
761             return isFullUserVisibleOnBackgroundLocked(userId, displayId);
762         }
763     }
764 
765     // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that
766     @GuardedBy("mLock")
isFullUserVisibleOnBackgroundLocked(@serIdInt int userId, int displayId)767     private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) {
768         if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
769             // User assigned to display on start
770             return true;
771         }
772         // Check for extra display assignment
773         return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
774     }
775 
776     /**
777      * See {@link UserManagerInternal#getMainDisplayAssignedToUser(int)}.
778      */
getMainDisplayAssignedToUser(@serIdInt int userId)779     public int getMainDisplayAssignedToUser(@UserIdInt int userId) {
780         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
781             if (mVisibleBackgroundUserOnDefaultDisplayEnabled) {
782                 // When device supports visible bg users on default display, the default display is
783                 // assigned to the current user, unless a user is started visible on it
784                 int userStartedOnDefaultDisplay;
785                 synchronized (mLock) {
786                     userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY);
787                 }
788                 if (userStartedOnDefaultDisplay != USER_NULL) {
789                     if (DBG) {
790                         Slogf.d(TAG, "getMainDisplayAssignedToUser(%d): returning INVALID_DISPLAY "
791                                         + "for current user user %d was started on DEFAULT_DISPLAY",
792                                 userId, userStartedOnDefaultDisplay);
793                     }
794                     return INVALID_DISPLAY;
795                 }
796             }
797             return DEFAULT_DISPLAY;
798         }
799 
800         if (!mVisibleBackgroundUsersEnabled) {
801             return INVALID_DISPLAY;
802         }
803 
804         synchronized (mLock) {
805             return mUsersAssignedToDisplayOnStart.get(userId, INVALID_DISPLAY);
806         }
807     }
808 
809     /** See {@link UserManagerInternal#getDisplaysAssignedToUser(int)}. */
810     @Nullable
getDisplaysAssignedToUser(@serIdInt int userId)811     public int[] getDisplaysAssignedToUser(@UserIdInt int userId) {
812         int mainDisplayId = getMainDisplayAssignedToUser(userId);
813         if (mainDisplayId == INVALID_DISPLAY) {
814             // The user will not have any extra displays if they have no main display.
815             // Return null if no display is assigned to the user.
816             if (DBG) {
817                 Slogf.d(TAG, "getDisplaysAssignedToUser(): returning null"
818                         + " because there is no display assigned to user %d", userId);
819             }
820             return null;
821         }
822 
823         synchronized (mLock) {
824             if (mExtraDisplaysAssignedToUsers == null
825                     || mExtraDisplaysAssignedToUsers.size() == 0) {
826                 return new int[]{mainDisplayId};
827             }
828 
829             int count = 0;
830             int[] displayIds = new int[mExtraDisplaysAssignedToUsers.size() + 1];
831             displayIds[count++] = mainDisplayId;
832             for (int i = 0; i < mExtraDisplaysAssignedToUsers.size(); ++i) {
833                 if (mExtraDisplaysAssignedToUsers.valueAt(i) == userId) {
834                     displayIds[count++] = mExtraDisplaysAssignedToUsers.keyAt(i);
835                 }
836             }
837             // Return the array if the array length happens to be correct.
838             if (displayIds.length == count) {
839                 return displayIds;
840             }
841 
842             // Copy the results to a new array with the exact length. The size of displayIds[] is
843             // initialized to `1 + mExtraDisplaysAssignedToUsers.size()`, which is usually larger
844             // than the actual length, because mExtraDisplaysAssignedToUsers contains displayIds for
845             // other users. Therefore, we need to copy to a new array with the correct length.
846             int[] results = new int[count];
847             System.arraycopy(displayIds, 0, results, 0, count);
848             return results;
849         }
850     }
851 
852     /**
853      * See {@link UserManagerInternal#getUserAssignedToDisplay(int)}.
854      */
getUserAssignedToDisplay(@serIdInt int displayId)855     public @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId) {
856         return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ true);
857     }
858 
859     /**
860      * Gets the user explicitly assigned to a display.
861      */
getUserStartedOnDisplay(@serIdInt int displayId)862     private @UserIdInt int getUserStartedOnDisplay(@UserIdInt int displayId) {
863         return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ false);
864     }
865 
866     /**
867      * Gets the user explicitly assigned to a display, or the current user when no user is assigned
868      * to it (and {@code returnCurrentUserByDefault} is {@code true}).
869      */
getUserAssignedToDisplay(@serIdInt int displayId, boolean returnCurrentUserByDefault)870     private @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId,
871             boolean returnCurrentUserByDefault) {
872         if (returnCurrentUserByDefault
873                 && ((displayId == DEFAULT_DISPLAY && !mVisibleBackgroundUserOnDefaultDisplayEnabled
874                 || !mVisibleBackgroundUsersEnabled))) {
875             return getCurrentUserId();
876         }
877 
878         synchronized (mLock) {
879             for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
880                 if (mUsersAssignedToDisplayOnStart.valueAt(i) != displayId) {
881                     continue;
882                 }
883                 int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
884                 if (!isStartedVisibleProfileLocked(userId)) {
885                     return userId;
886                 } else if (DBG) {
887                     Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
888                             + "a profile", displayId, userId);
889                 }
890             }
891         }
892         if (!returnCurrentUserByDefault) {
893             if (DBG) {
894                 Slogf.d(TAG, "getUserAssignedToDisplay(%d): no user assigned to display, returning "
895                         + "USER_NULL instead", displayId);
896             }
897             return USER_NULL;
898         }
899 
900         int currentUserId = getCurrentUserId();
901         if (DBG) {
902             Slogf.d(TAG, "getUserAssignedToDisplay(%d): no user assigned to display, returning "
903                     + "current user (%d) instead", displayId, currentUserId);
904         }
905         return currentUserId;
906     }
907 
908     /**
909      * Gets the ids of the visible users.
910      */
getVisibleUsers()911     public IntArray getVisibleUsers() {
912         // TODO(b/258054362): this method's performance is O(n2), as it interacts through all users
913         // here, then again on isUserVisible(). We could "fix" it to be O(n), but given that the
914         // number of users is too small, the gain is probably not worth the increase on complexity.
915         IntArray visibleUsers = new IntArray();
916         synchronized (mLock) {
917             for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) {
918                 int userId = mStartedVisibleProfileGroupIds.keyAt(i);
919                 if (isUserVisible(userId)) {
920                     visibleUsers.add(userId);
921                 }
922             }
923         }
924         return visibleUsers;
925     }
926 
927     /**
928      * Adds a {@link UserVisibilityListener listener}.
929      */
addListener(UserVisibilityListener listener)930     public void addListener(UserVisibilityListener listener) {
931         if (DBG) {
932             Slogf.d(TAG, "adding listener %s", listener);
933         }
934         synchronized (mLock) {
935             mListeners.add(listener);
936         }
937     }
938 
939     /**
940      * Removes a {@link UserVisibilityListener listener}.
941      */
removeListener(UserVisibilityListener listener)942     public void removeListener(UserVisibilityListener listener) {
943         if (DBG) {
944             Slogf.d(TAG, "removing listener %s", listener);
945         }
946         synchronized (mLock) {
947             mListeners.remove(listener);
948         }
949     }
950 
951     // TODO(b/266158156): remove this method if not needed anymore
952     /**
953      * Nofify all listeners that the system user visibility changed.
954      */
onSystemUserVisibilityChanged(boolean visible)955     void onSystemUserVisibilityChanged(boolean visible) {
956         dispatchVisibilityChanged(mListeners, USER_SYSTEM, visible);
957     }
958 
959     /**
960      * Nofify all listeners about the visibility changes from before / after a change of state.
961      */
dispatchVisibilityChanged(IntArray visibleUsersBefore, IntArray visibleUsersAfter)962     private void dispatchVisibilityChanged(IntArray visibleUsersBefore,
963             IntArray visibleUsersAfter) {
964         if (visibleUsersBefore == null) {
965             // Optimization - it's only null when listeners is empty
966             if (DBG) {
967                 Slogf.d(TAG,  "dispatchVisibilityChanged(): ignoring, no listeners");
968             }
969             return;
970         }
971         CopyOnWriteArrayList<UserVisibilityListener> listeners = mListeners;
972         if (DBG) {
973             Slogf.d(TAG,
974                     "dispatchVisibilityChanged(): visibleUsersBefore=%s, visibleUsersAfter=%s, "
975                     + "%d listeners (%s)", visibleUsersBefore, visibleUsersAfter, listeners.size(),
976                     listeners);
977         }
978         for (int i = 0; i < visibleUsersBefore.size(); i++) {
979             int userId = visibleUsersBefore.get(i);
980             if (visibleUsersAfter.indexOf(userId) == -1) {
981                 dispatchVisibilityChanged(listeners, userId, /* visible= */ false);
982             }
983         }
984         for (int i = 0; i < visibleUsersAfter.size(); i++) {
985             int userId = visibleUsersAfter.get(i);
986             if (visibleUsersBefore.indexOf(userId) == -1) {
987                 dispatchVisibilityChanged(listeners, userId, /* visible= */ true);
988             }
989         }
990     }
991 
dispatchVisibilityChanged(CopyOnWriteArrayList<UserVisibilityListener> listeners, @UserIdInt int userId, boolean visible)992     private void dispatchVisibilityChanged(CopyOnWriteArrayList<UserVisibilityListener> listeners,
993             @UserIdInt int userId, boolean visible) {
994         EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
995         if (DBG) {
996             Slogf.d(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %d listeners",
997                     userId, visible, listeners.size());
998         }
999         for (int i = 0; i < mListeners.size(); i++) {
1000             UserVisibilityListener listener =  mListeners.get(i);
1001             if (VERBOSE) {
1002                 Slogf.v(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %s",
1003                         userId, visible, listener);
1004             }
1005             mHandler.post(() -> listener.onUserVisibilityChanged(userId, visible));
1006         }
1007     }
1008 
dump(IndentingPrintWriter ipw)1009     private void dump(IndentingPrintWriter ipw) {
1010         ipw.println("UserVisibilityMediator");
1011         ipw.increaseIndent();
1012 
1013         ipw.print("DBG: ");
1014         ipw.println(DBG);
1015 
1016         synchronized (mLock) {
1017             ipw.print("Current user id: ");
1018             ipw.println(mCurrentUserId);
1019 
1020             ipw.print("Visible users: ");
1021             ipw.println(getVisibleUsers());
1022 
1023             dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds,
1024                     "started visible user / profile group", "u", "pg");
1025             if (mStartedInvisibleProfileUserIds != null) {
1026                 ipw.print("Profiles started invisible: ");
1027                 ipw.println(mStartedInvisibleProfileUserIds);
1028             }
1029 
1030             ipw.print("Supports visible background users on displays: ");
1031             ipw.println(mVisibleBackgroundUsersEnabled);
1032 
1033             ipw.print("Supports visible background users on default display: ");
1034             ipw.println(mVisibleBackgroundUserOnDefaultDisplayEnabled);
1035 
1036             dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d");
1037             dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user",
1038                     "d", "u");
1039 
1040             int numberListeners = mListeners.size();
1041             ipw.print("Number of listeners: ");
1042             ipw.println(numberListeners);
1043             if (numberListeners > 0) {
1044                 ipw.increaseIndent();
1045                 for (int i = 0; i < numberListeners; i++) {
1046                     ipw.print(i);
1047                     ipw.print(": ");
1048                     ipw.println(mListeners.get(i));
1049                 }
1050                 ipw.decreaseIndent();
1051             }
1052         }
1053 
1054         ipw.decreaseIndent();
1055     }
1056 
dumpSparseIntArray(IndentingPrintWriter ipw, @Nullable SparseIntArray array, String arrayDescription, String keyName, String valueName)1057     private static void dumpSparseIntArray(IndentingPrintWriter ipw, @Nullable SparseIntArray array,
1058             String arrayDescription, String keyName, String valueName) {
1059         if (array == null) {
1060             ipw.print("No ");
1061             ipw.print(arrayDescription);
1062             ipw.println(" mappings");
1063             return;
1064         }
1065         ipw.print("Number of ");
1066         ipw.print(arrayDescription);
1067         ipw.print(" mappings: ");
1068         ipw.println(array.size());
1069         if (array.size() <= 0) {
1070             return;
1071         }
1072         ipw.increaseIndent();
1073         for (int i = 0; i < array.size(); i++) {
1074             ipw.print(keyName); ipw.print(':');
1075             ipw.print(array.keyAt(i));
1076             ipw.print(" -> ");
1077             ipw.print(valueName); ipw.print(':');
1078             ipw.println(array.valueAt(i));
1079         }
1080         ipw.decreaseIndent();
1081     }
1082 
1083     @Override
dump(PrintWriter pw, String[] args)1084     public void dump(PrintWriter pw, String[] args) {
1085         if (pw instanceof IndentingPrintWriter) {
1086             dump((IndentingPrintWriter) pw);
1087             return;
1088         }
1089         dump(new IndentingPrintWriter(pw));
1090     }
1091 
isSpecialUserId(@serIdInt int userId)1092     private static boolean isSpecialUserId(@UserIdInt int userId) {
1093         switch (userId) {
1094             case UserHandle.USER_ALL:
1095             case UserHandle.USER_CURRENT:
1096             case UserHandle.USER_CURRENT_OR_SELF:
1097             case UserHandle.USER_NULL:
1098                 return true;
1099             default:
1100                 return false;
1101         }
1102     }
1103 
isProfile(@serIdInt int userId, @UserIdInt int profileGroupId)1104     private static boolean isProfile(@UserIdInt int userId, @UserIdInt int profileGroupId) {
1105         return profileGroupId != NO_PROFILE_GROUP_ID && profileGroupId != userId;
1106     }
1107 
1108     // NOTE: methods below are needed because some APIs use the current users (full and profiles)
1109     // state to decide whether a user is visible or not. If we decide to always store that info into
1110     // mUsersOnSecondaryDisplays, we should remove them.
1111 
getCurrentUserId()1112     private @UserIdInt int getCurrentUserId() {
1113         synchronized (mLock) {
1114             return mCurrentUserId;
1115         }
1116     }
1117 
1118     @GuardedBy("mLock")
isCurrentUserLocked(@serIdInt int userId)1119     private boolean isCurrentUserLocked(@UserIdInt int userId) {
1120         // Special case as NO_PROFILE_GROUP_ID == USER_NULL
1121         if (userId == USER_NULL || mCurrentUserId == USER_NULL) {
1122             return false;
1123         }
1124         return mCurrentUserId == userId;
1125     }
1126 
isCurrentUserOrRunningProfileOfCurrentUser(@serIdInt int userId)1127     private boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) {
1128         synchronized (mLock) {
1129             // Special case as NO_PROFILE_GROUP_ID == USER_NULL
1130             if (userId == USER_NULL || mCurrentUserId == USER_NULL) {
1131                 return false;
1132             }
1133             if (mCurrentUserId == userId) {
1134                 return true;
1135             }
1136             return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID)
1137                     == mCurrentUserId;
1138         }
1139     }
1140 
1141     @GuardedBy("mLock")
isStartedVisibleProfileLocked(@serIdInt int userId)1142     private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) {
1143         int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
1144         return isProfile(userId, profileGroupId);
1145     }
1146 
validateUserStartMode(@serStartMode int userStartMode)1147     private void validateUserStartMode(@UserStartMode int userStartMode) {
1148         switch (userStartMode) {
1149             case USER_START_MODE_FOREGROUND:
1150             case USER_START_MODE_BACKGROUND:
1151             case USER_START_MODE_BACKGROUND_VISIBLE:
1152                 return;
1153         }
1154         throw new IllegalArgumentException("Invalid user start mode: " + userStartMode);
1155     }
1156 
secondaryDisplayMappingStatusToString( @econdaryDisplayMappingStatus int status)1157     private static String secondaryDisplayMappingStatusToString(
1158             @SecondaryDisplayMappingStatus int status) {
1159         return DebugUtils.constantToString(UserVisibilityMediator.class,
1160                 PREFIX_SECONDARY_DISPLAY_MAPPING, status);
1161     }
1162 }
1163