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