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