1 /* 2 * Copyright (C) 2019 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 17 package android.car.user; 18 19 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 20 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; 21 import static android.os.Process.myUid; 22 23 import static com.android.internal.util.FunctionalUtils.getLambdaName; 24 25 import android.annotation.CallbackExecutor; 26 import android.annotation.IntDef; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.annotation.RequiresPermission; 30 import android.annotation.SystemApi; 31 import android.annotation.TestApi; 32 import android.annotation.UserIdInt; 33 import android.car.Car; 34 import android.car.CarManagerBase; 35 import android.car.ICarUserService; 36 import android.content.pm.UserInfo; 37 import android.content.pm.UserInfo.UserInfoFlag; 38 import android.os.Bundle; 39 import android.os.IBinder; 40 import android.os.RemoteException; 41 import android.os.UserHandle; 42 import android.os.UserManager; 43 import android.provider.Settings; 44 import android.sysprop.CarProperties; 45 import android.util.ArrayMap; 46 import android.util.EventLog; 47 import android.util.Log; 48 49 import com.android.internal.annotations.GuardedBy; 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.internal.car.EventLogTags; 52 import com.android.internal.infra.AndroidFuture; 53 import com.android.internal.os.IResultReceiver; 54 import com.android.internal.util.ArrayUtils; 55 import com.android.internal.util.Preconditions; 56 57 import java.lang.annotation.Retention; 58 import java.lang.annotation.RetentionPolicy; 59 import java.util.Arrays; 60 import java.util.List; 61 import java.util.Objects; 62 import java.util.concurrent.Executor; 63 import java.util.stream.Collectors; 64 65 /** 66 * API to manage users related to car. 67 * 68 * @hide 69 */ 70 @SystemApi 71 @TestApi 72 public final class CarUserManager extends CarManagerBase { 73 74 private static final String TAG = CarUserManager.class.getSimpleName(); 75 private static final int HAL_TIMEOUT_MS = CarProperties.user_hal_timeout().orElse(5_000); 76 77 private static final boolean DBG = false; 78 79 /** 80 * {@link UserLifecycleEvent} called when the user is starting, for components to initialize 81 * any per-user state they maintain for running users. 82 * 83 * @hide 84 */ 85 @SystemApi 86 @TestApi 87 public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; 88 89 /** 90 * {@link UserLifecycleEvent} called when switching to a different foreground user, for 91 * components that have special behavior for whichever user is currently in the foreground. 92 * 93 * <p>This is called before any application processes are aware of the new user. 94 * 95 * <p>Notice that internal system services might not have handled user switching yet, so be 96 * careful with interaction with them. 97 * 98 * @hide 99 */ 100 @SystemApi 101 @TestApi 102 public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; 103 104 /** 105 * {@link UserLifecycleEvent} called when an existing user is in the process of being unlocked. 106 * 107 * <p>This means the credential-encrypted storage for that user is now available, and 108 * encryption-aware component filtering is no longer in effect. 109 * 110 * <p>Notice that internal system services might not have handled unlock yet, so most components 111 * should ignore this callback and rely on {@link #USER_LIFECYCLE_EVENT_TYPE_UNLOCKED} instead. 112 * 113 * @hide 114 */ 115 @SystemApi 116 @TestApi 117 public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; 118 119 /** 120 * {@link UserLifecycleEvent} called after an existing user is unlocked. 121 * 122 * @hide 123 */ 124 @SystemApi 125 @TestApi 126 public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; 127 128 /** 129 * {@link UserLifecycleEvent} called when an existing user is stopping, for components to 130 * finalize any per-user state they maintain for running users. 131 * 132 * <p>This is called prior to sending the {@code SHUTDOWN} broadcast to the user; it is a good 133 * place to stop making use of any resources of that user (such as binding to a service running 134 * in the user). 135 * 136 * <p><b>Note:</b> this is the last callback where the callee may access the target user's CE 137 * storage. 138 * 139 * @hide 140 */ 141 @SystemApi 142 @TestApi 143 public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; 144 145 /** 146 * {@link UserLifecycleEvent} called after an existing user is stopped. 147 * 148 * <p>This is called after all application process teardown of the user is complete. 149 * 150 * @hide 151 */ 152 @SystemApi 153 @TestApi 154 public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; 155 156 /** @hide */ 157 @IntDef(prefix = { "USER_LIFECYCLE_EVENT_TYPE_" }, value = { 158 USER_LIFECYCLE_EVENT_TYPE_STARTING, 159 USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 160 USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, 161 USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 162 USER_LIFECYCLE_EVENT_TYPE_STOPPING, 163 USER_LIFECYCLE_EVENT_TYPE_STOPPED, 164 }) 165 @Retention(RetentionPolicy.SOURCE) 166 public @interface UserLifecycleEventType{} 167 168 /** @hide */ 169 public static final String BUNDLE_PARAM_ACTION = "action"; 170 /** @hide */ 171 public static final String BUNDLE_PARAM_PREVIOUS_USER_ID = "previous_user"; 172 173 private final Object mLock = new Object(); 174 private final ICarUserService mService; 175 private final UserManager mUserManager; 176 177 @Nullable 178 @GuardedBy("mLock") 179 private ArrayMap<UserLifecycleListener, Executor> mListeners; 180 181 @Nullable 182 @GuardedBy("mLock") 183 private LifecycleResultReceiver mReceiver; 184 185 /** 186 * @hide 187 */ CarUserManager(@onNull Car car, @NonNull IBinder service)188 public CarUserManager(@NonNull Car car, @NonNull IBinder service) { 189 this(car, ICarUserService.Stub.asInterface(service), UserManager.get(car.getContext())); 190 } 191 192 /** 193 * @hide 194 */ 195 @VisibleForTesting CarUserManager(@onNull Car car, @NonNull ICarUserService service, @NonNull UserManager userManager)196 public CarUserManager(@NonNull Car car, @NonNull ICarUserService service, 197 @NonNull UserManager userManager) { 198 super(car); 199 mService = service; 200 mUserManager = userManager; 201 } 202 203 /** 204 * Switches the foreground user to the given target user. 205 * 206 * @hide 207 */ 208 @RequiresPermission(android.Manifest.permission.MANAGE_USERS) switchUser(@serIdInt int targetUserId)209 public AndroidFuture<UserSwitchResult> switchUser(@UserIdInt int targetUserId) { 210 int uid = myUid(); 211 212 if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) { 213 return newSwitchResuiltForFailure(UserSwitchResult.STATUS_NOT_SWITCHABLE); 214 } 215 216 try { 217 AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() { 218 @Override 219 protected void onCompleted(UserSwitchResult result, Throwable err) { 220 if (result != null) { 221 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_RESP, uid, 222 result.getStatus(), result.getErrorMessage()); 223 } else { 224 Log.w(TAG, "switchUser(" + targetUserId + ") failed: " + err); 225 } 226 super.onCompleted(result, err); 227 } 228 }; 229 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQ, uid, targetUserId); 230 mService.switchUser(targetUserId, HAL_TIMEOUT_MS, future); 231 return future; 232 } catch (RemoteException e) { 233 AndroidFuture<UserSwitchResult> future = 234 newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); 235 return handleRemoteExceptionFromCarService(e, future); 236 } 237 } 238 newSwitchResuiltForFailure( @serSwitchResult.Status int status)239 private AndroidFuture<UserSwitchResult> newSwitchResuiltForFailure( 240 @UserSwitchResult.Status int status) { 241 AndroidFuture<UserSwitchResult> future = new AndroidFuture<>(); 242 future.complete(new UserSwitchResult(status, null)); 243 return future; 244 } 245 246 /** 247 * Creates a new Android user. 248 * 249 * @hide 250 */ 251 @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, 252 android.Manifest.permission.CREATE_USERS}) createUser(@ullable String name, @NonNull String userType, @UserInfoFlag int flags)253 public AndroidFuture<UserCreationResult> createUser(@Nullable String name, 254 @NonNull String userType, @UserInfoFlag int flags) { 255 int uid = myUid(); 256 try { 257 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() { 258 @Override 259 protected void onCompleted(UserCreationResult result, Throwable err) { 260 if (result != null) { 261 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_RESP, uid, 262 result.getStatus(), result.getErrorMessage()); 263 UserInfo user = result.getUser(); 264 if (result.isSuccess() && user != null && user.isGuest()) { 265 onGuestCreated(user); 266 } 267 } else { 268 Log.w(TAG, "createUser(" + userType + "," + UserInfo.flagsToString(flags) 269 + ") failed: " + err); 270 } 271 super.onCompleted(result, err); 272 }; 273 }; 274 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_REQ, uid, 275 safeName(name), userType, flags); 276 mService.createUser(name, userType, flags, HAL_TIMEOUT_MS, future); 277 return future; 278 } catch (RemoteException e) { 279 AndroidFuture<UserCreationResult> future = new AndroidFuture<>(); 280 future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE, 281 null, null)); 282 return handleRemoteExceptionFromCarService(e, future); 283 } 284 } 285 286 /** 287 * Creates a new guest Android user. 288 * 289 * @hide 290 */ 291 @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, 292 android.Manifest.permission.CREATE_USERS}) createGuest(@ullable String name)293 public AndroidFuture<UserCreationResult> createGuest(@Nullable String name) { 294 return createUser(name, UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0); 295 } 296 297 /** 298 * Creates a new Android user. 299 * 300 * @hide 301 */ 302 @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, 303 android.Manifest.permission.CREATE_USERS}) createUser(@ullable String name, @UserInfoFlag int flags)304 public AndroidFuture<UserCreationResult> createUser(@Nullable String name, 305 @UserInfoFlag int flags) { 306 return createUser(name, UserManager.USER_TYPE_FULL_SECONDARY, flags); 307 } 308 309 // TODO(b/159283854): move to UserManager onGuestCreated(UserInfo user)310 private void onGuestCreated(UserInfo user) { 311 Settings.Secure.putStringForUser(getContext().getContentResolver(), 312 Settings.Secure.SKIP_FIRST_USE_HINTS, "1", user.id); 313 } 314 315 /** 316 * Removes a user. 317 * 318 * @hide 319 */ 320 @RequiresPermission(android.Manifest.permission.MANAGE_USERS) removeUser(@serIdInt int userId)321 public UserRemovalResult removeUser(@UserIdInt int userId) { 322 int uid = myUid(); 323 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_REQ, uid, userId); 324 int status = UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE; 325 try { 326 UserRemovalResult result = mService.removeUser(userId); 327 status = result.getStatus(); 328 return result; 329 } catch (RemoteException e) { 330 return handleRemoteExceptionFromCarService(e, 331 new UserRemovalResult(UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE)); 332 } finally { 333 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_RESP, uid, status); 334 } 335 } 336 337 /** 338 * Adds a listener for {@link UserLifecycleEvent user lifecycle events}. 339 * 340 * @throws IllegalStateException if the listener was already added. 341 * 342 * @hide 343 */ 344 @SystemApi 345 @TestApi 346 @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL}) addListener(@onNull @allbackExecutor Executor executor, @NonNull UserLifecycleListener listener)347 public void addListener(@NonNull @CallbackExecutor Executor executor, 348 @NonNull UserLifecycleListener listener) { 349 Objects.requireNonNull(executor, "executor cannot be null"); 350 Objects.requireNonNull(listener, "listener cannot be null"); 351 352 int uid = myUid(); 353 synchronized (mLock) { 354 Preconditions.checkState(mListeners == null || !mListeners.containsKey(listener), 355 "already called for this listener"); 356 if (mReceiver == null) { 357 mReceiver = new LifecycleResultReceiver(); 358 try { 359 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid); 360 if (DBG) Log.d(TAG, "Setting lifecycle receiver for uid " + uid); 361 mService.setLifecycleListenerForUid(mReceiver); 362 } catch (RemoteException e) { 363 handleRemoteExceptionFromCarService(e); 364 } 365 } else { 366 if (DBG) Log.d(TAG, "Already set receiver for uid " + uid); 367 } 368 369 if (mListeners == null) { 370 mListeners = new ArrayMap<>(1); // Most likely app will have just one listener 371 } else if (DBG) { 372 Log.d(TAG, "addListener(" + getLambdaName(listener) + "): context " + getContext() 373 + " already has " + mListeners.size() + " listeners: " 374 + mListeners.keySet().stream() 375 .map((l) -> getLambdaName(l)) 376 .collect(Collectors.toList()), new Exception()); 377 } 378 if (DBG) Log.d(TAG, "Adding listener: " + listener); 379 mListeners.put(listener, executor); 380 } 381 } 382 383 /** 384 * Removes a listener for {@link UserLifecycleEvent user lifecycle events}. 385 * 386 * @throws IllegalStateException if the listener was not added beforehand. 387 * 388 * @hide 389 */ 390 @SystemApi 391 @TestApi 392 @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL}) removeListener(@onNull UserLifecycleListener listener)393 public void removeListener(@NonNull UserLifecycleListener listener) { 394 Objects.requireNonNull(listener, "listener cannot be null"); 395 396 int uid = myUid(); 397 synchronized (mLock) { 398 Preconditions.checkState(mListeners != null && mListeners.containsKey(listener), 399 "not called for this listener yet"); 400 mListeners.remove(listener); 401 402 if (!mListeners.isEmpty()) { 403 if (DBG) Log.d(TAG, "removeListeners(): still " + mListeners.size() + " left"); 404 return; 405 } 406 mListeners = null; 407 408 if (mReceiver == null) { 409 Log.wtf(TAG, "removeListener(): receiver already null"); 410 return; 411 } 412 413 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid); 414 if (DBG) Log.d(TAG, "Removing lifecycle receiver for uid=" + uid); 415 try { 416 mService.resetLifecycleListenerForUid(); 417 mReceiver = null; 418 } catch (RemoteException e) { 419 handleRemoteExceptionFromCarService(e); 420 } 421 } 422 } 423 424 /** 425 * Check if user hal supports user association. 426 * 427 * @hide 428 */ isUserHalUserAssociationSupported()429 public boolean isUserHalUserAssociationSupported() { 430 try { 431 return mService.isUserHalUserAssociationSupported(); 432 } catch (RemoteException e) { 433 return handleRemoteExceptionFromCarService(e, false); 434 } 435 } 436 437 /** 438 * Gets the user authentication types associated with this manager's user. 439 * 440 * @hide 441 */ 442 @NonNull 443 @RequiresPermission(android.Manifest.permission.MANAGE_USERS) getUserIdentificationAssociation( @onNull int... types)444 public UserIdentificationAssociationResponse getUserIdentificationAssociation( 445 @NonNull int... types) { 446 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type"); 447 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, types.length); 448 try { 449 UserIdentificationAssociationResponse response = 450 mService.getUserIdentificationAssociation(types); 451 if (response != null) { 452 int[] values = response.getValues(); 453 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, 454 values != null ? values.length : 0); 455 } 456 return response; 457 } catch (RemoteException e) { 458 return handleRemoteExceptionFromCarService(e, null); 459 } 460 } 461 462 /** 463 * Sets the user authentication types associated with this manager's user. 464 * 465 * @hide 466 */ 467 @NonNull 468 @RequiresPermission(android.Manifest.permission.MANAGE_USERS) setUserIdentificationAssociation( @onNull int[] types, @NonNull int[] values)469 public AndroidFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation( 470 @NonNull int[] types, @NonNull int[] values) { 471 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type"); 472 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value"); 473 if (types.length != values.length) { 474 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values (" 475 + Arrays.toString(values) + ") should have the same length"); 476 } 477 // TODO(b/153900032): move this logic to a common helper 478 Object[] loggedValues = new Integer[types.length * 2]; 479 for (int i = 0; i < types.length; i++) { 480 loggedValues[i * 2] = types[i]; 481 loggedValues[i * 2 + 1 ] = values[i]; 482 } 483 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, loggedValues); 484 485 try { 486 AndroidFuture<UserIdentificationAssociationResponse> future = 487 new AndroidFuture<UserIdentificationAssociationResponse>() { 488 @Override 489 protected void onCompleted(UserIdentificationAssociationResponse result, 490 Throwable err) { 491 if (result != null) { 492 int[] rawValues = result.getValues(); 493 // TODO(b/153900032): move this logic to a common helper 494 if (rawValues != null) { 495 Object[] loggedValues = new Object[rawValues.length]; 496 for (int i = 0; i < rawValues.length; i++) { 497 loggedValues[i] = rawValues[i]; 498 } 499 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 500 loggedValues); 501 } 502 } else { 503 Log.w(TAG, "setUserIdentificationAssociation(" + Arrays.toString(types) 504 + ", " + Arrays.toString(values) + ") failed: " + err); 505 } 506 super.onCompleted(result, err); 507 }; 508 }; 509 mService.setUserIdentificationAssociation(HAL_TIMEOUT_MS, types, values, future); 510 return future; 511 } catch (RemoteException e) { 512 AndroidFuture<UserIdentificationAssociationResponse> future = new AndroidFuture<>(); 513 future.complete(UserIdentificationAssociationResponse.forFailure()); 514 return handleRemoteExceptionFromCarService(e, future); 515 } 516 } 517 518 /** 519 * Sets a callback to be notified before user switch. It should only be used by Car System UI. 520 * 521 * @hide 522 */ 523 @RequiresPermission(android.Manifest.permission.MANAGE_USERS) setUserSwitchUiCallback(@onNull UserSwitchUiCallback callback)524 public void setUserSwitchUiCallback(@NonNull UserSwitchUiCallback callback) { 525 Preconditions.checkArgument(callback != null, "Null callback"); 526 UserSwitchUiCallbackReceiver userSwitchUiCallbackReceiver = 527 new UserSwitchUiCallbackReceiver(callback); 528 try { 529 mService.setUserSwitchUiCallback(userSwitchUiCallbackReceiver); 530 } catch (RemoteException e) { 531 handleRemoteExceptionFromCarService(e); 532 } 533 } 534 535 /** 536 * {@code IResultReceiver} used to receive user switch UI Callback. 537 */ 538 // TODO(b/154958003): use mReceiver instead as now there are two binder objects 539 private final class UserSwitchUiCallbackReceiver extends IResultReceiver.Stub { 540 541 private final UserSwitchUiCallback mUserSwitchUiCallback; 542 UserSwitchUiCallbackReceiver(UserSwitchUiCallback callback)543 UserSwitchUiCallbackReceiver(UserSwitchUiCallback callback) { 544 mUserSwitchUiCallback = callback; 545 } 546 547 @Override send(int userId, Bundle unused)548 public void send(int userId, Bundle unused) throws RemoteException { 549 mUserSwitchUiCallback.showUserSwitchDialog(userId); 550 } 551 } 552 553 /** 554 * {@code IResultReceiver} used to receive lifecycle events and dispatch to the proper listener. 555 */ 556 private class LifecycleResultReceiver extends IResultReceiver.Stub { 557 @Override send(int resultCode, Bundle resultData)558 public void send(int resultCode, Bundle resultData) { 559 if (resultData == null) { 560 Log.w(TAG, "Received result (" + resultCode + ") without data"); 561 return; 562 } 563 int from = resultData.getInt(BUNDLE_PARAM_PREVIOUS_USER_ID, UserHandle.USER_NULL); 564 int to = resultCode; 565 int eventType = resultData.getInt(BUNDLE_PARAM_ACTION); 566 UserLifecycleEvent event = new UserLifecycleEvent(eventType, from, to); 567 ArrayMap<UserLifecycleListener, Executor> listeners; 568 synchronized (mLock) { 569 listeners = mListeners; 570 } 571 if (listeners == null) { 572 Log.w(TAG, "No listeners for event " + event); 573 return; 574 } 575 int size = listeners.size(); 576 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_NOTIFY_LIFECYCLE_LISTENER, 577 size, eventType, from, to); 578 for (int i = 0; i < size; i++) { 579 UserLifecycleListener listener = listeners.keyAt(i); 580 Executor executor = listeners.valueAt(i); 581 if (DBG) { 582 Log.d(TAG, "Calling " + getLambdaName(listener) + " for event " + event); 583 } 584 executor.execute(() -> listener.onEvent(event)); 585 } 586 } 587 } 588 589 /** @hide */ 590 @Override onCarDisconnected()591 public void onCarDisconnected() { 592 // nothing to do 593 } 594 595 /** 596 * @hide 597 */ 598 @TestApi lifecycleEventTypeToString(@serLifecycleEventType int type)599 public static String lifecycleEventTypeToString(@UserLifecycleEventType int type) { 600 switch (type) { 601 case USER_LIFECYCLE_EVENT_TYPE_STARTING: 602 return "STARTING"; 603 case USER_LIFECYCLE_EVENT_TYPE_SWITCHING: 604 return "SWITCHING"; 605 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING: 606 return "UNLOCKING"; 607 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED: 608 return "UNLOCKED"; 609 case USER_LIFECYCLE_EVENT_TYPE_STOPPING: 610 return "STOPPING"; 611 case USER_LIFECYCLE_EVENT_TYPE_STOPPED: 612 return "STOPPED"; 613 default: 614 return "UNKNOWN-" + type; 615 } 616 } 617 618 // NOTE: this method is called by ExperimentalCarUserManager, so it can get the mService. 619 // "Real" ExperimentalCarUserManager instances should be obtained through 620 // ExperimentalCarUserManager.from(mCarUserManager) 621 // instead. newExperimentalCarUserManager()622 ExperimentalCarUserManager newExperimentalCarUserManager() { 623 return new ExperimentalCarUserManager(mCar, mService); 624 } 625 626 /** 627 * Checks if the given {@code userId} represents a valid user. 628 * 629 * <p>A "valid" user: 630 * 631 * <ul> 632 * <li>Must exist in the device. 633 * <li>Is not in the process of being deleted. 634 * <li>Cannot be the {@link UserHandle#isSystem() system} user on devices that use 635 * {@link UserManager#isHeadlessSystemUserMode() headless system mode}. 636 * </ul> 637 * 638 * @hide 639 */ isValidUser(@serIdInt int userId)640 public boolean isValidUser(@UserIdInt int userId) { 641 List<UserInfo> allUsers = mUserManager.getUsers(/* excludeDying= */ true); 642 for (int i = 0; i < allUsers.size(); i++) { 643 UserInfo user = allUsers.get(i); 644 if (user.id == userId && (userId != UserHandle.USER_SYSTEM 645 || !UserManager.isHeadlessSystemUserMode())) { 646 return true; 647 } 648 } 649 return false; 650 } 651 652 // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it 653 // would include the whole car-user-lib) isHeadlessSystemUser(int targetUserId)654 private boolean isHeadlessSystemUser(int targetUserId) { 655 return targetUserId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode(); 656 } 657 658 // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it 659 // would include the whole car-user-lib) 660 @Nullable safeName(@ullable String name)661 private static String safeName(@Nullable String name) { 662 return name == null ? name : name.length() + "_chars"; 663 } 664 665 /** 666 * Defines a lifecycle event for an Android user. 667 * 668 * @hide 669 */ 670 @SystemApi 671 @TestApi 672 public static final class UserLifecycleEvent { 673 private final @UserLifecycleEventType int mEventType; 674 private final @UserIdInt int mUserId; 675 private final @UserIdInt int mPreviousUserId; 676 677 /** @hide */ UserLifecycleEvent(@serLifecycleEventType int eventType, @UserIdInt int from, @UserIdInt int to)678 public UserLifecycleEvent(@UserLifecycleEventType int eventType, 679 @UserIdInt int from, @UserIdInt int to) { 680 mEventType = eventType; 681 mPreviousUserId = from; 682 mUserId = to; 683 } 684 685 /** @hide */ UserLifecycleEvent(@serLifecycleEventType int eventType, @UserIdInt int to)686 public UserLifecycleEvent(@UserLifecycleEventType int eventType, @UserIdInt int to) { 687 this(eventType, UserHandle.USER_NULL, to); 688 } 689 690 /** 691 * Gets the event type. 692 * 693 * @return either {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STARTING}, 694 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}, 695 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKING}, 696 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED}, 697 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPING}, or 698 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPED}. 699 */ 700 @UserLifecycleEventType getEventType()701 public int getEventType() { 702 return mEventType; 703 } 704 705 /** 706 * Gets the id of the user whose event is being reported. 707 * 708 * @hide 709 */ 710 @UserIdInt getUserId()711 public int getUserId() { 712 return mUserId; 713 } 714 715 /** 716 * Gets the handle of the user whose event is being reported. 717 */ 718 @NonNull getUserHandle()719 public UserHandle getUserHandle() { 720 return UserHandle.of(mUserId); 721 } 722 723 /** 724 * Gets the id of the user being switched from. 725 * 726 * <p>This method returns {@link UserHandle#USER_NULL} for all event types but 727 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}. 728 * 729 * @hide 730 */ 731 @UserIdInt getPreviousUserId()732 public int getPreviousUserId() { 733 return mPreviousUserId; 734 } 735 736 /** 737 * Gets the handle of the user being switched from. 738 * 739 * <p>This method returns {@code null} for all event types but 740 * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}. 741 */ 742 @Nullable getPreviousUserHandle()743 public UserHandle getPreviousUserHandle() { 744 return mPreviousUserId == UserHandle.USER_NULL ? null : UserHandle.of(mPreviousUserId); 745 } 746 747 @Override toString()748 public String toString() { 749 StringBuilder builder = new StringBuilder("Event[type=") 750 .append(lifecycleEventTypeToString(mEventType)); 751 if (mPreviousUserId != UserHandle.USER_NULL) { 752 builder 753 .append(",from=").append(mPreviousUserId) 754 .append(",to=").append(mUserId); 755 } else { 756 builder.append(",user=").append(mUserId); 757 } 758 759 return builder.append(']').toString(); 760 } 761 } 762 763 /** 764 * Listener for Android User lifecycle events. 765 * 766 * <p>Must be registered using {@link CarUserManager#addListener(UserLifecycleListener)} and 767 * unregistered through {@link CarUserManager#removeListener(UserLifecycleListener)}. 768 * 769 * @hide 770 */ 771 @SystemApi 772 @TestApi 773 public interface UserLifecycleListener { 774 775 /** 776 * Called to notify the given {@code event}. 777 */ onEvent(@onNull UserLifecycleEvent event)778 void onEvent(@NonNull UserLifecycleEvent event); 779 } 780 781 /** 782 * Callback for notifying user switch before switch started. 783 * 784 * <p> It should only be user by Car System UI. The purpose of this callback is notify the 785 * Car System UI to display the user switch UI. 786 * 787 * @hide 788 */ 789 public interface UserSwitchUiCallback { 790 791 /** 792 * Called to notify that user switch dialog should be shown now. 793 */ showUserSwitchDialog(@serIdInt int userId)794 void showUserSwitchDialog(@UserIdInt int userId); 795 } 796 } 797