1 /* 2 * Copyright (C) 2020 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.car.user; 17 18 import static android.car.userlib.UserHalHelper.userFlagsToString; 19 20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.UserIdInt; 26 import android.app.ActivityManager; 27 import android.app.IActivityManager; 28 import android.car.settings.CarSettings; 29 import android.car.userlib.UserHalHelper; 30 import android.content.Context; 31 import android.content.pm.UserInfo; 32 import android.hardware.automotive.vehicle.V2_0.UserFlags; 33 import android.os.RemoteException; 34 import android.os.Trace; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 import android.provider.Settings; 38 import android.sysprop.CarProperties; 39 import android.util.Pair; 40 import android.util.Slog; 41 import android.util.TimingsTraceLog; 42 43 import com.android.car.CarLog; 44 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 45 import com.android.car.internal.common.UserHelperLite; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.util.Preconditions; 48 import com.android.internal.widget.LockPatternUtils; 49 50 import java.io.PrintWriter; 51 import java.lang.annotation.Retention; 52 import java.lang.annotation.RetentionPolicy; 53 import java.util.ArrayList; 54 import java.util.Collections; 55 import java.util.Iterator; 56 import java.util.List; 57 import java.util.function.Consumer; 58 59 /** 60 * Helper used to set the initial Android user on boot or when resuming from RAM. 61 */ 62 final class InitialUserSetter { 63 64 private static final String TAG = CarLog.tagFor(InitialUserSetter.class); 65 66 private static final boolean DBG = false; 67 private static final int BOOT_USER_NOT_FOUND = -1; 68 69 /** 70 * Sets the initial user using the default behavior. 71 * 72 * <p>The default behavior is: 73 * 74 * <ol> 75 * <li>On first boot, it creates and switches to a new user. 76 * <li>Otherwise, it will switch to either: 77 * <ol> 78 * <li>User defined by {@code android.car.systemuser.bootuseroverrideid} (when it was 79 * constructed with such option enabled). 80 * <li>Last active user (as defined by 81 * {@link android.provider.Settings.Global.LAST_ACTIVE_USER_ID}. 82 * </ol> 83 * </ol> 84 */ 85 public static final int TYPE_DEFAULT_BEHAVIOR = 0; 86 87 /** 88 * Switches to the given user, falling back to {@link #fallbackDefaultBehavior(String)} if it 89 * fails. 90 */ 91 public static final int TYPE_SWITCH = 1; 92 93 /** 94 * Creates a new user and switches to it, falling back to 95 * {@link #fallbackDefaultBehavior(String) if any of these steps fails. 96 * 97 * @param name (optional) name of the new user 98 * @param halFlags user flags as defined by Vehicle HAL ({@code UserFlags} enum). 99 */ 100 public static final int TYPE_CREATE = 2; 101 102 /** 103 * Creates a new guest user and switches to it, if current user is unlocked guest user. 104 * Does not fallback if any of these steps fails. falling back to 105 * {@link #fallbackDefaultBehavior(String) if any of these steps fails 106 */ 107 public static final int TYPE_REPLACE_GUEST = 3; 108 109 @IntDef(prefix = { "TYPE_" }, value = { 110 TYPE_DEFAULT_BEHAVIOR, 111 TYPE_SWITCH, 112 TYPE_CREATE, 113 TYPE_REPLACE_GUEST 114 }) 115 @Retention(RetentionPolicy.SOURCE) 116 public @interface InitialUserInfoType { } 117 118 private final Context mContext; 119 120 // TODO(b/150413304): abstract AM / UM into interfaces, then provide local and remote 121 // implementation (where local is implemented by ActivityManagerInternal / UserManagerInternal) 122 private final UserManager mUm; 123 private final CarUserService mCarUserService; 124 private final LockPatternUtils mLockPatternUtils; 125 126 private final String mNewUserName; 127 private final String mNewGuestName; 128 129 private final Consumer<UserInfo> mListener; 130 InitialUserSetter(@onNull Context context, @NonNull CarUserService carUserService, @NonNull Consumer<UserInfo> listener)131 InitialUserSetter(@NonNull Context context, @NonNull CarUserService carUserService, 132 @NonNull Consumer<UserInfo> listener) { 133 this(context, carUserService, listener, /* newGuestName= */ null); 134 } 135 InitialUserSetter(@onNull Context context, @NonNull CarUserService carUserService, @NonNull Consumer<UserInfo> listener, @Nullable String newGuestName)136 InitialUserSetter(@NonNull Context context, @NonNull CarUserService carUserService, 137 @NonNull Consumer<UserInfo> listener, @Nullable String newGuestName) { 138 this(context, UserManager.get(context), carUserService, listener, 139 new LockPatternUtils(context), 140 context.getString(com.android.internal.R.string.owner_name), newGuestName); 141 } 142 143 @VisibleForTesting InitialUserSetter(@onNull Context context, @NonNull UserManager um, @NonNull CarUserService carUserService, @NonNull Consumer<UserInfo> listener, @NonNull LockPatternUtils lockPatternUtils, @Nullable String newUserName, @Nullable String newGuestName)144 InitialUserSetter(@NonNull Context context, @NonNull UserManager um, 145 @NonNull CarUserService carUserService, @NonNull Consumer<UserInfo> listener, 146 @NonNull LockPatternUtils lockPatternUtils, @Nullable String newUserName, 147 @Nullable String newGuestName) { 148 mContext = context; 149 mUm = um; 150 mCarUserService = carUserService; 151 mListener = listener; 152 mLockPatternUtils = lockPatternUtils; 153 mNewUserName = newUserName; 154 mNewGuestName = newGuestName; 155 } 156 157 /** 158 * Builder for {@link InitialUserInfo} objects. 159 * 160 */ 161 public static final class Builder { 162 163 private final @InitialUserInfoType int mType; 164 private boolean mReplaceGuest; 165 private @UserIdInt int mSwitchUserId; 166 private @Nullable String mNewUserName; 167 private int mNewUserFlags; 168 private boolean mSupportsOverrideUserIdProperty; 169 private @Nullable String mUserLocales; 170 171 /** 172 * Constructor for the given type. 173 * 174 * @param type {@link #TYPE_DEFAULT_BEHAVIOR}, {@link #TYPE_SWITCH}, 175 * {@link #TYPE_CREATE} or {@link #TYPE_REPLACE_GUEST}. 176 */ Builder(@nitialUserInfoType int type)177 public Builder(@InitialUserInfoType int type) { 178 Preconditions.checkArgument(type == TYPE_DEFAULT_BEHAVIOR || type == TYPE_SWITCH 179 || type == TYPE_CREATE || type == TYPE_REPLACE_GUEST, "invalid builder type"); 180 mType = type; 181 } 182 183 /** 184 * Sets the id of the user to be switched to. 185 * 186 * @throws IllegalArgumentException if builder is not for {@link #TYPE_SWITCH}. 187 */ 188 @NonNull setSwitchUserId(@serIdInt int userId)189 public Builder setSwitchUserId(@UserIdInt int userId) { 190 Preconditions.checkArgument(mType == TYPE_SWITCH, "invalid builder type: " + mType); 191 mSwitchUserId = userId; 192 return this; 193 } 194 195 /** 196 * Sets whether the current user should be replaced when it's a guest. 197 */ 198 @NonNull setReplaceGuest(boolean value)199 public Builder setReplaceGuest(boolean value) { 200 mReplaceGuest = value; 201 return this; 202 } 203 204 /** 205 * Sets the name of the new user being created. 206 * 207 * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}. 208 */ 209 @NonNull setNewUserName(@ullable String name)210 public Builder setNewUserName(@Nullable String name) { 211 Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType); 212 mNewUserName = name; 213 return this; 214 } 215 216 /** 217 * Sets the flags (as defined by {@link android.hardware.automotive.vehicle.V2_0.UserFlags}) 218 * of the new user being created. 219 * 220 * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}. 221 */ 222 @NonNull setNewUserFlags(int flags)223 public Builder setNewUserFlags(int flags) { 224 Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType); 225 mNewUserFlags = flags; 226 return this; 227 } 228 229 /** 230 * Sets whether the {@link CarProperties#boot_user_override_id()} should be taking in 231 * account when using the default behavior. 232 */ 233 @NonNull setSupportsOverrideUserIdProperty(boolean value)234 public Builder setSupportsOverrideUserIdProperty(boolean value) { 235 mSupportsOverrideUserIdProperty = value; 236 return this; 237 } 238 239 /** 240 * Sets the system locales for the initial user (when it's created). 241 */ 242 @NonNull setUserLocales(@ullable String userLocales)243 public Builder setUserLocales(@Nullable String userLocales) { 244 mUserLocales = userLocales; 245 return this; 246 } 247 248 /** 249 * Builds the object. 250 */ 251 @NonNull build()252 public InitialUserInfo build() { 253 return new InitialUserInfo(this); 254 } 255 } 256 257 /** 258 * Object used to define the properties of the initial user (which can then be set by 259 * {@link InitialUserSetter#set(InitialUserInfo)}); 260 */ 261 public static final class InitialUserInfo { 262 public final @InitialUserInfoType int type; 263 public final boolean replaceGuest; 264 public final @UserIdInt int switchUserId; 265 public final @Nullable String newUserName; 266 public final int newUserFlags; 267 public final boolean supportsOverrideUserIdProperty; 268 public @Nullable String userLocales; 269 InitialUserInfo(@onNull Builder builder)270 private InitialUserInfo(@NonNull Builder builder) { 271 type = builder.mType; 272 switchUserId = builder.mSwitchUserId; 273 replaceGuest = builder.mReplaceGuest; 274 newUserName = builder.mNewUserName; 275 newUserFlags = builder.mNewUserFlags; 276 supportsOverrideUserIdProperty = builder.mSupportsOverrideUserIdProperty; 277 userLocales = builder.mUserLocales; 278 } 279 280 @Override toString()281 public String toString() { 282 StringBuilder string = new StringBuilder("InitialUserInfo[type="); 283 switch(type) { 284 case TYPE_DEFAULT_BEHAVIOR: 285 string.append("DEFAULT_BEHAVIOR"); 286 break; 287 case TYPE_REPLACE_GUEST: 288 string.append("REPLACE_GUEST"); 289 break; 290 case TYPE_SWITCH: 291 string.append("SWITCH").append(",userId=").append(switchUserId); 292 break; 293 case TYPE_CREATE: 294 string.append("CREATE").append(",flags=") 295 .append(UserHalHelper.userFlagsToString(newUserFlags)); 296 if (newUserName != null) { 297 string.append(",name=" + UserHelperLite.safeName(newUserName)); 298 } 299 if (userLocales != null) { 300 string.append(",locales=").append(userLocales); 301 } 302 break; 303 default: 304 string.append("UNKNOWN:").append(type); 305 } 306 if (replaceGuest) string.append(",replaceGuest"); 307 if (supportsOverrideUserIdProperty) string.append(",supportsOverrideUserIdProperty"); 308 309 return string.append(']').toString(); 310 } 311 } 312 313 /** 314 * Sets the initial user. 315 */ set(@onNull InitialUserInfo info)316 public void set(@NonNull InitialUserInfo info) { 317 Preconditions.checkArgument(info != null, "info cannot be null"); 318 319 switch (info.type) { 320 case TYPE_DEFAULT_BEHAVIOR: 321 executeDefaultBehavior(info, /* fallback= */ false); 322 break; 323 case TYPE_SWITCH: 324 try { 325 switchUser(info, /* fallback= */ true); 326 } catch (Exception e) { 327 fallbackDefaultBehavior(info, /* fallback= */ true, 328 "Exception switching user: " + e); 329 } 330 break; 331 case TYPE_CREATE: 332 try { 333 createAndSwitchUser(info, /* fallback= */ true); 334 } catch (Exception e) { 335 fallbackDefaultBehavior(info, /* fallback= */ true, 336 "Exception createUser user with name " 337 + UserHelperLite.safeName(info.newUserName) + " and flags " 338 + UserHalHelper.userFlagsToString(info.newUserFlags) + ": " 339 + e); 340 } 341 break; 342 case TYPE_REPLACE_GUEST: 343 try { 344 replaceUser(info, /* fallback= */ true); 345 } catch (Exception e) { 346 fallbackDefaultBehavior(info, /* fallback= */ true, 347 "Exception replace guest user: " + e); 348 } 349 break; 350 default: 351 throw new IllegalArgumentException("invalid InitialUserInfo type: " + info.type); 352 } 353 } 354 replaceUser(InitialUserInfo info, boolean fallback)355 private void replaceUser(InitialUserInfo info, boolean fallback) { 356 int currentUserId = ActivityManager.getCurrentUser(); 357 UserInfo currentUser = mUm.getUserInfo(currentUserId); 358 359 UserInfo newUser = replaceGuestIfNeeded(currentUser); 360 if (newUser == null) { 361 fallbackDefaultBehavior(info, fallback, 362 "could not replace guest " + currentUser.toFullString()); 363 return; 364 } 365 366 switchUser(new Builder(TYPE_SWITCH) 367 .setSwitchUserId(newUser.id) 368 .build(), fallback); 369 370 if (newUser.id != currentUser.id) { 371 Slog.i(TAG, "Removing old guest " + currentUser.id); 372 if (!mUm.removeUser(currentUser.id)) { 373 Slog.w(TAG, "Could not remove old guest " + currentUser.id); 374 } 375 } 376 } 377 executeDefaultBehavior(@onNull InitialUserInfo info, boolean fallback)378 private void executeDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback) { 379 if (!hasInitialUser()) { 380 if (DBG) Slog.d(TAG, "executeDefaultBehavior(): no initial user, creating it"); 381 createAndSwitchUser(new Builder(TYPE_CREATE) 382 .setNewUserName(mNewUserName) 383 .setNewUserFlags(UserFlags.ADMIN) 384 .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty) 385 .setUserLocales(info.userLocales) 386 .build(), fallback); 387 } else { 388 if (DBG) Slog.d(TAG, "executeDefaultBehavior(): switching to initial user"); 389 int userId = getInitialUser(info.supportsOverrideUserIdProperty); 390 switchUser(new Builder(TYPE_SWITCH) 391 .setSwitchUserId(userId) 392 .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty) 393 .setReplaceGuest(info.replaceGuest) 394 .build(), fallback); 395 } 396 } 397 398 @VisibleForTesting fallbackDefaultBehavior(@onNull InitialUserInfo info, boolean fallback, @NonNull String reason)399 void fallbackDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback, 400 @NonNull String reason) { 401 if (!fallback) { 402 // Only log the error 403 Slog.w(TAG, reason); 404 // Must explicitly tell listener that initial user could not be determined 405 notifyListener(/*initialUser= */ null); 406 return; 407 } 408 Slog.w(TAG, "Falling back to default behavior. Reason: " + reason); 409 executeDefaultBehavior(info, /* fallback= */ false); 410 } 411 switchUser(@onNull InitialUserInfo info, boolean fallback)412 private void switchUser(@NonNull InitialUserInfo info, boolean fallback) { 413 int userId = info.switchUserId; 414 boolean replaceGuest = info.replaceGuest; 415 416 if (DBG) { 417 Slog.d(TAG, "switchUser(): userId=" + userId + ", replaceGuest=" + replaceGuest 418 + ", fallback=" + fallback); 419 } 420 421 UserInfo user = mUm.getUserInfo(userId); 422 if (user == null) { 423 fallbackDefaultBehavior(info, fallback, "user with id " + userId + " doesn't exist"); 424 return; 425 } 426 427 UserInfo actualUser = user; 428 429 if (user.isGuest() && replaceGuest) { 430 actualUser = replaceGuestIfNeeded(user); 431 432 if (actualUser == null) { 433 fallbackDefaultBehavior(info, fallback, "could not replace guest " 434 + user.toFullString()); 435 return; 436 } 437 } 438 439 int actualUserId = actualUser.id; 440 441 unlockSystemUserIfNecessary(actualUserId); 442 443 int currentUserId = ActivityManager.getCurrentUser(); 444 if (actualUserId != currentUserId) { 445 if (!startForegroundUser(actualUserId)) { 446 fallbackDefaultBehavior(info, fallback, 447 "am.switchUser(" + actualUserId + ") failed"); 448 return; 449 } 450 setLastActiveUser(actualUser.id); 451 } 452 notifyListener(actualUser); 453 454 if (actualUserId != userId) { 455 Slog.i(TAG, "Removing old guest " + userId); 456 if (!mUm.removeUser(userId)) { 457 Slog.w(TAG, "Could not remove old guest " + userId); 458 } 459 } 460 } 461 unlockSystemUserIfNecessary(@serIdInt int userId)462 private void unlockSystemUserIfNecessary(@UserIdInt int userId) { 463 // If system user is the only user to unlock, it will be handled when boot is complete. 464 if (userId != UserHandle.USER_SYSTEM) { 465 unlockSystemUser(); 466 } 467 } 468 469 /** 470 * Check if the user is a guest and can be replaced. 471 */ canReplaceGuestUser(UserInfo user)472 public boolean canReplaceGuestUser(UserInfo user) { 473 if (!user.isGuest()) return false; 474 475 if (mLockPatternUtils.isSecure(user.id)) { 476 if (DBG) { 477 Slog.d(TAG, "replaceGuestIfNeeded(), skipped, since user " 478 + user.id + " has secure lock pattern"); 479 } 480 return false; 481 } 482 483 return true; 484 } 485 486 /** 487 * Replaces {@code user} by a new guest, if necessary. 488 * 489 * <p>If {@code user} is not a guest, it doesn't do anything and returns the same user. 490 * 491 * <p>Otherwise, it marks the current guest for deletion, creates a new one, and returns the 492 * new guest (or {@code null} if a new guest could not be created). 493 */ 494 495 @VisibleForTesting 496 @Nullable replaceGuestIfNeeded(@onNull UserInfo user)497 UserInfo replaceGuestIfNeeded(@NonNull UserInfo user) { 498 Preconditions.checkArgument(user != null, "user cannot be null"); 499 500 if (!canReplaceGuestUser(user)) { 501 return user; 502 } 503 504 Slog.i(TAG, "Replacing guest (" + user.toFullString() + ")"); 505 506 int halFlags = UserFlags.GUEST; 507 if (user.isEphemeral()) { 508 halFlags |= UserFlags.EPHEMERAL; 509 } else { 510 // TODO(b/150413515): decide whether we should allow it or not. Right now we're 511 // just logging, as UserManagerService will automatically set it to ephemeral if 512 // platform is set to do so. 513 Slog.w(TAG, "guest being replaced is not ephemeral: " + user.toFullString()); 514 } 515 516 if (!mUm.markGuestForDeletion(user.id)) { 517 // Don't need to recover in case of failure - most likely create new user will fail 518 // because there is already a guest 519 Slog.w(TAG, "failed to mark guest " + user.id + " for deletion"); 520 } 521 522 Pair<UserInfo, String> result = createNewUser(new Builder(TYPE_CREATE) 523 .setNewUserName(mNewGuestName) 524 .setNewUserFlags(halFlags) 525 .build()); 526 527 String errorMessage = result.second; 528 if (errorMessage != null) { 529 Slog.w(TAG, "could not replace guest " + user.toFullString() + ": " + errorMessage); 530 return null; 531 } 532 533 return result.first; 534 } 535 createAndSwitchUser(@onNull InitialUserInfo info, boolean fallback)536 private void createAndSwitchUser(@NonNull InitialUserInfo info, boolean fallback) { 537 Pair<UserInfo, String> result = createNewUser(info); 538 String reason = result.second; 539 if (reason != null) { 540 fallbackDefaultBehavior(info, fallback, reason); 541 return; 542 } 543 544 switchUser(new Builder(TYPE_SWITCH) 545 .setSwitchUserId(result.first.id) 546 .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty) 547 .build(), fallback); 548 } 549 550 /** 551 * Creates a new user. 552 * 553 * @return on success, first element is the new user; on failure, second element contains the 554 * error message. 555 */ 556 @NonNull createNewUser(@onNull InitialUserInfo info)557 private Pair<UserInfo, String> createNewUser(@NonNull InitialUserInfo info) { 558 String name = info.newUserName; 559 int halFlags = info.newUserFlags; 560 561 if (DBG) { 562 Slog.d(TAG, "createUser(name=" + UserHelperLite.safeName(name) + ", flags=" 563 + userFlagsToString(halFlags) + ")"); 564 } 565 566 if (UserHalHelper.isSystem(halFlags)) { 567 return new Pair<>(null, "Cannot create system user"); 568 } 569 570 if (UserHalHelper.isAdmin(halFlags)) { 571 boolean validAdmin = true; 572 if (UserHalHelper.isGuest(halFlags)) { 573 Slog.w(TAG, "Cannot create guest admin"); 574 validAdmin = false; 575 } 576 if (UserHalHelper.isEphemeral(halFlags)) { 577 Slog.w(TAG, "Cannot create ephemeral admin"); 578 validAdmin = false; 579 } 580 if (!validAdmin) { 581 return new Pair<>(null, "Invalid flags for admin user"); 582 } 583 } 584 // TODO(b/150413515): decide what to if HAL requested a non-ephemeral guest but framework 585 // sets all guests as ephemeral - should it fail or just warn? 586 587 int flags = UserHalHelper.toUserInfoFlags(halFlags); 588 String type = UserHalHelper.isGuest(halFlags) ? UserManager.USER_TYPE_FULL_GUEST 589 : UserManager.USER_TYPE_FULL_SECONDARY; 590 591 if (DBG) { 592 Slog.d(TAG, "calling am.createUser((name=" + UserHelperLite.safeName(name) + ", type=" 593 + type + ", flags=" + UserInfo.flagsToString(flags) + ")"); 594 } 595 596 UserInfo userInfo = mCarUserService.createUserEvenWhenDisallowed(name, type, flags); 597 if (userInfo == null) { 598 return new Pair<>(null, "createUser(name=" + UserHelperLite.safeName(name) + ", flags=" 599 + userFlagsToString(halFlags) + "): failed to create user"); 600 } 601 602 if (DBG) Slog.d(TAG, "user created: " + userInfo.id); 603 604 if (info.userLocales != null) { 605 if (DBG) { 606 Slog.d(TAG, "setting locale for user " + userInfo.id + " to " + info.userLocales); 607 } 608 Settings.System.putStringForUser(mContext.getContentResolver(), 609 Settings.System.SYSTEM_LOCALES, info.userLocales, userInfo.id); 610 } 611 612 return new Pair<>(userInfo, null); 613 } 614 615 @VisibleForTesting unlockSystemUser()616 void unlockSystemUser() { 617 Slog.i(TAG, "unlocking system user"); 618 IActivityManager am = ActivityManager.getService(); 619 620 TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 621 t.traceBegin("UnlockSystemUser"); 622 try { 623 // This is for force changing state into RUNNING_LOCKED. Otherwise unlock does not 624 // update the state and USER_SYSTEM unlock happens twice. 625 t.traceBegin("am.startUser"); 626 boolean started = am.startUserInBackground(UserHandle.USER_SYSTEM); 627 t.traceEnd(); 628 if (!started) { 629 Slog.w(TAG, "could not restart system user in foreground; trying unlock instead"); 630 t.traceBegin("am.unlockUser"); 631 boolean unlocked = am.unlockUser(UserHandle.USER_SYSTEM, /* token= */ null, 632 /* secret= */ null, /* listener= */ null); 633 t.traceEnd(); 634 if (!unlocked) { 635 Slog.w(TAG, "could not unlock system user neither"); 636 return; 637 } 638 } 639 } catch (RemoteException e) { 640 // should not happen for local call. 641 Slog.wtf("RemoteException from AMS", e); 642 } finally { 643 t.traceEnd(); 644 } 645 } 646 647 @VisibleForTesting startForegroundUser(@serIdInt int userId)648 boolean startForegroundUser(@UserIdInt int userId) { 649 if (UserHelperLite.isHeadlessSystemUser(userId)) { 650 // System User doesn't associate with real person, can not be switched to. 651 return false; 652 } 653 try { 654 return ActivityManager.getService().startUserInForegroundWithListener(userId, null); 655 } catch (RemoteException e) { 656 Slog.w(TAG, "failed to start user " + userId, e); 657 return false; 658 } 659 } 660 notifyListener(@ullable UserInfo initialUser)661 private void notifyListener(@Nullable UserInfo initialUser) { 662 if (DBG) Slog.d(TAG, "notifyListener(): " + initialUser); 663 mListener.accept(initialUser); 664 } 665 666 /** 667 * Dumps it state. 668 */ 669 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(@onNull PrintWriter writer)670 public void dump(@NonNull PrintWriter writer) { 671 writer.println("InitialUserSetter"); 672 String indent = " "; 673 writer.printf("%smNewUserName: %s\n", indent, mNewUserName); 674 writer.printf("%smNewGuestName: %s\n", indent, mNewGuestName); 675 } 676 677 /** 678 * Sets the last active user. 679 */ setLastActiveUser(@serIdInt int userId)680 public void setLastActiveUser(@UserIdInt int userId) { 681 if (UserHelperLite.isHeadlessSystemUser(userId)) { 682 if (DBG) Slog.d(TAG, "setLastActiveUser(): ignoring headless system user " + userId); 683 return; 684 } 685 setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID, userId); 686 687 // TODO(b/155918094): change method to receive a UserInfo instead 688 UserInfo user = mUm.getUserInfo(userId); 689 if (user == null) { 690 Slog.w(TAG, "setLastActiveUser(): user " + userId + " doesn't exist"); 691 return; 692 } 693 if (!user.isEphemeral()) { 694 setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID, userId); 695 } 696 } 697 setUserIdGlobalProperty(@onNull String name, @UserIdInt int userId)698 private void setUserIdGlobalProperty(@NonNull String name, @UserIdInt int userId) { 699 if (DBG) Slog.d(TAG, "setting global property " + name + " to " + userId); 700 701 Settings.Global.putInt(mContext.getContentResolver(), name, userId); 702 } 703 704 /** 705 * Gets the user id for the initial user to boot into. This is only applicable for headless 706 * system user model. This method checks for a system property and will only work for system 707 * apps. 708 * 709 * This method checks for the initial user via three mechanisms in this order: 710 * <ol> 711 * <li>Check for a boot user override via {@link CarProperties#boot_user_override_id()}</li> 712 * <li>Check for the last active user in the system</li> 713 * <li>Fallback to the smallest user id that is not {@link UserHandle.USER_SYSTEM}</li> 714 * </ol> 715 * 716 * If any step fails to retrieve the stored id or the retrieved id does not exist on device, 717 * then it will move onto the next step. 718 * 719 * @return user id of the initial user to boot into on the device, or 720 * {@link UserHandle#USER_NULL} if there is no user available. 721 */ 722 @VisibleForTesting getInitialUser(boolean usesOverrideUserIdProperty)723 int getInitialUser(boolean usesOverrideUserIdProperty) { 724 725 List<Integer> allUsers = userInfoListToUserIdList(getAllUsers()); 726 727 if (allUsers.isEmpty()) { 728 return UserHandle.USER_NULL; 729 } 730 731 //TODO(b/150416512): Check if it is still supported, if not remove it. 732 if (usesOverrideUserIdProperty) { 733 int bootUserOverride = CarProperties.boot_user_override_id() 734 .orElse(BOOT_USER_NOT_FOUND); 735 736 // If an override user is present and a real user, return it 737 if (bootUserOverride != BOOT_USER_NOT_FOUND 738 && allUsers.contains(bootUserOverride)) { 739 Slog.i(TAG, "Boot user id override found for initial user, user id: " 740 + bootUserOverride); 741 return bootUserOverride; 742 } 743 } 744 745 // If the last active user is not the SYSTEM user and is a real user, return it 746 int lastActiveUser = getUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID); 747 if (allUsers.contains(lastActiveUser)) { 748 Slog.i(TAG, "Last active user loaded for initial user: " + lastActiveUser); 749 return lastActiveUser; 750 } 751 resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID); 752 753 int lastPersistentUser = getUserIdGlobalProperty( 754 CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID); 755 if (allUsers.contains(lastPersistentUser)) { 756 Slog.i(TAG, "Last active, persistent user loaded for initial user: " 757 + lastPersistentUser); 758 return lastPersistentUser; 759 } 760 resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID); 761 762 // If all else fails, return the smallest user id 763 int returnId = Collections.min(allUsers); 764 // TODO(b/158101909): the smallest user id is not always the initial user; a better approach 765 // would be looking for the first ADMIN user, or keep track of all last active users (not 766 // just the very last) 767 Slog.w(TAG, "Last active user (" + lastActiveUser + ") not found. Returning smallest user " 768 + "id instead: " + returnId); 769 return returnId; 770 } 771 772 /** 773 * Gets all the users that can be brought to the foreground on the system. 774 * 775 * @return List of {@code UserInfo} for users that associated with a real person. 776 */ getAllUsers()777 private List<UserInfo> getAllUsers() { 778 if (UserManager.isHeadlessSystemUserMode()) { 779 return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM); 780 } else { 781 return mUm.getAliveUsers(); 782 } 783 } 784 785 /** 786 * Gets all the users except system user and the one with userId passed in. 787 * 788 * @param userId of the user not to be returned. 789 * @return All users other than system user and user with userId. 790 */ getAllUsersExceptSystemUserAndSpecifiedUser(@serIdInt int userId)791 private List<UserInfo> getAllUsersExceptSystemUserAndSpecifiedUser(@UserIdInt int userId) { 792 List<UserInfo> users = mUm.getAliveUsers(); 793 794 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) { 795 UserInfo userInfo = iterator.next(); 796 if (userInfo.id == userId || userInfo.id == UserHandle.USER_SYSTEM) { 797 // Remove user with userId from the list. 798 iterator.remove(); 799 } 800 } 801 return users; 802 } 803 804 /** 805 * Checks whether the device has an initial user that can be switched to. 806 */ hasInitialUser()807 public boolean hasInitialUser() { 808 List<UserInfo> allUsers = getAllUsers(); 809 for (int i = 0; i < allUsers.size(); i++) { 810 UserInfo user = allUsers.get(i); 811 if (user.isManagedProfile()) continue; 812 813 return true; 814 } 815 return false; 816 } 817 userInfoListToUserIdList(List<UserInfo> allUsers)818 private static List<Integer> userInfoListToUserIdList(List<UserInfo> allUsers) { 819 ArrayList<Integer> list = new ArrayList<>(allUsers.size()); 820 for (int i = 0; i < allUsers.size(); i++) { 821 list.add(allUsers.get(i).id); 822 } 823 return list; 824 } 825 resetUserIdGlobalProperty(@onNull String name)826 private void resetUserIdGlobalProperty(@NonNull String name) { 827 if (DBG) Slog.d(TAG, "resetting global property " + name); 828 829 Settings.Global.putInt(mContext.getContentResolver(), name, UserHandle.USER_NULL); 830 } 831 getUserIdGlobalProperty(@onNull String name)832 private int getUserIdGlobalProperty(@NonNull String name) { 833 int userId = Settings.Global.getInt(mContext.getContentResolver(), name, 834 UserHandle.USER_NULL); 835 if (DBG) Slog.d(TAG, "getting global property " + name + ": " + userId); 836 837 return userId; 838 } 839 } 840