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