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