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