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