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