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