• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package com.android.car.user;
17 
18 import static com.android.car.CarServiceUtils.getContentResolverForUser;
19 import static com.android.car.CarServiceUtils.isVisibleBackgroundUsersOnDefaultDisplaySupported;
20 import static com.android.car.hal.UserHalHelper.userFlagsToString;
21 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
22 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
23 import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeastU;
24 
25 import android.annotation.IntDef;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.UserIdInt;
29 import android.app.ActivityManager;
30 import android.car.builtin.app.ActivityManagerHelper;
31 import android.car.builtin.os.TraceHelper;
32 import android.car.builtin.os.UserManagerHelper;
33 import android.car.builtin.provider.SettingsHelper;
34 import android.car.builtin.util.EventLogHelper;
35 import android.car.builtin.util.Slogf;
36 import android.car.builtin.util.TimingsTraceLog;
37 import android.car.builtin.widget.LockPatternHelper;
38 import android.car.settings.CarSettings;
39 import android.content.Context;
40 import android.hardware.automotive.vehicle.InitialUserInfoRequestType;
41 import android.hardware.automotive.vehicle.UserInfo;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.provider.Settings;
45 import android.util.Pair;
46 
47 import com.android.car.CarLog;
48 import com.android.car.R;
49 import com.android.car.hal.UserHalHelper;
50 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
51 import com.android.car.internal.common.UserHelperLite;
52 import com.android.car.internal.os.CarSystemProperties;
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.util.Preconditions;
55 
56 import java.io.PrintWriter;
57 import java.lang.annotation.Retention;
58 import java.lang.annotation.RetentionPolicy;
59 import java.util.ArrayList;
60 import java.util.Collections;
61 import java.util.Iterator;
62 import java.util.List;
63 import java.util.function.Consumer;
64 
65 /**
66  * Helper used to set the initial Android user on boot or when resuming from RAM.
67  */
68 final class InitialUserSetter {
69 
70     @VisibleForTesting
71     static final String TAG = CarLog.tagFor(InitialUserSetter.class);
72 
73     private static final boolean DBG = false;
74     private static final int BOOT_USER_NOT_FOUND = -1;
75 
76     /**
77      * Sets the initial user using the default behavior.
78      *
79      * <p>The default behavior is:
80      *
81      * <ol>
82      *  <li>On first boot, it creates and switches to a new user.
83      *  <li>Otherwise, it will switch to either:
84      *  <ol>
85      *   <li>User defined by {@code android.car.systemuser.bootuseroverrideid} (when it was
86      * constructed with such option enabled).
87      *   <li>Last active user (as defined by
88      * {@link android.provider.Settings.Global.LAST_ACTIVE_USER_ID}.
89      *  </ol>
90      * </ol>
91      */
92     public static final int TYPE_DEFAULT_BEHAVIOR = 0;
93 
94     /**
95      * Switches to the given user, falling back to {@link #fallbackDefaultBehavior(String)} if it
96      * fails.
97      */
98     public static final int TYPE_SWITCH = 1;
99 
100     /**
101      * Creates a new user and switches to it, falling back to
102      * {@link #fallbackDefaultBehavior(String) if any of these steps fails.
103      *
104      * @param name (optional) name of the new user
105      * @param halFlags user flags as defined by Vehicle HAL ({@code UserFlags} enum).
106      */
107     public static final int TYPE_CREATE = 2;
108 
109     /**
110      * Creates a new guest user and switches to it, if current user is unlocked guest user.
111      * Does not fallback if any of these steps fails. falling back to
112      * {@link #fallbackDefaultBehavior(String) if any of these steps fails
113      */
114     public static final int TYPE_REPLACE_GUEST = 3;
115 
116     @IntDef(prefix = { "TYPE_" }, value = {
117             TYPE_DEFAULT_BEHAVIOR,
118             TYPE_SWITCH,
119             TYPE_CREATE,
120             TYPE_REPLACE_GUEST
121     })
122     @Retention(RetentionPolicy.SOURCE)
123     public @interface InitialUserInfoType { }
124 
125     private final Context mContext;
126 
127     // TODO(b/150413304): abstract AM / UM into interfaces, then provide local and remote
128     // implementation (where local is implemented by ActivityManagerInternal / UserManagerInternal)
129     private final UserManager mUm;
130     private final CarUserService mCarUserService;
131 
132     private final String mNewUserName;
133     private final String mNewGuestName;
134 
135     private final Consumer<UserHandle> mListener;
136 
137     private final UserHandleHelper mUserHandleHelper;
138 
139     private final boolean mIsVisibleBackgroundUsersOnDefaultDisplaySupported;
140 
InitialUserSetter(@onNull Context context, @NonNull CarUserService carUserService, @NonNull Consumer<UserHandle> listener, @NonNull UserHandleHelper userHandleHelper)141     InitialUserSetter(@NonNull Context context, @NonNull CarUserService carUserService,
142             @NonNull Consumer<UserHandle> listener, @NonNull UserHandleHelper userHandleHelper) {
143         this(context, carUserService, listener, userHandleHelper,
144                 context.getString(R.string.default_guest_name));
145     }
146 
InitialUserSetter(@onNull Context context, @NonNull CarUserService carUserService, @NonNull Consumer<UserHandle> listener, @NonNull UserHandleHelper userHandleHelper, @Nullable String newGuestName)147     InitialUserSetter(@NonNull Context context, @NonNull CarUserService carUserService,
148             @NonNull Consumer<UserHandle> listener, @NonNull UserHandleHelper userHandleHelper,
149             @Nullable String newGuestName) {
150         this(context, context.getSystemService(UserManager.class), carUserService, listener,
151                 userHandleHelper, UserManagerHelper.getDefaultUserName(context), newGuestName);
152     }
153 
154     @VisibleForTesting
InitialUserSetter(@onNull Context context, @NonNull UserManager um, @NonNull CarUserService carUserService, @NonNull Consumer<UserHandle> listener, @NonNull UserHandleHelper userHandleHelper, @Nullable String newUserName, @Nullable String newGuestName)155     InitialUserSetter(@NonNull Context context, @NonNull UserManager um,
156             @NonNull CarUserService carUserService, @NonNull Consumer<UserHandle> listener,
157             @NonNull UserHandleHelper userHandleHelper, @Nullable String newUserName,
158             @Nullable String newGuestName) {
159         mContext = context;
160         mUm = um;
161         mCarUserService = carUserService;
162         mListener = listener;
163         mUserHandleHelper = userHandleHelper;
164         mNewUserName = newUserName;
165         mNewGuestName = newGuestName;
166         mIsVisibleBackgroundUsersOnDefaultDisplaySupported =
167                 isVisibleBackgroundUsersOnDefaultDisplaySupported(mUm);
168     }
169 
170     /**
171      * Builder for {@link InitialUserInfo} objects.
172      *
173      */
174     public static final class Builder {
175 
176         private final @InitialUserInfoType int mType;
177         private boolean mReplaceGuest;
178         private @UserIdInt int mSwitchUserId;
179         private @Nullable String mNewUserName;
180         private int mNewUserFlags;
181         private boolean mSupportsOverrideUserIdProperty;
182         private @Nullable String mUserLocales;
183         private int mRequestType;
184 
185         /**
186          * Constructor for the given type.
187          *
188          * @param type {@link #TYPE_DEFAULT_BEHAVIOR}, {@link #TYPE_SWITCH},
189          * {@link #TYPE_CREATE} or {@link #TYPE_REPLACE_GUEST}.
190          */
Builder(@nitialUserInfoType int type)191         public Builder(@InitialUserInfoType int type) {
192             Preconditions.checkArgument(type == TYPE_DEFAULT_BEHAVIOR || type == TYPE_SWITCH
193                     || type == TYPE_CREATE || type == TYPE_REPLACE_GUEST, "invalid builder type");
194             mType = type;
195         }
196 
197         /**
198          * Sets the request type for {@link InitialUserInfoRequestType}.
199          */
setRequestType(int requestType)200         public Builder setRequestType(int requestType) {
201             mRequestType = requestType;
202             return this;
203         }
204 
205         /**
206          * Sets the id of the user to be switched to.
207          *
208          * @throws IllegalArgumentException if builder is not for {@link #TYPE_SWITCH}.
209          */
210         @NonNull
setSwitchUserId(@serIdInt int userId)211         public Builder setSwitchUserId(@UserIdInt int userId) {
212             Preconditions.checkArgument(mType == TYPE_SWITCH, "invalid builder type: " + mType);
213             mSwitchUserId = userId;
214             return this;
215         }
216 
217         /**
218          * Sets whether the current user should be replaced when it's a guest.
219          */
220         @NonNull
setReplaceGuest(boolean value)221         public Builder setReplaceGuest(boolean value) {
222             mReplaceGuest = value;
223             return this;
224         }
225 
226         /**
227          * Sets the name of the new user being created.
228          *
229          * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}.
230          */
231         @NonNull
setNewUserName(@ullable String name)232         public Builder setNewUserName(@Nullable String name) {
233             Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType);
234             mNewUserName = name;
235             return this;
236         }
237 
238         /**
239          * Sets the flags (as defined by {@link android.hardware.automotive.vehicle.UserInfo})
240          * of the new user being created.
241          *
242          * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}.
243          */
244         @NonNull
setNewUserFlags(int flags)245         public Builder setNewUserFlags(int flags) {
246             Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType);
247             mNewUserFlags = flags;
248             return this;
249         }
250 
251         /**
252          * Sets whether the {@code CarProperties#boot_user_override_id()} should be taking in
253          * account when using the default behavior.
254          */
255         @NonNull
setSupportsOverrideUserIdProperty(boolean value)256         public Builder setSupportsOverrideUserIdProperty(boolean value) {
257             mSupportsOverrideUserIdProperty = value;
258             return this;
259         }
260 
261         /**
262          * Sets the system locales for the initial user (when it's created).
263          */
264         @NonNull
setUserLocales(@ullable String userLocales)265         public Builder setUserLocales(@Nullable String userLocales) {
266             // This string can come from a binder IPC call where empty string is the default value
267             // for the auto-generated code. So, need to check for that.
268             if (userLocales != null && userLocales.trim().isEmpty()) {
269                 mUserLocales = null;
270             } else {
271                 mUserLocales = userLocales;
272             }
273             return this;
274         }
275 
276         /**
277          * Builds the object.
278          */
279         @NonNull
build()280         public InitialUserInfo build() {
281             return new InitialUserInfo(this);
282         }
283     }
284 
285     /**
286      * Object used to define the properties of the initial user (which can then be set by
287      * {@link InitialUserSetter#set(InitialUserInfo)});
288      */
289     public static final class InitialUserInfo {
290         public final @InitialUserInfoType int type;
291         public final boolean replaceGuest;
292         public final @UserIdInt int switchUserId;
293         public final @Nullable String newUserName;
294         public final int newUserFlags;
295         public final boolean supportsOverrideUserIdProperty;
296         public @Nullable String userLocales;
297         public final int requestType;
298 
InitialUserInfo(@onNull Builder builder)299         private InitialUserInfo(@NonNull Builder builder) {
300             type = builder.mType;
301             switchUserId = builder.mSwitchUserId;
302             replaceGuest = builder.mReplaceGuest;
303             newUserName = builder.mNewUserName;
304             newUserFlags = builder.mNewUserFlags;
305             supportsOverrideUserIdProperty = builder.mSupportsOverrideUserIdProperty;
306             userLocales = builder.mUserLocales;
307             requestType = builder.mRequestType;
308         }
309 
310         @Override
311         @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
toString()312         public String toString() {
313             StringBuilder string = new StringBuilder("InitialUserInfo[type=");
314             switch(type) {
315                 case TYPE_DEFAULT_BEHAVIOR:
316                     string.append("DEFAULT_BEHAVIOR");
317                     break;
318                 case TYPE_REPLACE_GUEST:
319                     string.append("REPLACE_GUEST");
320                     break;
321                 case TYPE_SWITCH:
322                     string.append("SWITCH").append(",userId=").append(switchUserId);
323                     break;
324                 case TYPE_CREATE:
325                     string.append("CREATE").append(",flags=")
326                             .append(UserHalHelper.userFlagsToString(newUserFlags));
327                     if (newUserName != null) {
328                         string.append(",name=" + UserHelperLite.safeName(newUserName));
329                     }
330                     if (userLocales != null) {
331                         string.append(",locales=").append(userLocales);
332                     }
333                     break;
334                 default:
335                     string.append("UNKNOWN:").append(type);
336             }
337             if (replaceGuest) string.append(",replaceGuest");
338             if (supportsOverrideUserIdProperty) string.append(",supportsOverrideUserIdProperty");
339 
340             return string.append(']').toString();
341         }
342     }
343 
344     /**
345      * Sets the initial user.
346      */
set(@onNull InitialUserInfo info)347     public void set(@NonNull InitialUserInfo info) {
348         Preconditions.checkArgument(info != null, "info cannot be null");
349 
350         if (isPlatformVersionAtLeastU()) {
351             EventLogHelper.writeCarInitialUserInfo(info.type, info.replaceGuest, info.switchUserId,
352                     info.newUserName, info.newUserFlags,
353                     info.supportsOverrideUserIdProperty, info.userLocales);
354         }
355 
356         switch (info.type) {
357             case TYPE_DEFAULT_BEHAVIOR:
358                 executeDefaultBehavior(info, /* fallback= */ false);
359                 break;
360             case TYPE_SWITCH:
361                 try {
362                     switchUser(info, /* fallback= */ true);
363                 } catch (Exception e) {
364                     fallbackDefaultBehavior(info, /* fallback= */ true,
365                             "Exception switching user: " + e);
366                 }
367                 break;
368             case TYPE_CREATE:
369                 try {
370                     createAndSwitchUser(info, /* fallback= */ true);
371                 } catch (Exception e) {
372                     fallbackDefaultBehavior(info, /* fallback= */ true,
373                             "Exception createUser user with name "
374                                     + UserHelperLite.safeName(info.newUserName) + " and flags "
375                                     + UserHalHelper.userFlagsToString(info.newUserFlags) + ": "
376                                     + e);
377                 }
378                 break;
379             case TYPE_REPLACE_GUEST:
380                 try {
381                     replaceUser(info, /* fallback= */ true);
382                 } catch (Exception e) {
383                     fallbackDefaultBehavior(info, /* fallback= */ true,
384                             "Exception replace guest user: " + e);
385                 }
386                 break;
387             default:
388                 throw new IllegalArgumentException("invalid InitialUserInfo type: " + info.type);
389         }
390     }
391 
replaceUser(InitialUserInfo info, boolean fallback)392     private void replaceUser(InitialUserInfo info, boolean fallback) {
393         int currentUserId = ActivityManager.getCurrentUser();
394         UserHandle currentUser = mUserHandleHelper.getExistingUserHandle(currentUserId);
395 
396         if (currentUser == null) {
397             Slogf.wtf(TAG, "Current user %d handle doesn't exits ", currentUserId);
398         }
399 
400         UserHandle newUser = replaceGuestIfNeeded(currentUser);
401         if (newUser == null) {
402             fallbackDefaultBehavior(info, fallback,
403                     "could not replace guest " + currentUser);
404             return;
405         }
406 
407         switchUser(new Builder(TYPE_SWITCH)
408                 .setSwitchUserId(newUser.getIdentifier())
409                 .build(), fallback);
410 
411         if (newUser.getIdentifier() != currentUser.getIdentifier()) {
412             Slogf.i(TAG, "Removing old guest %d", currentUser.getIdentifier());
413             if (!mUm.removeUser(currentUser)) {
414                 Slogf.w(TAG, "Could not remove old guest " + currentUser.getIdentifier());
415             }
416         }
417     }
418 
executeDefaultBehavior(@onNull InitialUserInfo info, boolean fallback)419     private void executeDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback) {
420         if (mIsVisibleBackgroundUsersOnDefaultDisplaySupported) {
421             if (DBG) {
422                 Slogf.d(TAG, "executeDefaultBehavior(): "
423                         + "Multi User No Driver switching to system user");
424             }
425             switchUser(new Builder(TYPE_SWITCH)
426                     .setSwitchUserId(UserHandle.SYSTEM.getIdentifier())
427                     .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
428                     .setReplaceGuest(false)
429                     .build(), fallback);
430         } else if (!hasValidInitialUser()) {
431             if (DBG) Slogf.d(TAG, "executeDefaultBehavior(): no initial user, creating it");
432             createAndSwitchUser(new Builder(TYPE_CREATE)
433                     .setNewUserName(mNewUserName)
434                     .setNewUserFlags(UserInfo.USER_FLAG_ADMIN)
435                     .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
436                     .setUserLocales(info.userLocales)
437                     .build(), fallback);
438         } else {
439             if (DBG) Slogf.d(TAG, "executeDefaultBehavior(): switching to initial user");
440             int userId = getInitialUser(info.supportsOverrideUserIdProperty);
441             switchUser(new Builder(TYPE_SWITCH)
442                     .setSwitchUserId(userId)
443                     .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
444                     .setReplaceGuest(info.replaceGuest)
445                     .build(), fallback);
446         }
447     }
448 
449     @VisibleForTesting
fallbackDefaultBehavior(@onNull InitialUserInfo info, boolean fallback, @NonNull String reason)450     void fallbackDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback,
451             @NonNull String reason) {
452         if (!fallback) {
453             // Only log the error
454             Slogf.w(TAG, reason);
455             // Must explicitly tell listener that initial user could not be determined
456             notifyListener(/*initialUser= */ null);
457             return;
458         }
459 
460         if (isPlatformVersionAtLeastU()) {
461             EventLogHelper.writeCarInitialUserFallbackDefaultBehavior(reason);
462         }
463         Slogf.w(TAG, "Falling back to default behavior. Reason: " + reason);
464         executeDefaultBehavior(info, /* fallback= */ false);
465     }
466 
switchUser(@onNull InitialUserInfo info, boolean fallback)467     private void switchUser(@NonNull InitialUserInfo info, boolean fallback) {
468         int userId = info.switchUserId;
469         boolean replaceGuest = info.replaceGuest;
470 
471         if (DBG) {
472             Slogf.d(TAG, "switchUser(): userId=" + userId + ", replaceGuest=" + replaceGuest
473                     + ", fallback=" + fallback);
474         }
475 
476         UserHandle user = mUserHandleHelper.getExistingUserHandle(userId);
477         if (user == null) {
478             fallbackDefaultBehavior(info, fallback, "user with id " + userId + " doesn't exist");
479             return;
480         }
481 
482         UserHandle actualUser = user;
483 
484         if (mUserHandleHelper.isGuestUser(user) && replaceGuest) {
485             actualUser = replaceGuestIfNeeded(user);
486 
487             if (actualUser == null) {
488                 fallbackDefaultBehavior(info, fallback, "could not replace guest " + user);
489                 return;
490             }
491         }
492 
493         int actualUserId = actualUser.getIdentifier();
494 
495         // Keep the old boot user flow for platform before U
496         if (!isPlatformVersionAtLeastU()) {
497             unlockSystemUserIfNecessary(actualUserId);
498         }
499 
500         int currentUserId = ActivityManager.getCurrentUser();
501 
502         if (DBG) {
503             Slogf.d(TAG, "switchUser: currentUserId = %d, actualUserId = %d",
504                     currentUserId, actualUserId);
505         }
506         // TODO(b/266473227): Set isMdnd on InitialUserInfo.
507         if (actualUserId != currentUserId || mIsVisibleBackgroundUsersOnDefaultDisplaySupported) {
508             if (!startForegroundUser(info, actualUserId)) {
509                 fallbackDefaultBehavior(info, fallback,
510                         "am.switchUser(" + actualUserId + ") failed");
511                 return;
512             }
513             setLastActiveUser(actualUserId);
514         }
515         notifyListener(actualUser);
516 
517         if (actualUserId != userId) {
518             Slogf.i(TAG, "Removing old guest " + userId);
519             if (!mUm.removeUser(user)) {
520                 Slogf.w(TAG, "Could not remove old guest " + userId);
521             }
522         }
523     }
524 
unlockSystemUserIfNecessary(@serIdInt int userId)525     private void unlockSystemUserIfNecessary(@UserIdInt int userId) {
526         // If system user is the only user to unlock, it will be handled when boot is complete.
527         if (userId != UserHandle.SYSTEM.getIdentifier()) {
528             unlockSystemUser();
529         }
530     }
531 
532     /**
533      * Check if the user is a guest and can be replaced.
534      */
canReplaceGuestUser(UserHandle user)535     public boolean canReplaceGuestUser(UserHandle user) {
536         if (!mUserHandleHelper.isGuestUser(user)) return false;
537 
538         if (LockPatternHelper.isSecure(mContext, user.getIdentifier())) {
539             if (DBG) {
540                 Slogf.d(TAG, "replaceGuestIfNeeded(), skipped, since user "
541                         + user.getIdentifier() + " has secure lock pattern");
542             }
543             return false;
544         }
545 
546         return true;
547     }
548 
549     /**
550      * Replaces {@code user} by a new guest, if necessary.
551      *
552      * <p>If {@code user} is not a guest, it doesn't do anything and returns the same user.
553      *
554      * <p>Otherwise, it marks the current guest for deletion, creates a new one, and returns the
555      * new guest (or {@code null} if a new guest could not be created).
556      */
557 
558     @VisibleForTesting
559     @Nullable
replaceGuestIfNeeded(@onNull UserHandle user)560     UserHandle replaceGuestIfNeeded(@NonNull UserHandle user) {
561         Preconditions.checkArgument(user != null, "user cannot be null");
562 
563         if (!canReplaceGuestUser(user)) {
564             return user;
565         }
566 
567         if (isPlatformVersionAtLeastU()) {
568             EventLogHelper.writeCarInitialUserReplaceGuest(user.getIdentifier());
569         }
570         Slogf.i(TAG, "Replacing guest (" + user + ")");
571 
572         int halFlags = UserInfo.USER_FLAG_GUEST;
573         if (mUserHandleHelper.isEphemeralUser(user)) {
574             halFlags |= UserInfo.USER_FLAG_EPHEMERAL;
575         } else {
576             // TODO(b/150413515): decide whether we should allow it or not. Right now we're
577             // just logging, as UserManagerService will automatically set it to ephemeral if
578             // platform is set to do so.
579             Slogf.w(TAG, "guest being replaced is not ephemeral: " + user);
580         }
581 
582         if (!UserManagerHelper.markGuestForDeletion(mUm, user)) {
583             // Don't need to recover in case of failure - most likely create new user will fail
584             // because there is already a guest
585             Slogf.w(TAG, "failed to mark guest " + user.getIdentifier() + " for deletion");
586         }
587 
588         Pair<UserHandle, String> result = createNewUser(new Builder(TYPE_CREATE)
589                 .setNewUserName(mNewGuestName)
590                 .setNewUserFlags(halFlags)
591                 .build());
592 
593         String errorMessage = result.second;
594         if (errorMessage != null) {
595             Slogf.w(TAG, "could not replace guest " + user + ": " + errorMessage);
596             return null;
597         }
598 
599         return result.first;
600     }
601 
createAndSwitchUser(@onNull InitialUserInfo info, boolean fallback)602     private void createAndSwitchUser(@NonNull InitialUserInfo info, boolean fallback) {
603         Pair<UserHandle, String> result = createNewUser(info);
604         String reason = result.second;
605         if (reason != null) {
606             fallbackDefaultBehavior(info, fallback, reason);
607             return;
608         }
609 
610         switchUser(new Builder(TYPE_SWITCH)
611                 .setSwitchUserId(result.first.getIdentifier())
612                 .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
613                 .build(), fallback);
614     }
615 
616     /**
617      * Creates a new user.
618      *
619      * @return on success, first element is the new user; on failure, second element contains the
620      * error message.
621      */
622     @NonNull
createNewUser(@onNull InitialUserInfo info)623     private Pair<UserHandle, String> createNewUser(@NonNull InitialUserInfo info) {
624         String name = info.newUserName;
625         int halFlags = info.newUserFlags;
626 
627         if (DBG) {
628             Slogf.d(TAG, "createUser(name=" + UserHelperLite.safeName(name) + ", flags="
629                     + userFlagsToString(halFlags) + ")");
630         }
631 
632         if (UserHalHelper.isSystem(halFlags)) {
633             return new Pair<>(null, "Cannot create system user");
634         }
635 
636         if (UserHalHelper.isAdmin(halFlags)) {
637             boolean validAdmin = true;
638             if (UserHalHelper.isGuest(halFlags)) {
639                 Slogf.w(TAG, "Cannot create guest admin");
640                 validAdmin = false;
641             }
642             if (UserHalHelper.isEphemeral(halFlags)) {
643                 Slogf.w(TAG, "Cannot create ephemeral admin");
644                 validAdmin = false;
645             }
646             if (!validAdmin) {
647                 return new Pair<>(null, "Invalid flags for admin user");
648             }
649         }
650         // TODO(b/150413515): decide what to if HAL requested a non-ephemeral guest but framework
651         // sets all guests as ephemeral - should it fail or just warn?
652 
653         int flags = UserHalHelper.toUserInfoFlags(halFlags);
654         String type = UserHalHelper.isGuest(halFlags) ? UserManager.USER_TYPE_FULL_GUEST
655                 : UserManager.USER_TYPE_FULL_SECONDARY;
656 
657         if (DBG) {
658             Slogf.d(TAG, "calling am.createUser((name=" + UserHelperLite.safeName(name) + ", type="
659                     + type + ", flags=" + flags + ")");
660         }
661 
662         UserHandle user = mCarUserService.createUserEvenWhenDisallowed(name, type, flags);
663         if (user == null) {
664             return new Pair<>(null, "createUser(name=" + UserHelperLite.safeName(name) + ", flags="
665                     + userFlagsToString(halFlags) + "): failed to create user");
666         }
667 
668         if (DBG) Slogf.d(TAG, "user created: " + user.getIdentifier());
669 
670         if (info.userLocales != null) {
671             if (DBG) {
672                 Slogf.d(TAG, "setting locale for user " + user.getIdentifier() + " to "
673                         + info.userLocales);
674             }
675             Settings.System.putString(
676                     getContentResolverForUser(mContext, user.getIdentifier()),
677                     SettingsHelper.SYSTEM_LOCALES, info.userLocales);
678         }
679 
680         return new Pair<>(user, null);
681     }
682 
683     @VisibleForTesting
unlockSystemUser()684     void unlockSystemUser() {
685         if (isPlatformVersionAtLeastU()) {
686             EventLogHelper.writeCarInitialUserUnlockSystemUser();
687         }
688         Slogf.i(TAG, "unlocking system user");
689         TimingsTraceLog t = new TimingsTraceLog(TAG, TraceHelper.TRACE_TAG_CAR_SERVICE);
690         t.traceBegin("UnlockSystemUser");
691         // This is for force changing state into RUNNING_LOCKED. Otherwise unlock does not
692         // update the state and USER_SYSTEM stays as BOOTING.
693         t.traceBegin("am.startUser");
694         boolean started = ActivityManagerHelper.startUserInBackground(
695                 UserHandle.SYSTEM.getIdentifier());
696         t.traceEnd();
697         if (!started) {
698             Slogf.w(TAG, "could not restart system user in foreground; trying unlock instead");
699             t.traceBegin("am.unlockUser");
700             boolean unlocked = ActivityManagerHelper.unlockUser(UserHandle.SYSTEM.getIdentifier());
701             t.traceEnd();
702             if (!unlocked) {
703                 Slogf.w(TAG, "could not unlock system user neither");
704                 return;
705             }
706         }
707         t.traceEnd();
708     }
709 
710     @VisibleForTesting
startForegroundUser(InitialUserInfo info, @UserIdInt int userId)711     boolean startForegroundUser(InitialUserInfo info, @UserIdInt int userId) {
712         if (isPlatformVersionAtLeastU()) {
713             EventLogHelper.writeCarInitialUserStartFgUser(userId);
714         }
715 
716         if (UserHelperLite.isHeadlessSystemUser(userId)) {
717             if (!mIsVisibleBackgroundUsersOnDefaultDisplaySupported) {
718                 // System User is not associated with real person, can not be switched to.
719                 // But in Multi User No Driver mode, we'll need to put system user to foreground as
720                 // this is exactly the user model.
721                 return false;
722             } else {
723                 if (DBG) {
724                     Slogf.d(TAG, "startForegroundUser: "
725                             + "Multi User No Driver, continue to put system user in foreground");
726                 }
727             }
728         }
729 
730         // Keep the old boot user flow for platform before U
731         if (info.requestType == InitialUserInfoRequestType.RESUME
732                 || !isPlatformVersionAtLeastU()) {
733             return ActivityManagerHelper.startUserInForeground(userId);
734         } else {
735             Slogf.i(TAG, "Setting boot user to: %d", userId);
736             mUm.setBootUser(UserHandle.of(userId));
737             return true;
738         }
739     }
740 
notifyListener(@ullable UserHandle initialUser)741     private void notifyListener(@Nullable UserHandle initialUser) {
742         if (DBG) Slogf.d(TAG, "notifyListener(): " + initialUser);
743         mListener.accept(initialUser);
744     }
745 
746     /**
747      * Dumps it state.
748      */
749     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(@onNull PrintWriter writer)750     public void dump(@NonNull PrintWriter writer) {
751         writer.println("InitialUserSetter");
752         String indent = "  ";
753         writer.printf("%smNewUserName: %s\n", indent, mNewUserName);
754         writer.printf("%smNewGuestName: %s\n", indent, mNewGuestName);
755     }
756 
757     /**
758      * Sets the last active user.
759      */
setLastActiveUser(@serIdInt int userId)760     public void setLastActiveUser(@UserIdInt int userId) {
761         if (isPlatformVersionAtLeastU()) {
762             EventLogHelper.writeCarInitialUserSetLastActive(userId);
763         }
764 
765         if (UserHelperLite.isHeadlessSystemUser(userId)) {
766             if (DBG) Slogf.d(TAG, "setLastActiveUser(): ignoring headless system user " + userId);
767             return;
768         }
769         setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID, userId);
770 
771         UserHandle user = mUserHandleHelper.getExistingUserHandle(userId);
772         if (user == null) {
773             Slogf.w(TAG, "setLastActiveUser(): user " + userId + " doesn't exist");
774             return;
775         }
776         if (!mUserHandleHelper.isEphemeralUser(user)) {
777             setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID, userId);
778         }
779     }
780 
setUserIdGlobalProperty(@onNull String name, @UserIdInt int userId)781     private void setUserIdGlobalProperty(@NonNull String name, @UserIdInt int userId) {
782         if (DBG) Slogf.d(TAG, "setting global property " + name + " to " + userId);
783 
784         Settings.Global.putInt(mContext.getContentResolver(), name, userId);
785     }
786 
787     /**
788      * Gets the user id for the initial user to boot into. This is only applicable for headless
789      * system user model. This method checks for a system property and will only work for system
790      * apps.
791      *
792      * This method checks for the initial user via three mechanisms in this order:
793      * <ol>
794      *     <li>Check for a boot user override via {@code CarProperties#boot_user_override_id()}</li>
795      *     <li>Check for the last active user in the system</li>
796      *     <li>Fallback to the smallest user id that is not {@link UserHandle.SYSTEM}</li>
797      * </ol>
798      *
799      * If any step fails to retrieve the stored id or the retrieved id does not exist on device,
800      * then it will move onto the next step.
801      *
802      * @return user id of the initial user to boot into on the device, or
803      * {@link UserHandle#USER_NULL} if there is no user available.
804      */
805     @VisibleForTesting
getInitialUser(boolean usesOverrideUserIdProperty)806     int getInitialUser(boolean usesOverrideUserIdProperty) {
807 
808         List<Integer> allUsers = userListToUserIdList(getAllUsers());
809 
810         if (allUsers.isEmpty()) {
811             return UserManagerHelper.USER_NULL;
812         }
813 
814         //TODO(b/150416512): Check if it is still supported, if not remove it.
815         if (usesOverrideUserIdProperty) {
816             int bootUserOverride = CarSystemProperties.getBootUserOverrideId()
817                     .orElse(BOOT_USER_NOT_FOUND);
818 
819             // If an override user is present and a real user, return it
820             if (bootUserOverride != BOOT_USER_NOT_FOUND
821                     && allUsers.contains(bootUserOverride)) {
822                 Slogf.i(TAG, "Boot user id override found for initial user, user id: "
823                         + bootUserOverride);
824                 return bootUserOverride;
825             }
826         }
827 
828         // If the last active user is not the SYSTEM user and is a real user, return it
829         int lastActiveUser = getUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID);
830         if (allUsers.contains(lastActiveUser)) {
831             Slogf.i(TAG, "Last active user loaded for initial user: " + lastActiveUser);
832             return lastActiveUser;
833         }
834         resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID);
835 
836         int lastPersistentUser = getUserIdGlobalProperty(
837                 CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
838         if (allUsers.contains(lastPersistentUser)) {
839             Slogf.i(TAG, "Last active, persistent user loaded for initial user: "
840                     + lastPersistentUser);
841             return lastPersistentUser;
842         }
843         resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
844 
845         // If all else fails, return the smallest user id
846         int returnId = Collections.min(allUsers);
847         // TODO(b/158101909): the smallest user id is not always the initial user; a better approach
848         // would be looking for the first ADMIN user, or keep track of all last active users (not
849         // just the very last)
850         Slogf.w(TAG, "Last active user (" + lastActiveUser + ") not found. Returning smallest user "
851                 + "id instead: " + returnId);
852         return returnId;
853     }
854 
855     /**
856      * Gets all the users that can be brought to the foreground on the system.
857      *
858      * @return List of {@code UserHandle} for users that associated with a real person.
859      */
getAllUsers()860     private List<UserHandle> getAllUsers() {
861         if (UserManager.isHeadlessSystemUserMode()) {
862             return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.SYSTEM.getIdentifier());
863         } else if (isPlatformVersionAtLeastU()) {
864             return UserManagerHelper.getUserHandles(mUm, /* excludeDying= */ false);
865         } else {
866             return UserManagerHelper.getUserHandles(mUm, /* excludePartial= */ false,
867                     /* excludeDying= */ false, /* excludePreCreated */ true);
868         }
869     }
870 
871     /**
872      * Gets all the users except system user and the one with userId passed in.
873      *
874      * @param userId of the user not to be returned.
875      * @return All users other than system user and user with userId.
876      */
getAllUsersExceptSystemUserAndSpecifiedUser(@serIdInt int userId)877     private List<UserHandle> getAllUsersExceptSystemUserAndSpecifiedUser(@UserIdInt int userId) {
878         List<UserHandle> users;
879         if (isPlatformVersionAtLeastU()) {
880             users = UserManagerHelper.getUserHandles(mUm, /* excludeDying= */ false);
881         } else {
882             users = UserManagerHelper.getUserHandles(mUm, /* excludePartial= */ false,
883                     /* excludeDying= */ false, /* excludePreCreated */ true);
884         }
885 
886         for (Iterator<UserHandle> iterator = users.iterator(); iterator.hasNext(); ) {
887             UserHandle user = iterator.next();
888             if (user.getIdentifier() == userId
889                     || user.getIdentifier() == UserHandle.SYSTEM.getIdentifier()) {
890                 // Remove user with userId from the list.
891                 iterator.remove();
892             }
893         }
894         return users;
895     }
896 
897     // TODO(b/231473748): this method should NOT be used to define if it's the first boot - we
898     // should create a new method for that instead (which would check the proper signals) and change
899     // CarUserService.getInitialUserInfoRequestType() to use it instead
900     /**
901      * Checks whether the device has an initial user that can be switched to.
902      */
hasInitialUser()903     public boolean hasInitialUser() {
904         List<UserHandle> allUsers = getAllUsers();
905         for (int i = 0; i < allUsers.size(); i++) {
906             UserHandle user = allUsers.get(i);
907             if (mUserHandleHelper.isManagedProfile(user)) continue;
908 
909             return true;
910         }
911         return false;
912     }
913 
914     // TODO(b/231473748): temporary method that ignores ephemeral user while hasInitialUser() is
915     // used to define if it's first boot - once there is an isInitialBoot() for that purpose, this
916     // method should be removed (and its logic moved to hasInitialUser())
917     @VisibleForTesting
hasValidInitialUser()918     boolean hasValidInitialUser() {
919         // TODO(b/231473748): should call method that ignores partial, dying, or pre-created
920         List<UserHandle> allUsers = getAllUsers();
921         for (int i = 0; i < allUsers.size(); i++) {
922             UserHandle user = allUsers.get(i);
923             if (mUserHandleHelper.isManagedProfile(user)
924                     || mUserHandleHelper.isEphemeralUser(user)) {
925                 continue;
926             }
927 
928             return true;
929         }
930         return false;
931     }
932 
userListToUserIdList(List<UserHandle> allUsers)933     private static List<Integer> userListToUserIdList(List<UserHandle> allUsers) {
934         ArrayList<Integer> list = new ArrayList<>(allUsers.size());
935         for (int i = 0; i < allUsers.size(); i++) {
936             list.add(allUsers.get(i).getIdentifier());
937         }
938         return list;
939     }
940 
resetUserIdGlobalProperty(@onNull String name)941     private void resetUserIdGlobalProperty(@NonNull String name) {
942         if (isPlatformVersionAtLeastU()) {
943             EventLogHelper.writeCarInitialUserResetGlobalProperty(name);
944         }
945 
946         Settings.Global.putInt(mContext.getContentResolver(), name, UserManagerHelper.USER_NULL);
947     }
948 
getUserIdGlobalProperty(@onNull String name)949     private int getUserIdGlobalProperty(@NonNull String name) {
950         int userId = Settings.Global.getInt(mContext.getContentResolver(), name,
951                 UserManagerHelper.USER_NULL);
952         if (DBG) Slogf.d(TAG, "getting global property " + name + ": " + userId);
953         return userId;
954     }
955 }
956