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