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