• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.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.ICarResultReceiver;
36 import android.car.ICarUserService;
37 import android.car.annotation.AddedInOrBefore;
38 import android.car.annotation.ApiRequirements;
39 import android.car.builtin.os.UserManagerHelper;
40 import android.car.builtin.util.EventLogHelper;
41 import android.car.util.concurrent.AndroidAsyncFuture;
42 import android.car.util.concurrent.AndroidFuture;
43 import android.car.util.concurrent.AsyncFuture;
44 import android.os.Bundle;
45 import android.os.IBinder;
46 import android.os.RemoteException;
47 import android.os.UserHandle;
48 import android.os.UserManager;
49 import android.util.ArrayMap;
50 import android.util.Dumpable;
51 import android.util.Log;
52 import android.util.Pair;
53 
54 import com.android.car.internal.common.CommonConstants;
55 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
56 import com.android.car.internal.common.UserHelperLite;
57 import com.android.car.internal.os.CarSystemProperties;
58 import com.android.car.internal.util.ArrayUtils;
59 import com.android.internal.annotations.GuardedBy;
60 import com.android.internal.annotations.VisibleForTesting;
61 import com.android.internal.util.Preconditions;
62 
63 import java.io.PrintWriter;
64 import java.lang.annotation.Retention;
65 import java.lang.annotation.RetentionPolicy;
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.List;
69 import java.util.Objects;
70 import java.util.concurrent.ExecutionException;
71 import java.util.concurrent.Executor;
72 import java.util.concurrent.TimeUnit;
73 import java.util.concurrent.TimeoutException;
74 import java.util.stream.Collectors;
75 
76 /**
77  * API to manage users related to car.
78  *
79  * @hide
80  */
81 @SystemApi
82 @TestApi
83 public final class CarUserManager extends CarManagerBase {
84 
85     /** @hide */
86     @AddedInOrBefore(majorVersion = 33)
87     public static final String TAG = CarUserManager.class.getSimpleName();
88 
89     private static final int HAL_TIMEOUT_MS = CarSystemProperties.getUserHalTimeout().orElse(5_000);
90     private static final int REMOVE_USER_CALL_TIMEOUT_MS = 60_000;
91 
92     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
93     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
94 
95     /**
96      * {@link UserLifecycleEvent} called when the user is starting, for components to initialize
97      * any per-user state they maintain for running users.
98      *
99      * @hide
100      */
101     @SystemApi
102     @TestApi
103     @AddedInOrBefore(majorVersion = 33)
104     public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING =
105             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
106 
107     /**
108      * {@link UserLifecycleEvent} called when switching to a different foreground user, for
109      * components that have special behavior for whichever user is currently in the foreground.
110      *
111      * <p>This is called before any application processes are aware of the new user.
112      *
113      * <p>Notice that internal system services might not have handled user switching yet, so be
114      * careful with interaction with them.
115      *
116      * @hide
117      */
118     @SystemApi
119     @TestApi
120     @AddedInOrBefore(majorVersion = 33)
121     public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING =
122             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
123 
124     /**
125      * {@link UserLifecycleEvent} called when an existing user is in the process of being unlocked.
126      *
127      * <p>This means the credential-encrypted storage for that user is now available, and
128      * encryption-aware component filtering is no longer in effect.
129      *
130      * <p>Notice that internal system services might not have handled unlock yet, so most components
131      * should ignore this callback and rely on {@link #USER_LIFECYCLE_EVENT_TYPE_UNLOCKED} instead.
132      *
133      * @hide
134      */
135     @SystemApi
136     @TestApi
137     @AddedInOrBefore(majorVersion = 33)
138     public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING =
139             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
140 
141     /**
142      * {@link UserLifecycleEvent} called after an existing user is unlocked.
143      *
144      * @hide
145      */
146     @SystemApi
147     @TestApi
148     @AddedInOrBefore(majorVersion = 33)
149     public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED =
150             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
151 
152     /**
153      * {@link UserLifecycleEvent} called after an existing user is unlocked for components to
154      * perform non-urgent tasks for user unlocked.
155      *
156      * <p>Note: This event type is intended only for internal system services. Application listeners
157      * should not use this event type and will not receive any events of this type.
158      *
159      * @hide
160      */
161     @AddedInOrBefore(majorVersion = 33)
162     public static final int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED =
163             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
164 
165     /**
166      * {@link UserLifecycleEvent} called when an existing user is stopping, for components to
167      * finalize any per-user state they maintain for running users.
168      *
169      * <p>This is called prior to sending the {@code SHUTDOWN} broadcast to the user; it is a good
170      * place to stop making use of any resources of that user (such as binding to a service running
171      * in the user).
172      *
173      * <p><b>Note:</b> this is the last callback where the callee may access the target user's CE
174      * storage.
175      *
176      * @hide
177      */
178     @SystemApi
179     @TestApi
180     @AddedInOrBefore(majorVersion = 33)
181     public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING =
182             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
183 
184     /**
185      * {@link UserLifecycleEvent} called after an existing user is stopped.
186      *
187      * <p>This is called after all application process teardown of the user is complete.
188      *
189      * @hide
190      */
191     @SystemApi
192     @TestApi
193     @AddedInOrBefore(majorVersion = 33)
194     public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED =
195             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
196 
197     /**
198      * {@link UserLifecycleEvent} called after an existing user is created.
199      *
200      * @hide
201      */
202     @SystemApi
203     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
204             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
205     public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED =
206             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_CREATED;
207 
208     /**
209      * {@link UserLifecycleEvent} called after an existing user is removed.
210      *
211      * @hide
212      */
213     @SystemApi
214     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
215             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
216     public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED =
217             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_REMOVED;
218 
219     /** @hide */
220     @AddedInOrBefore(majorVersion = 33)
221     public static final String BUNDLE_PARAM_ACTION = "action";
222     /** @hide */
223     @AddedInOrBefore(majorVersion = 33)
224     public static final String BUNDLE_PARAM_PREVIOUS_USER_ID = "previous_user";
225 
226     /**
227      * {@link UserIdentificationAssociationType} for key fob.
228      *
229      * @hide
230      */
231     @AddedInOrBefore(majorVersion = 33)
232     public static final int USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB = 1;
233 
234     /**
235      * {@link UserIdentificationAssociationType} for custom type 1.
236      *
237      * @hide
238      */
239     @AddedInOrBefore(majorVersion = 33)
240     public static final int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1 = 101;
241 
242     /**
243      * {@link UserIdentificationAssociationType} for custom type 2.
244      *
245      * @hide
246      */
247     @AddedInOrBefore(majorVersion = 33)
248     public static final int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2 = 102;
249 
250     /**
251      * {@link UserIdentificationAssociationType} for custom type 3.
252      *
253      * @hide
254      */
255     @AddedInOrBefore(majorVersion = 33)
256     public static final int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3 = 103;
257 
258     /**
259      * {@link UserIdentificationAssociationType} for custom type 4.
260      *
261      * @hide
262      */
263     @AddedInOrBefore(majorVersion = 33)
264     public static final int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4 = 104;
265 
266     /**
267      *  User HAL's user identification association types
268      *
269      * @hide
270      */
271     @IntDef(prefix = { "USER_IDENTIFICATION_ASSOCIATION_TYPE_" }, value = {
272             USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB,
273             USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1,
274             USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2,
275             USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3,
276             USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4,
277     })
278     @Retention(RetentionPolicy.SOURCE)
279     public @interface UserIdentificationAssociationType{}
280 
281     /**
282      * {@link UserIdentificationAssociationSetValue} to associate the identification type with the
283      * current foreground Android user.
284      *
285      * @hide
286      */
287     @AddedInOrBefore(majorVersion = 33)
288     public static final int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER = 1;
289 
290     /**
291      * {@link UserIdentificationAssociationSetValue} to disassociate the identification type from
292      * the current foreground Android user.
293      *
294      * @hide
295      */
296     @AddedInOrBefore(majorVersion = 33)
297     public static final int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER = 2;
298 
299     /**
300      * {@link UserIdentificationAssociationSetValue} to disassociate the identification type from
301      * all Android users.
302      *
303      * @hide
304      */
305     @AddedInOrBefore(majorVersion = 33)
306     public static final int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS = 3;
307 
308     /**
309      * User HAL's user identification association types
310      *
311      * @hide
312      */
313     @IntDef(prefix = { "USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_" }, value = {
314             USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER,
315             USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER,
316             USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS,
317     })
318     @Retention(RetentionPolicy.SOURCE)
319     public @interface UserIdentificationAssociationSetValue{}
320 
321     /**
322      * {@link UserIdentificationAssociationValue} when the status of an association could not be
323      * determined.
324      *
325      * @hide
326      */
327     @AddedInOrBefore(majorVersion = 33)
328     public static final int USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN = 1;
329 
330     /**
331      * {@link UserIdentificationAssociationValue} when the identification type is associated with
332      * the current foreground Android user.
333      *
334      * @hide
335      */
336     @AddedInOrBefore(majorVersion = 33)
337     public static final int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER = 2;
338 
339     /**
340      * {@link UserIdentificationAssociationValue} when the identification type is associated with
341      * another Android user.
342      *
343      * @hide
344      */
345     @AddedInOrBefore(majorVersion = 33)
346     public static final int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER = 3;
347 
348     /**
349      * {@link UserIdentificationAssociationValue} when the identification type is not associated
350      * with any Android user.
351      *
352      * @hide
353      */
354     @AddedInOrBefore(majorVersion = 33)
355     public static final int USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER = 4;
356 
357     /**
358      * User HAL's user identification association types
359      *
360      * @hide
361      */
362     @IntDef(prefix = { "USER_IDENTIFICATION_ASSOCIATION_VALUE_" }, value = {
363             USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN,
364             USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER,
365             USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER,
366             USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER,
367     })
368     @Retention(RetentionPolicy.SOURCE)
369     public @interface UserIdentificationAssociationValue{}
370 
371     private final Object mLock = new Object();
372 
373     private final ICarUserService mService;
374     private final UserManager mUserManager;
375 
376     /**
377      * Map of listeners registers by the app.
378      */
379     @Nullable
380     @GuardedBy("mLock")
381     private ArrayMap<UserLifecycleListener, Pair<UserLifecycleEventFilter, Executor>> mListeners;
382 
383     /**
384      * Receiver used to receive user-lifecycle callbacks from the service.
385      */
386     @Nullable
387     @GuardedBy("mLock")
388     private LifecycleResultReceiver mReceiver;
389 
390     private final Dumper mDumper;
391 
392     /**
393      * Logs the number of received events so it's shown on {@code Dumper.dump()}.
394      */
395     private int mNumberReceivedEvents;
396 
397     /**
398      * Logs the received events so they're shown on {@code Dumper.dump()}.
399      *
400      * <p><b>Note</b>: these events are only logged when {@link #VERBOSE} is {@code true}.
401      */
402     @Nullable
403     private List<UserLifecycleEvent> mEvents;
404 
405     /**
406      * @hide
407      */
CarUserManager(@onNull Car car, @NonNull IBinder service)408     public CarUserManager(@NonNull Car car, @NonNull IBinder service) {
409         this(car, ICarUserService.Stub.asInterface(service),
410                 car.getContext().getSystemService(UserManager.class));
411     }
412 
413     /**
414      * @hide
415      */
416     @VisibleForTesting
CarUserManager(@onNull Car car, @NonNull ICarUserService service, @NonNull UserManager userManager)417     public CarUserManager(@NonNull Car car, @NonNull ICarUserService service,
418             @NonNull UserManager userManager) {
419         super(car);
420 
421         mDumper = addDumpable(car.getContext(), () -> new Dumper());
422         Log.d(TAG, "CarUserManager(): DBG= " + DBG + ", mDumper=" + mDumper);
423 
424         mService = service;
425         mUserManager = userManager;
426     }
427 
428     /**
429      * Switches the foreground user to the given target user.
430      *
431      * @hide
432      */
433     @TestApi
434     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
435             android.Manifest.permission.CREATE_USERS})
436     @AddedInOrBefore(majorVersion = 33)
switchUser(@serIdInt int targetUserId)437     public AsyncFuture<UserSwitchResult> switchUser(@UserIdInt int targetUserId) {
438         int uid = myUid();
439         try {
440             AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() {
441                 @Override
442                 protected void onCompleted(UserSwitchResult result, Throwable err) {
443                     if (result != null) {
444                         EventLogHelper.writeCarUserManagerSwitchUserResp(uid,
445                                 result.getStatus(), result.getErrorMessage());
446                     } else {
447                         Log.w(TAG, "switchUser(" + targetUserId + ") failed: " + err);
448                     }
449                     super.onCompleted(result, err);
450                 }
451             };
452             EventLogHelper.writeCarUserManagerSwitchUserReq(uid, targetUserId);
453             mService.switchUser(targetUserId, HAL_TIMEOUT_MS, future);
454             return new AndroidAsyncFuture<>(future);
455         } catch (SecurityException e) {
456             throw e;
457         } catch (RemoteException | RuntimeException e) {
458             AsyncFuture<UserSwitchResult> future =
459                     newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
460             return handleExceptionFromCarService(e, future);
461         }
462     }
463 
464     /**
465      * Logouts the current user (if it was switched to by a device admin).
466      *
467      * @hide
468      */
469     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
470             android.Manifest.permission.CREATE_USERS})
471     @AddedInOrBefore(majorVersion = 33)
logoutUser()472     public AsyncFuture<UserSwitchResult> logoutUser() {
473         int uid = myUid();
474         try {
475             AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() {
476                 @Override
477                 protected void onCompleted(UserSwitchResult result, Throwable err) {
478                     if (result != null) {
479                         EventLogHelper.writeCarUserManagerLogoutUserResp(uid,
480                                 result.getStatus(), result.getErrorMessage());
481                     } else {
482                         Log.w(TAG, "logoutUser() failed: " + err);
483                     }
484                     super.onCompleted(result, err);
485                 }
486             };
487             EventLogHelper.writeCarUserManagerLogoutUserReq(uid);
488             mService.logoutUser(HAL_TIMEOUT_MS, future);
489             return new AndroidAsyncFuture<>(future);
490         } catch (SecurityException e) {
491             throw e;
492         } catch (RemoteException | RuntimeException e) {
493             AsyncFuture<UserSwitchResult> future =
494                     newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
495             return handleExceptionFromCarService(e, future);
496         }
497     }
498 
newSwitchResuiltForFailure( @serSwitchResult.Status int status)499     private AndroidAsyncFuture<UserSwitchResult> newSwitchResuiltForFailure(
500             @UserSwitchResult.Status int status) {
501         AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
502         future.complete(new UserSwitchResult(status, null));
503         return new AndroidAsyncFuture<>(future);
504     }
505 
createUser(@ullable String name, @NonNull String userType, int flags)506     private AsyncFuture<UserCreationResult> createUser(@Nullable String name,
507             @NonNull String userType, int flags) {
508         int uid = myUid();
509         try {
510             AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
511                 @Override
512                 protected void onCompleted(UserCreationResult result, Throwable err) {
513                     if (result != null) {
514                         EventLogHelper.writeCarUserManagerCreateUserResp(uid,
515                                 result.getStatus(), result.getErrorMessage());
516                     } else {
517                         Log.w(TAG, "createUser(" + userType + "," + flags
518                                 + ") failed: " + err);
519                     }
520                     super.onCompleted(result, err);
521                 };
522             };
523             EventLogHelper.writeCarUserManagerCreateUserReq(uid,
524                     UserHelperLite.safeName(name), userType, flags);
525             mService.createUser(name, userType, flags, HAL_TIMEOUT_MS, future);
526             return new AndroidAsyncFuture<>(future);
527         } catch (SecurityException e) {
528             throw e;
529         } catch (RemoteException | RuntimeException e) {
530             AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
531             future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE));
532             return handleExceptionFromCarService(e, new AndroidAsyncFuture<>(future));
533         }
534     }
535 
536     /**
537      * Creates a new guest Android user.
538      *
539      * @hide
540      */
541     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
542             android.Manifest.permission.CREATE_USERS})
543     @AddedInOrBefore(majorVersion = 33)
createGuest(@ullable String name)544     public AsyncFuture<UserCreationResult> createGuest(@Nullable String name) {
545         return createUser(name, UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0);
546     }
547 
548     /**
549      * Creates a new Android user.
550      *
551      * @hide
552      */
553     @AddedInOrBefore(majorVersion = 33)
554     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
555             android.Manifest.permission.CREATE_USERS})
createUser(@ullable String name, int flags)556     public AsyncFuture<UserCreationResult> createUser(@Nullable String name,
557             int flags) {
558         return createUser(name, UserManager.USER_TYPE_FULL_SECONDARY, flags);
559     }
560 
561     /**
562      * Updates pre-created users.
563      * <p>
564      * Updates pre-created users based on the car properties defined
565      * {@code CarProperties.number_pre_created_guests} and (@code
566      * CarProperties.number_pre_created_users}.
567      *
568      * @hide
569      */
570     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
571             android.Manifest.permission.CREATE_USERS})
572     @AddedInOrBefore(majorVersion = 33)
updatePreCreatedUsers()573     public void updatePreCreatedUsers() {
574         int uid = myUid();
575         EventLogHelper.writeCarUserManagerPreCreateUserReq(uid);
576         try {
577             mService.updatePreCreatedUsers();
578         } catch (SecurityException e) {
579             throw e;
580         } catch (RemoteException | RuntimeException e) {
581             handleExceptionFromCarService(e, null);
582         }
583     }
584 
585     /**
586      * Removes the given user.
587      *
588      * @param userId identification of the user to be removed.
589      *
590      * @return whether the user was successfully removed.
591      *
592      * @hide
593      */
594     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
595             android.Manifest.permission.CREATE_USERS})
596     @NonNull
597     @AddedInOrBefore(majorVersion = 33)
removeUser(@serIdInt int userId)598     public UserRemovalResult removeUser(@UserIdInt int userId) {
599         int uid = myUid();
600         EventLogHelper.writeCarUserManagerRemoveUserReq(uid, userId);
601         int status = UserRemovalResult.STATUS_ANDROID_FAILURE;
602         try {
603             AndroidFuture<UserRemovalResult> future = new AndroidFuture<UserRemovalResult>();
604             mService.removeUser(userId, future);
605             UserRemovalResult result = future.get(REMOVE_USER_CALL_TIMEOUT_MS,
606                     TimeUnit.MILLISECONDS);
607             status = result.getStatus();
608             return result;
609         } catch (SecurityException e) {
610             throw e;
611         } catch (InterruptedException e) {
612             Thread.currentThread().interrupt();
613             return new UserRemovalResult(UserRemovalResult.STATUS_ANDROID_FAILURE);
614         } catch (ExecutionException | TimeoutException e) {
615             return new UserRemovalResult(UserRemovalResult.STATUS_ANDROID_FAILURE);
616         } catch (RemoteException | RuntimeException e) {
617             return handleExceptionFromCarService(e,
618                     new UserRemovalResult(UserRemovalResult.STATUS_ANDROID_FAILURE));
619         } finally {
620             EventLogHelper.writeCarUserManagerRemoveUserResp(uid, status);
621         }
622     }
623 
624     /**
625      * Adds a listener for {@link UserLifecycleEvent user lifecycle events}.
626      *
627      * @throws IllegalStateException if the listener was already added.
628      *
629      * @hide
630      */
631     @SystemApi
632     @TestApi
633     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
634     @AddedInOrBefore(majorVersion = 33)
addListener(@onNull @allbackExecutor Executor executor, @NonNull UserLifecycleListener listener)635     public void addListener(@NonNull @CallbackExecutor Executor executor,
636             @NonNull UserLifecycleListener listener) {
637         addListenerInternal(executor, /* filter= */null, listener);
638     }
639 
640     /**
641      * Adds a listener for {@link UserLifecycleEvent user lifecycle events} with a filter that can
642      * specify a specific event type or a user id.
643      *
644      * @throws IllegalStateException if the listener was already added.
645      *
646      * @hide
647      */
648     @SystemApi
649     @TestApi
650     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
651     @AddedInOrBefore(majorVersion = 33)
addListener(@onNull @allbackExecutor Executor executor, @NonNull UserLifecycleEventFilter filter, @NonNull UserLifecycleListener listener)652     public void addListener(@NonNull @CallbackExecutor Executor executor,
653             @NonNull UserLifecycleEventFilter filter, @NonNull UserLifecycleListener listener) {
654         Objects.requireNonNull(filter, "filter cannot be null");
655 
656         addListenerInternal(executor, filter, listener);
657     }
658 
addListenerInternal(@allbackExecutor Executor executor, @Nullable UserLifecycleEventFilter filter, UserLifecycleListener listener)659     private void addListenerInternal(@CallbackExecutor Executor executor,
660             @Nullable UserLifecycleEventFilter filter, UserLifecycleListener listener) {
661         Objects.requireNonNull(executor, "executor cannot be null");
662         Objects.requireNonNull(listener, "listener cannot be null");
663 
664         int uid = myUid();
665         String packageName = getContext().getPackageName();
666         if (DBG) {
667             Log.d(TAG, "addListener(): uid=" + uid + ", pkg=" + packageName
668                     + ", listener=" + listener + ", filter= " + filter);
669         }
670         synchronized (mLock) {
671             Preconditions.checkState(mListeners == null || !mListeners.containsKey(listener),
672                     "already called for this listener");
673             if (mReceiver == null) {
674                 mReceiver = new LifecycleResultReceiver();
675                 if (DBG) {
676                     Log.d(TAG, "Setting lifecycle receiver with filter " + filter
677                             + " for uid " + uid + " and package " + packageName);
678                 }
679             } else {
680                 if (DBG) {
681                     Log.d(TAG, "Already set receiver for uid " + uid + " and package "
682                             + packageName + " adding new filter " + filter);
683                 }
684             }
685             try {
686                 boolean hasFilter = filter != null;
687                 EventLogHelper.writeCarUserManagerAddListener(uid, packageName, hasFilter);
688                 mService.setLifecycleListenerForApp(packageName, filter, mReceiver);
689             } catch (RemoteException e) {
690                 handleRemoteExceptionFromCarService(e);
691             }
692 
693             if (mListeners == null) {
694                 mListeners = new ArrayMap<>(1); // Most likely app will have just one listener
695             } else if (DBG) {
696                 Log.d(TAG, "addListener(" + getLambdaName(listener) + "): context " + getContext()
697                         + " already has " + mListeners.size() + " listeners: "
698                         + mListeners.keySet().stream()
699                                 .map((l) -> getLambdaName(l))
700                                 .collect(Collectors.toList()), new Exception("caller's stack"));
701             }
702             if (DBG) Log.d(TAG, "Adding listener: " + listener + " with filter " + filter);
703             mListeners.put(listener, Pair.create(filter, executor));
704         }
705     }
706 
707     /**
708      * Removes a listener for {@link UserLifecycleEvent user lifecycle events}.
709      *
710      * @throws IllegalStateException if the listener was not added beforehand.
711      *
712      * @hide
713      */
714     @SystemApi
715     @TestApi
716     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
717     @AddedInOrBefore(majorVersion = 33)
removeListener(@onNull UserLifecycleListener listener)718     public void removeListener(@NonNull UserLifecycleListener listener) {
719         Objects.requireNonNull(listener, "listener cannot be null");
720 
721         int uid = myUid();
722         String packageName = getContext().getPackageName();
723         if (DBG) {
724             Log.d(TAG, "removeListener(): uid=" + uid + ", pkg=" + packageName
725                     + ", listener=" + listener);
726         }
727         synchronized (mLock) {
728             Preconditions.checkState(mListeners != null && mListeners.containsKey(listener),
729                     "not called for this listener yet");
730             mListeners.remove(listener);
731 
732             // Note that there can be some rare corner cases that a listener is removed but its
733             // corresponding filter remains in the service side. This may cause slight inefficiency
734             // due to unnecessary receiver calls. It will still be functionally correct, because the
735             // removed listener will no longer be invoked.
736             if (!mListeners.isEmpty()) {
737                 if (DBG) Log.d(TAG, "removeListeners(): still " + mListeners.size() + " left");
738                 return;
739             }
740             mListeners = null;
741 
742             if (mReceiver == null) {
743                 Log.wtf(TAG, "removeListener(): receiver already null");
744                 return;
745             }
746 
747             EventLogHelper.writeCarUserManagerRemoveListener(uid, packageName);
748             if (DBG) {
749                 Log.d(TAG, "Removing lifecycle receiver for uid=" + uid + " and package "
750                         + packageName);
751             }
752             try {
753                 mService.resetLifecycleListenerForApp(mReceiver);
754                 mReceiver = null;
755             } catch (RemoteException e) {
756                 handleRemoteExceptionFromCarService(e);
757             }
758         }
759     }
760 
761     /**
762      * Check if user hal supports user association.
763      *
764      * @hide
765      */
766     @AddedInOrBefore(majorVersion = 33)
isUserHalUserAssociationSupported()767     public boolean isUserHalUserAssociationSupported() {
768         try {
769             return mService.isUserHalUserAssociationSupported();
770         } catch (RemoteException | RuntimeException e) {
771             return handleExceptionFromCarService(e, false);
772         }
773     }
774 
775     /**
776      * Gets the user authentication types associated with this manager's user.
777      *
778      * @hide
779      */
780     @NonNull
781     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
782             android.Manifest.permission.CREATE_USERS})
783     @AddedInOrBefore(majorVersion = 33)
getUserIdentificationAssociation( @serIdentificationAssociationType int... types)784     public UserIdentificationAssociationResponse getUserIdentificationAssociation(
785             @UserIdentificationAssociationType int... types) {
786         Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
787         EventLogHelper.writeCarUserManagerGetUserAuthReq(convertToObjectArray(types));
788         try {
789             UserIdentificationAssociationResponse response =
790                     mService.getUserIdentificationAssociation(types);
791             if (response != null) {
792                 int[] values = response.getValues();
793                 EventLogHelper.writeCarUserManagerGetUserAuthResp(convertToObjectArray(values));
794             }
795             return response;
796         } catch (SecurityException e) {
797             throw e;
798         } catch (RemoteException | RuntimeException e) {
799             return handleExceptionFromCarService(e,
800                     UserIdentificationAssociationResponse.forFailure(e.getMessage()));
801         }
802     }
803 
convertToObjectArray(int[] input)804     private Object[] convertToObjectArray(int[] input) {
805         if (input == null) return null;
806         Object[] output = new Object[input.length];
807         for (int i = 0; i < input.length; i++) {
808             output[i] = input[i];
809         }
810         return output;
811     }
812 
813     /**
814      * Sets the user authentication types associated with this manager's user.
815      *
816      * @hide
817      */
818     @NonNull
819     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
820             android.Manifest.permission.CREATE_USERS})
821     @AddedInOrBefore(majorVersion = 33)
setUserIdentificationAssociation( @serIdentificationAssociationType int[] types, @UserIdentificationAssociationSetValue int[] values)822     public AsyncFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation(
823             @UserIdentificationAssociationType int[] types,
824             @UserIdentificationAssociationSetValue int[] values) {
825         Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
826         Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
827         if (types.length != values.length) {
828             throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
829                     + Arrays.toString(values) + ") should have the same length");
830         }
831         // TODO(b/153900032): move this logic to a common helper
832         Object[] loggedValues = new Integer[types.length * 2];
833         for (int i = 0; i < types.length; i++) {
834             loggedValues[i * 2] = types[i];
835             loggedValues[i * 2 + 1 ] = values[i];
836         }
837         EventLogHelper.writeCarUserManagerSetUserAuthReq(loggedValues);
838 
839         try {
840             AndroidFuture<UserIdentificationAssociationResponse> future =
841                     new AndroidFuture<UserIdentificationAssociationResponse>() {
842                 @Override
843                 protected void onCompleted(UserIdentificationAssociationResponse result,
844                         Throwable err) {
845                     if (result != null) {
846                         int[] rawValues = result.getValues();
847                         // TODO(b/153900032): move this logic to a common helper
848                         if (rawValues != null) {
849                             Object[] loggedValues = new Object[rawValues.length];
850                             for (int i = 0; i < rawValues.length; i++) {
851                                 loggedValues[i] = rawValues[i];
852                             }
853                             EventLogHelper.writeCarUserManagerSetUserAuthResp(loggedValues);
854                         }
855                     } else {
856                         Log.w(TAG, "setUserIdentificationAssociation(" + Arrays.toString(types)
857                                 + ", " + Arrays.toString(values) + ") failed: " + err);
858                     }
859                     super.onCompleted(result, err);
860                 };
861             };
862             mService.setUserIdentificationAssociation(HAL_TIMEOUT_MS, types, values, future);
863             return new AndroidAsyncFuture<>(future);
864         } catch (SecurityException e) {
865             throw e;
866         } catch (RemoteException | RuntimeException e) {
867             AndroidFuture<UserIdentificationAssociationResponse> future = new AndroidFuture<>();
868             future.complete(UserIdentificationAssociationResponse.forFailure());
869             return handleExceptionFromCarService(e, new AndroidAsyncFuture<>(future));
870         }
871     }
872 
873     /**
874      * Sets a callback to be notified before user switch. It should only be used by Car System UI.
875      *
876      * @hide
877      */
878     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
879     @AddedInOrBefore(majorVersion = 33)
setUserSwitchUiCallback(@onNull UserSwitchUiCallback callback)880     public void setUserSwitchUiCallback(@NonNull UserSwitchUiCallback callback) {
881         Preconditions.checkArgument(callback != null, "Null callback");
882         UserSwitchUiCallbackReceiver userSwitchUiCallbackReceiver =
883                 new UserSwitchUiCallbackReceiver(callback);
884         try {
885             mService.setUserSwitchUiCallback(userSwitchUiCallbackReceiver);
886         } catch (RemoteException e) {
887             handleRemoteExceptionFromCarService(e);
888         }
889     }
890 
891     /**
892      * {@code ICarResultReceiver} used to receive user switch UI Callback.
893      */
894     // TODO(b/154958003): use mReceiver instead as now there are two binder objects
895     private final class UserSwitchUiCallbackReceiver extends ICarResultReceiver.Stub {
896 
897         private final UserSwitchUiCallback mUserSwitchUiCallback;
898 
UserSwitchUiCallbackReceiver(UserSwitchUiCallback callback)899         UserSwitchUiCallbackReceiver(UserSwitchUiCallback callback) {
900             mUserSwitchUiCallback = callback;
901         }
902 
903         @Override
send(int userId, Bundle unused)904         public void send(int userId, Bundle unused) throws RemoteException {
905             mUserSwitchUiCallback.showUserSwitchDialog(userId);
906         }
907     }
908 
909     /**
910      * {@code ICarResultReceiver} used to receive lifecycle events and dispatch to the proper
911      * listener.
912      */
913     private class LifecycleResultReceiver extends ICarResultReceiver.Stub {
914         @Override
send(int resultCode, Bundle resultData)915         public void send(int resultCode, Bundle resultData) {
916             if (resultData == null) {
917                 Log.w(TAG, "Received result (" + resultCode + ") without data");
918                 return;
919             }
920             int from = resultData.getInt(BUNDLE_PARAM_PREVIOUS_USER_ID,
921                     UserManagerHelper.USER_NULL);
922             int to = resultCode;
923             int eventType = resultData.getInt(BUNDLE_PARAM_ACTION);
924             UserLifecycleEvent event = new UserLifecycleEvent(eventType, from, to);
925             ArrayMap<UserLifecycleListener, Pair<UserLifecycleEventFilter, Executor>> listeners;
926             synchronized (mLock) {
927                 if (mListeners == null) {
928                     Log.w(TAG, "No listeners for event " + event);
929                     return;
930                 }
931                 listeners = new ArrayMap<>(mListeners);
932             }
933             int size = listeners.size();
934             EventLogHelper.writeCarUserManagerNotifyLifecycleListener(size, eventType, from, to);
935             for (int i = 0; i < size; i++) {
936                 UserLifecycleListener listener = listeners.keyAt(i);
937                 UserLifecycleEventFilter filter = listeners.valueAt(i).first;
938                 if (filter != null && !filter.apply(event)) {
939                     if (DBG) {
940                         Log.d(TAG, "Listener " + getLambdaName(listener)
941                                 + " is skipped for the event " + event + " due to the filter "
942                                 + filter);
943                     }
944                     continue;
945                 }
946                 Executor executor = listeners.valueAt(i).second;
947                 if (DBG) {
948                     Log.d(TAG, "Calling " + getLambdaName(listener) + " for event " + event);
949                 }
950                 executor.execute(() -> listener.onEvent(event));
951             }
952             mNumberReceivedEvents++;
953             if (VERBOSE) {
954                 if (mEvents == null) {
955                     mEvents = new ArrayList<>();
956                 }
957                 mEvents.add(event);
958             }
959         }
960     }
961 
962     /** @hide */
963     @Override
964     @AddedInOrBefore(majorVersion = 33)
onCarDisconnected()965     public void onCarDisconnected() {
966         // nothing to do
967     }
968 
969     private final class Dumper implements Dumpable {
970         @Override
dump(PrintWriter pw, String[] args)971         public void dump(PrintWriter pw, String[] args) {
972             String prefix = "  ";
973 
974             pw.printf("DBG=%b, VERBOSE=%b\n", DBG, VERBOSE);
975             int listenersSize = 0;
976             synchronized (mLock) {
977                 pw.printf("mReceiver: %s\n", mReceiver);
978                 if (mListeners == null) {
979                     pw.println("no listeners");
980                 } else {
981                     listenersSize = mListeners.size();
982                     pw.printf("%d listeners\n", listenersSize);
983                 }
984                 if (DBG) {
985                     for (int i = 0; i < listenersSize; i++) {
986                         pw.printf("%s%d: %s\n", prefix, i + 1, mListeners.keyAt(i));
987                     }
988                 }
989             }
990             pw.printf("mNumberReceivedEvents: %d\n", mNumberReceivedEvents);
991             if (VERBOSE && mEvents != null) {
992                 for (int i = 0; i < mEvents.size(); i++) {
993                     pw.printf("%s%d: %s\n", prefix, i + 1, mEvents.get(i));
994                 }
995             }
996         }
997 
998         @Override
getDumpableName()999         public String getDumpableName() {
1000             return CarUserManager.class.getSimpleName();
1001         }
1002     }
1003 
1004     /**
1005      * @hide
1006      */
1007     @TestApi
1008     @AddedInOrBefore(majorVersion = 33)
lifecycleEventTypeToString(@serLifecycleEventType int type)1009     public static String lifecycleEventTypeToString(@UserLifecycleEventType int type) {
1010         switch (type) {
1011             case USER_LIFECYCLE_EVENT_TYPE_STARTING:
1012                 return "STARTING";
1013             case USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
1014                 return "SWITCHING";
1015             case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING:
1016                 return "UNLOCKING";
1017             case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
1018                 return "UNLOCKED";
1019             case USER_LIFECYCLE_EVENT_TYPE_STOPPING:
1020                 return "STOPPING";
1021             case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
1022                 return "STOPPED";
1023             case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED:
1024                 return "POST_UNLOCKED";
1025             case USER_LIFECYCLE_EVENT_TYPE_CREATED:
1026                 return "CREATED";
1027             case USER_LIFECYCLE_EVENT_TYPE_REMOVED:
1028                 return "REMOVED";
1029             default:
1030                 return "UNKNOWN-" + type;
1031         }
1032     }
1033 
1034     /**
1035      * Checks if the given {@code userId} represents a valid user.
1036      *
1037      * <p>A "valid" user:
1038      *
1039      * <ul>
1040      *   <li>Must exist in the device.
1041      *   <li>Is not in the process of being deleted.
1042      *   <li>Cannot be the {@link UserHandle#isSystem() system} user on devices that use
1043      *   {@link UserManager#isHeadlessSystemUserMode() headless system mode}.
1044      * </ul>
1045      *
1046      * @hide
1047      */
1048     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
1049             android.Manifest.permission.CREATE_USERS})
1050     @AddedInOrBefore(majorVersion = 33)
isValidUser(@serIdInt int userId)1051     public boolean isValidUser(@UserIdInt int userId) {
1052         List<UserHandle> allUsers = mUserManager.getUserHandles(/* excludeDying=*/ true);
1053         for (int i = 0; i < allUsers.size(); i++) {
1054             UserHandle user = allUsers.get(i);
1055             if (user.getIdentifier() == userId && (userId != UserHandle.SYSTEM.getIdentifier()
1056                     || !UserManager.isHeadlessSystemUserMode())) {
1057                 return true;
1058             }
1059         }
1060         return false;
1061     }
1062 
1063     /**
1064      * Defines a lifecycle event for an Android user.
1065      *
1066      * @hide
1067      */
1068     @SystemApi
1069     @TestApi
1070     public static final class UserLifecycleEvent {
1071         private final @UserLifecycleEventType int mEventType;
1072         private final @UserIdInt int mUserId;
1073         private final @UserIdInt int mPreviousUserId;
1074 
1075         /** @hide */
UserLifecycleEvent(@serLifecycleEventType int eventType, @UserIdInt int from, @UserIdInt int to)1076         public UserLifecycleEvent(@UserLifecycleEventType int eventType,
1077                 @UserIdInt int from, @UserIdInt int to) {
1078             mEventType = eventType;
1079             mPreviousUserId = from;
1080             mUserId = to;
1081         }
1082 
1083         /** @hide */
UserLifecycleEvent(@serLifecycleEventType int eventType, @UserIdInt int to)1084         public UserLifecycleEvent(@UserLifecycleEventType int eventType, @UserIdInt int to) {
1085             this(eventType, UserManagerHelper.USER_NULL, to);
1086         }
1087 
1088         /**
1089          * Gets the event type.
1090          *
1091          * @return either {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STARTING},
1092          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING},
1093          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKING},
1094          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED},
1095          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPING} or
1096          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPED} for all apps;
1097          * for apps {@link CarPackageManager#getTargetCarVersion() targeting car version}
1098          * {@link CarVersion.VERSION_CODES#TIRAMISU_1} or higher, it could be new types
1099          * added on later releases, such as
1100          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED},
1101          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED} and possibly others.
1102          *
1103          */
1104         @UserLifecycleEventType
1105         @AddedInOrBefore(majorVersion = 33)
getEventType()1106         public int getEventType() {
1107             return mEventType;
1108         }
1109 
1110         /**
1111          * Gets the id of the user whose event is being reported.
1112          *
1113          * @hide
1114          */
1115         @UserIdInt
1116         @AddedInOrBefore(majorVersion = 33)
getUserId()1117         public int getUserId() {
1118             return mUserId;
1119         }
1120 
1121         /**
1122          * Gets the handle of the user whose event is being reported.
1123          */
1124         @NonNull
1125         @AddedInOrBefore(majorVersion = 33)
getUserHandle()1126         public UserHandle getUserHandle() {
1127             return UserHandle.of(mUserId);
1128         }
1129 
1130         /**
1131          * Gets the id of the user being switched from.
1132          *
1133          * <p>This method returns {@link UserHandle#USER_NULL} for all event types but
1134          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}.
1135          *
1136          * @hide
1137          */
1138         @UserIdInt
1139         @AddedInOrBefore(majorVersion = 33)
getPreviousUserId()1140         public int getPreviousUserId() {
1141             return mPreviousUserId;
1142         }
1143 
1144         /**
1145          * Gets the handle of the user being switched from.
1146          *
1147          * <p>This method returns {@code null} for all event types but
1148          * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}.
1149          */
1150         @Nullable
1151         @AddedInOrBefore(majorVersion = 33)
getPreviousUserHandle()1152         public UserHandle getPreviousUserHandle() {
1153             return mPreviousUserId == UserManagerHelper.USER_NULL ? null
1154                     : UserHandle.of(mPreviousUserId);
1155         }
1156 
1157         @Override
1158         @AddedInOrBefore(majorVersion = 33)
toString()1159         public String toString() {
1160             StringBuilder builder = new StringBuilder("Event[type=")
1161                     .append(lifecycleEventTypeToString(mEventType));
1162             if (mPreviousUserId != UserManagerHelper.USER_NULL) {
1163                 builder
1164                     .append(",from=").append(mPreviousUserId)
1165                     .append(",to=").append(mUserId);
1166             } else {
1167                 builder.append(",user=").append(mUserId);
1168             }
1169 
1170             return builder.append(']').toString();
1171         }
1172 
1173         @Override
1174         @AddedInOrBefore(majorVersion = 33)
equals(@ullable Object o)1175         public boolean equals(@Nullable Object o) {
1176             if (this == o) return true;
1177             if (o == null || getClass() != o.getClass()) return false;
1178 
1179             UserLifecycleEvent that = (UserLifecycleEvent) o;
1180             return mEventType == that.mEventType && mUserId == that.mUserId
1181                     && mPreviousUserId == that.mPreviousUserId;
1182         }
1183 
1184         @Override
1185         @AddedInOrBefore(majorVersion = 33)
hashCode()1186         public int hashCode() {
1187             int hash = 23;
1188             hash = 17 * hash + mEventType;
1189             hash = 17 * hash + mUserId;
1190             hash = 17 * hash + mPreviousUserId;
1191 
1192             return hash;
1193         }
1194     }
1195 
1196     /**
1197      * Listener for Android User lifecycle events.
1198      *
1199      * <p>Must be registered using {@link CarUserManager#addListener(UserLifecycleListener)} and
1200      * unregistered through {@link CarUserManager#removeListener(UserLifecycleListener)}.
1201      *
1202      * @hide
1203      */
1204     @SystemApi
1205     @TestApi
1206     public interface UserLifecycleListener {
1207 
1208         /**
1209          * Called to notify the given {@code event}.
1210          */
1211         @AddedInOrBefore(majorVersion = 33)
onEvent(@onNull UserLifecycleEvent event)1212         void onEvent(@NonNull UserLifecycleEvent event);
1213     }
1214 
1215     /**
1216      * Callback for notifying user switch before switch started.
1217      *
1218      * <p> It should only be user by Car System UI. The purpose of this callback is notify the
1219      * Car System UI to display the user switch UI.
1220      *
1221      * @hide
1222      */
1223     public interface UserSwitchUiCallback {
1224 
1225         /**
1226          * Called to notify that user switch dialog should be shown now.
1227          */
1228         @AddedInOrBefore(majorVersion = 33)
showUserSwitchDialog(@serIdInt int userId)1229         void showUserSwitchDialog(@UserIdInt int userId);
1230     }
1231 }
1232