blob: 329ac112e6a7e3e76972349ca796bec4af8bd99f [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 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
17package com.android.car.user;
18
Eric Jeong1545f3b2019-09-16 13:56:52 -070019import static com.android.car.CarLog.TAG_USER;
20
21import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070022import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070024import android.app.ActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070025import android.app.ActivityManager.StackInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070026import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070027import android.car.CarOccupantZoneManager;
28import android.car.CarOccupantZoneManager.OccupantTypeEnum;
29import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070030import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070031import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080032import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080033import android.car.user.CarUserManager.UserLifecycleEvent;
felipeale8c5dce2020-04-15 11:27:06 -070034import android.car.user.CarUserManager.UserLifecycleEventType;
Antonio Kantekc8114752020-03-05 21:37:39 -080035import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070036import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070037import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070038import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070039import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070040import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070041import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070042import android.car.userlib.HalCallback;
43import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070044import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070046import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070047import android.content.pm.PackageManager;
48import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070049import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070050import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070051import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070052import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070053import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
54import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070055import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080056import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070057import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070058import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070059import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070062import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
63import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080064import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070065import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070066import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080067import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070068import android.os.Handler;
69import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070070import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080071import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070072import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070073import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070074import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070075import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070076import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070077import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080079import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080080import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081
82import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070083import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070084import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080085import com.android.car.hal.UserHalService;
Mayank Garg4bdfbf72020-08-06 13:27:43 -070086import com.android.car.power.CarPowerManagementService;
Mayank Garg665c20b2020-08-07 16:19:28 -070087import com.android.car.user.InitialUserSetter.InitialUserInfo;
Keun-young Parkd462a912019-02-11 08:53:42 -080088import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070089import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070090import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070091import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080092import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070093import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070094import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070095import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070096import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097
98import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080099import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -0700100import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700101import java.util.Iterator;
102import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000103import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700104import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700105import java.util.concurrent.CountDownLatch;
106import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700107
108/**
109 * User service for cars. Manages users at boot time. Including:
110 *
111 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700112 * <li> Creates a user used as driver.
113 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700115 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700116 * <ol/>
117 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700118public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800119
felipealf7368962020-04-16 12:55:19 -0700120 private static final String TAG = TAG_USER;
121
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800122 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700123 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800124 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700125 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800126 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700127 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
felipeala68ecef2020-05-19 12:46:08 -0700128 /**
129 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
130 */
131 public static final String BUNDLE_USER_LOCALES =
132 CarUserServiceConstants.BUNDLE_USER_LOCALES;
133 /**
134 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
135 */
felipeal1a9410d2020-05-06 13:30:05 -0700136 public static final String BUNDLE_INITIAL_INFO_ACTION =
137 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800138
Mayank Garg9ed099e2020-06-04 16:05:20 -0700139 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
140
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700141 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700142 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700143 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700144 private final UserManager mUserManager;
145 private final int mMaxRunningUsers;
Mayank Garg70732a82020-08-05 20:17:47 -0700146 private final InitialUserSetter mInitialUserSetter;
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 private final boolean mEnablePassengerSupport;
Mayank Garg9732d602020-08-09 21:02:40 -0700148 private final UserPreCreator mUserPreCreator;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700149
Eric Jeongc91f9452019-08-30 15:04:21 -0700150 private final Object mLockUser = new Object();
151 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800152 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700153 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800154 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700155 // Only one passenger is supported.
156 @GuardedBy("mLockUser")
157 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700158 /**
159 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800160 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700161 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700162 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700163 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
164 /**
165 * Keep the list of background users started here. This is wholly for debugging purpose.
166 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700168 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
169
Felipe Leme58412202020-01-09 13:45:33 -0800170 private final UserHalService mHal;
171
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700172 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700173 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
174 getClass().getSimpleName());
175 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700176
Felipe Leme5528ff72020-02-10 19:05:14 -0800177 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800178 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700179 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800180 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700181 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800182
183 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800184 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700185 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800186 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700187 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800188
Mayank Garg7a114c82020-04-08 21:25:06 -0700189 /**
190 * User Id for the user switch in process, if any.
191 */
192 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700193 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700194 /**
195 * Request Id for the user switch in process, if any.
196 */
197 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700198 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700199 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
200
Eric Jeongc91f9452019-08-30 15:04:21 -0700201 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
202 new CopyOnWriteArrayList<>();
203
felipeal61ce3732020-04-03 11:01:00 -0700204 @Nullable
205 @GuardedBy("mLockUser")
206 private UserInfo mInitialUser;
207
Mayank Garg71661ea2020-04-29 01:25:03 -0700208 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700209
Mayank Garg587f1942020-05-06 01:41:34 -0700210 private IResultReceiver mUserSwitchUiReceiver;
211
Eric Jeongc91f9452019-08-30 15:04:21 -0700212 /** Interface for callbaks related to passenger activities. */
213 public interface PassengerCallback {
214 /** Called when passenger is started at a certain zone. */
215 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
216 /** Called when passenger is stopped. */
217 void onPassengerStopped(@UserIdInt int passengerId);
218 }
219
220 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
221 public interface ZoneUserBindingHelper {
222 /** Gets occupant zones corresponding to the occupant type. */
223 @NonNull
224 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
225 /** Assigns the user to the occupant zone. */
226 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
227 /** Makes the occupant zone unoccupied. */
228 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
229 /** Returns whether there is a passenger display. */
230 boolean isPassengerDisplayAvailable();
231 }
232
233 private final Object mLockHelper = new Object();
234 @GuardedBy("mLockHelper")
235 private ZoneUserBindingHelper mZoneUserBindingHelper;
236
Felipe Leme58412202020-01-09 13:45:33 -0800237 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700238 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
239 @NonNull IActivityManager am, int maxRunningUsers) {
240 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
Mayank Garg70732a82020-08-05 20:17:47 -0700241 new UserMetrics(), /* initialUserSetter= */ null);
Mayank Garg71661ea2020-04-29 01:25:03 -0700242 }
243
244 @VisibleForTesting
245 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
246 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
Mayank Garg70732a82020-08-05 20:17:47 -0700247 @NonNull IActivityManager am, int maxRunningUsers, @NonNull UserMetrics userMetrics,
248 @Nullable InitialUserSetter initialUserSetter) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700249 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
250 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700251 }
252 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800253 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700254 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700255 mAm = am;
256 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700257 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700258 mLastPassengerId = UserHandle.USER_NULL;
259 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700260 mUserMetrics = userMetrics;
Mayank Garg70732a82020-08-05 20:17:47 -0700261 if (initialUserSetter == null) {
262 mInitialUserSetter = new InitialUserSetter(context, (u) -> setInitialUser(u));
263 } else {
264 mInitialUserSetter = initialUserSetter;
265 }
Mayank Garg9732d602020-08-09 21:02:40 -0700266 mUserPreCreator = new UserPreCreator(mUserManager);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700267 }
268
269 @Override
270 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700271 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
272 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700273 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700274 }
275
276 @Override
277 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700278 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
279 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700280 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700281 }
282
283 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700284 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700285 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700286 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800287 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700288 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700289 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700290 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700291 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700292 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
293 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700294 }
295 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
296 List<UserInfo> allDrivers = getAllDrivers();
297 int driversSize = allDrivers.size();
298 writer.println("NumberOfDrivers: " + driversSize);
299 for (int i = 0; i < driversSize; i++) {
300 int driverId = allDrivers.get(i).id;
301 writer.print(indent + "#" + i + ": id=" + driverId);
302 List<UserInfo> passengers = getPassengers(driverId);
303 int passengersSize = passengers.size();
304 writer.print(" NumberPassengers: " + passengersSize);
305 if (passengersSize > 0) {
306 writer.print(" [");
307 for (int j = 0; j < passengersSize; j++) {
308 writer.print(passengers.get(j).id);
309 if (j < passengersSize - 1) {
310 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700311 }
felipeal2d0483c2019-11-02 14:07:22 -0700312 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700313 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700314 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700315 writer.println();
316 }
317 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
318 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
319 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700320
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700321 writer.println("Relevant overlayable properties");
322 Resources res = mContext.getResources();
323 writer.printf("%sowner_name=%s\n", indent,
324 res.getString(com.android.internal.R.string.owner_name));
325 writer.printf("%sdefault_guest_name=%s\n", indent,
326 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700327 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700328 writer.printf("Request Id for the user switch in process=%d\n ",
329 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700330 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700331
felipealbf327652020-06-03 11:33:29 -0700332 writer.println("Relevant Global settings");
333 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
334 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
335
felipeale8c5dce2020-04-15 11:27:06 -0700336 dumpUserMetrics(writer);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700337
338 mInitialUserSetter.dump(writer);
felipeale8c5dce2020-04-15 11:27:06 -0700339 }
340
felipealbf327652020-06-03 11:33:29 -0700341 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
342 String value = Settings.Global.getString(mContext.getContentResolver(), property);
343 writer.printf("%s%s=%s\n", indent, property, value);
344 }
345
felipeale8c5dce2020-04-15 11:27:06 -0700346 /**
347 * Dumps user metrics.
348 */
349 public void dumpUserMetrics(@NonNull PrintWriter writer) {
350 mUserMetrics.dump(writer);
351 }
352
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700353 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
354 CountDownLatch latch = new CountDownLatch(1);
355 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700356 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700357 handleDumpAppLifecycleListeners(writer, indent);
358 latch.countDown();
359 });
360 int timeout = 5;
361 try {
362 if (!latch.await(timeout, TimeUnit.SECONDS)) {
363 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
364 timeout);
365 }
366 } catch (InterruptedException e) {
367 Thread.currentThread().interrupt();
368 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
369 }
370 }
371
felipealde1e16d2020-06-03 13:20:48 -0700372 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700373 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700374 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700375 return;
376 }
felipealde1e16d2020-06-03 13:20:48 -0700377 int size = mUserLifecycleListeners.size();
378 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
379 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700380 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700381 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700382 }
383 }
384
385 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700386 int size = mAppLifecycleListeners.size();
387 if (size == 0) {
388 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700389 return;
390 }
felipealde1e16d2020-06-03 13:20:48 -0700391 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
392 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700393 int uid = mAppLifecycleListeners.keyAt(i);
394 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700395 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800396 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700397 }
398
399 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700400 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700401 */
402 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700403 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700404 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000405 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700406
407 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
408 @Override
409 protected void onCompleted(UserCreationResult result, Throwable err) {
410 if (result == null) {
411 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
412 } else {
413 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
414 assignDefaultIcon(result.getUser());
415 }
416 }
417 super.onCompleted(result, err);
418 };
419 };
420 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700421 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700422 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
423 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
424 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
425 return future;
426 }
427 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700428 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700429 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
430 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700431 }
432
433 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700434 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700435 */
436 @Override
437 @Nullable
438 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
439 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000440 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 UserInfo driver = mUserManager.getUserInfo(driverId);
442 if (driver == null) {
443 Log.w(TAG_USER, "the driver is invalid");
444 return null;
445 }
446 if (driver.isGuest()) {
447 Log.w(TAG_USER, "a guest driver cannot create a passenger");
448 return null;
449 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700450 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700451 UserInfo user = mUserManager.createProfileForUser(name,
452 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700453 if (user == null) {
454 // Couldn't create user, most likely because there are too many.
455 Log.w(TAG_USER, "can't create a profile for user" + driverId);
456 return null;
457 }
458 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700459 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700460 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700461 return user;
462 }
463
464 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700465 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700466 */
467 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700468 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700469 checkManageUsersPermission("switchDriver");
Eric Jeong25666cf2020-05-14 15:16:27 -0700470 if (UserHelper.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700471 // System user doesn't associate with real person, can not be switched to.
472 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700473 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700474 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700475 }
476 int userSwitchable = mUserManager.getUserSwitchability();
477 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
478 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700479 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700480 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700481 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700482 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700483 }
484
485 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800486 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
487 *
488 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700489 */
490 @Override
491 @NonNull
492 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700493 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700494 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700495 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700496 }
497
498 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800499 * Returns all passengers under the given driver.
500 *
501 * @param driverId User id of a driver.
502 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700503 */
504 @Override
505 @NonNull
506 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700507 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700508 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700509 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
510 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700511 });
512 }
513
514 /**
515 * @see CarUserManager.startPassenger
516 */
517 @Override
518 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
519 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700520 synchronized (mLockUser) {
521 try {
522 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
523 Log.w(TAG_USER, "could not start passenger");
524 return false;
525 }
526 } catch (RemoteException e) {
527 // ignore
528 Log.w(TAG_USER, "error while starting passenger", e);
529 return false;
530 }
531 if (!assignUserToOccupantZone(passengerId, zoneId)) {
532 Log.w(TAG_USER, "could not assign passenger to zone");
533 return false;
534 }
535 mLastPassengerId = passengerId;
536 }
537 for (PassengerCallback callback : mPassengerCallbacks) {
538 callback.onPassengerStarted(passengerId, zoneId);
539 }
540 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700541 }
542
543 /**
544 * @see CarUserManager.stopPassenger
545 */
546 @Override
547 public boolean stopPassenger(@UserIdInt int passengerId) {
548 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700549 return stopPassengerInternal(passengerId, true);
550 }
551
552 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
553 synchronized (mLockUser) {
554 UserInfo passenger = mUserManager.getUserInfo(passengerId);
555 if (passenger == null) {
556 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
557 return false;
558 }
559 if (mLastPassengerId != passengerId) {
560 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
561 return true;
562 }
563 if (checkCurrentDriver) {
564 int currentUser = ActivityManager.getCurrentUser();
565 if (passenger.profileGroupId != currentUser) {
566 Log.w(TAG_USER, "passenger " + passengerId
567 + " is not a profile of the current user");
568 return false;
569 }
570 }
571 // Passenger is a profile, so cannot be stopped through activity manager.
572 // Instead, activities started by the passenger are stopped and the passenger is
573 // unassigned from the zone.
574 stopAllTasks(passengerId);
575 if (!unassignUserFromOccupantZone(passengerId)) {
576 Log.w(TAG_USER, "could not unassign user from occupant zone");
577 return false;
578 }
579 mLastPassengerId = UserHandle.USER_NULL;
580 }
581 for (PassengerCallback callback : mPassengerCallbacks) {
582 callback.onPassengerStopped(passengerId);
583 }
584 return true;
585 }
586
587 private void stopAllTasks(@UserIdInt int userId) {
588 try {
589 for (StackInfo info : mAm.getAllStackInfos()) {
590 for (int i = 0; i < info.taskIds.length; i++) {
591 if (info.taskUserIds[i] == userId) {
592 int taskId = info.taskIds[i];
593 if (!mAm.removeTask(taskId)) {
594 Log.w(TAG_USER, "could not remove task " + taskId);
595 }
596 }
597 }
598 }
599 } catch (RemoteException e) {
600 Log.e(TAG_USER, "could not get stack info", e);
601 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700602 }
603
Felipe Leme5528ff72020-02-10 19:05:14 -0800604 @Override
605 public void setLifecycleListenerForUid(IResultReceiver listener) {
606 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700607 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800608 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
609
610 try {
611 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
612 } catch (RemoteException e) {
613 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
614 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700615 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800616 }
617
618 private void onListenerDeath(int uid) {
619 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700620 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800621 }
622
623 @Override
624 public void resetLifecycleListenerForUid() {
625 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700626 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800627 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700628 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800629 }
630
Felipe Lemee3cab982020-03-12 11:39:29 -0700631 /**
felipeal61ce3732020-04-03 11:01:00 -0700632 * Gets the initial foreground user after the device boots or resumes from suspension.
633 *
634 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
635 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
636 * method returns {@code null}.
637 *
638 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
639 * (like switching to the last active user), and this method will return the result of such
640 * operation.
641 *
642 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
643 * {@code null}.
644 *
645 * @hide
646 */
647 @Nullable
648 public UserInfo getInitialUser() {
649 checkInteractAcrossUsersPermission("getInitialUser");
650 synchronized (mLockUser) {
651 return mInitialUser;
652 }
653 }
654
felipeal61ce3732020-04-03 11:01:00 -0700655 /**
656 * Sets the initial foreground user after the device boots or resumes from suspension.
657 */
658 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700659 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
660 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700661 synchronized (mLockUser) {
662 mInitialUser = user;
663 }
664 if (user == null) {
665 // This mean InitialUserSetter failed and could not fallback, so the initial user was
666 // not switched (and most likely is SYSTEM_USER).
667 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
668 Log.wtf(TAG_USER, "Initial user set to null");
669 }
670 }
671
672 /**
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700673 * Calls to replace current guest user due to STR.
674 * <p>
675 * <b>Note:</b> Should be user by only {@link CarPowerManagementService}
676 */
677
678 public void initResumeReplaceGuest() {
679 int currentUserId = ActivityManager.getCurrentUser();
680 UserInfo currentUser = mUserManager.getUserInfo(currentUserId);
681
682 if (!mInitialUserSetter.canReplaceGuestUser(currentUser)) return; // Not a guest
683
684 InitialUserInfo info =
685 new InitialUserSetter.Builder(InitialUserSetter.TYPE_REPLACE_GUEST).build();
686
687 mInitialUserSetter.set(info);
688 }
689
690 /**
691 * Calls to start user at the android startup.
Mayank Garg70732a82020-08-05 20:17:47 -0700692 */
693 public void initBootUser() {
694 int requestType = getInitialUserInfoRequestType();
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700695 initBootUser(requestType, false);
696 }
697
698 /**
699 * Calls to start user at the power resume.
700 */
701 public void initBootUser(int requestType, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700702 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
703 mHalTimeoutMs);
704 checkManageUsersPermission("startInitialUser");
705
706 if (!isUserHalSupported()) {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700707 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700708 return;
709 }
710
711 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
712 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
713 if (resp != null) {
714 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
715 status, resp.action, resp.userToSwitchOrCreate.userId,
716 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
717
718 String userLocales = resp.userLocales;
719 InitialUserInfo info;
720 switch (resp.action) {
721 case InitialUserInfoResponseAction.SWITCH:
722 int userId = resp.userToSwitchOrCreate.userId;
723 if (userId <= 0) {
724 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700725 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700726 break;
727 }
728 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
729 .setUserLocales(userLocales)
730 .setSwitchUserId(userId)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700731 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700732 .build();
733 mInitialUserSetter.set(info);
734 break;
735
736 case InitialUserInfoResponseAction.CREATE:
737 int halFlags = resp.userToSwitchOrCreate.flags;
738 String userName = resp.userNameToCreate;
739 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
740 .setUserLocales(userLocales)
741 .setNewUserName(userName)
742 .setNewUserFlags(halFlags)
743 .build();
744 mInitialUserSetter.set(info);
745 break;
746
747 case InitialUserInfoResponseAction.DEFAULT:
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700748 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700749 break;
750 default:
751 Log.w(TAG_USER, "invalid response action on " + resp);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700752 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700753 break;
754
755 }
756 } else {
757 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700758 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700759 }
760 });
761 }
762
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700763 private void fallbackToDefaultInitialUserBehavior(String userLocales, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700764 InitialUserInfo info = new InitialUserSetter.Builder(
765 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
766 .setUserLocales(userLocales)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700767 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700768 .build();
769 mInitialUserSetter.set(info);
770 }
771
772 @VisibleForTesting
773 int getInitialUserInfoRequestType() {
774 if (!mCarUserManagerHelper.hasInitialUser()) {
775 return InitialUserInfoRequestType.FIRST_BOOT;
776 }
777 if (mContext.getPackageManager().isDeviceUpgrading()) {
778 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
779 }
780 return InitialUserInfoRequestType.COLD_BOOT;
781 }
782
783 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700784 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
785 *
786 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700787 * When everything works well, the workflow is:
788 * <ol>
789 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
790 * type, current user id, target user id, and a callback.
791 * <li> HAL called back with SUCCESS.
792 * <li> {@link IActivityManager} is called for Android user switch.
793 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
794 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
795 * request type, current user id, and target user id. In this case, the current and target
796 * user IDs would be same.
797 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700798 *
799 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700800 * Corner cases:
801 * <ul>
802 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700803 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700804 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
805 * {@code STATUS_HAL_INTERNAL_FAILURE}.
806 * <li> If HAL user switch call is successful, but android user switch call fails,
807 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
808 * target user id, but in this case the current and target user IDs would be different.
809 * <li> If another user switch request for the same target user is received while previous
810 * request is in process, receiver would receive
811 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
812 * <li> If a user switch request is received while another user switch request for different
813 * target user is in process, the previous request would be abandoned and new request will be
814 * processed. No POST_SWITCH would be sent for the previous request.
815 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700816 *
Mayank Garge19c2922020-03-30 18:05:53 -0700817 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700818 * @param timeoutMs - timeout for HAL to wait
819 * @param receiver - receiver for the results
820 */
Mayank Garge19c2922020-03-30 18:05:53 -0700821 @Override
822 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700823 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700824 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700825 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700826 Objects.requireNonNull(receiver);
827 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700828 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700829
felipealf7368962020-04-16 12:55:19 -0700830 int currentUser = ActivityManager.getCurrentUser();
831 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700832 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
833 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
834 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700835 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700836 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700837 return;
838 }
839
Mayank Garg9ed099e2020-06-04 16:05:20 -0700840 // If User Hal is not supported, just android user switch.
841 if (!isUserHalSupported()) {
842 try {
843 if (mAm.switchUser(targetUserId)) {
844 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
845 return;
846 }
847 } catch (RemoteException e) {
848 // ignore
849 Log.w(TAG_USER,
850 "error while switching user " + targetUser.toFullString(), e);
851 }
852 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
853 return;
854 }
855
Mayank Garg7a114c82020-04-08 21:25:06 -0700856 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700857 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
858 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
859 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
860 }
861
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700862 // If there is another request for the same target user, return another request in
863 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
864 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
865 // user switch request in process for different target user, but that request is now
866 // ignored.
felipealf7368962020-04-16 12:55:19 -0700867 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700868 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
869 Log.d(TAG_USER,
870 "Another user switch request in process for the requested target user: "
871 + targetUserId);
872 }
873
874 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700875 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700876 return;
877 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700878 else {
879 mUserIdForUserSwitchInProcess = targetUserId;
880 mRequestIdForUserSwitchInProcess = 0;
881 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700882 }
883
felipealdfdf8512020-06-01 09:35:45 -0700884 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700885 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
886
887 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700888 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
889 Log.d(TAG, "switch response: status="
890 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
891 }
892
felipeale5bf0322020-04-16 15:10:57 -0700893 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700894
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700895 synchronized (mLockUser) {
896 if (status != HalCallback.STATUS_OK) {
897 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
898 Log.w(TAG, "invalid callback status ("
899 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
900 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700901 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700902 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
903 return;
904 }
felipealf7368962020-04-16 12:55:19 -0700905
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700906 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
907 resp.errorMessage);
908
909 if (mUserIdForUserSwitchInProcess != targetUserId) {
910 // Another user switch request received while HAL responded. No need to process
911 // this request further
912 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
913 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
914 + "abondoned for : " + targetUserId + ". Current user in process: "
915 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700916 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700917 resultStatus =
918 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700919 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700920 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
921 return;
922 }
923
924 switch (resp.status) {
925 case SwitchUserStatus.SUCCESS:
926 boolean switched;
927 try {
928 switched = mAm.switchUser(targetUserId);
929 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700930 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700931 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
932 mRequestIdForUserSwitchInProcess = resp.requestId;
933 } else {
934 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
935 postSwitchHalResponse(resp.requestId, targetUserId);
936 }
937 } catch (RemoteException e) {
938 // ignore
939 Log.w(TAG_USER,
940 "error while switching user " + targetUser.toFullString(), e);
941 }
942 break;
943 case SwitchUserStatus.FAILURE:
944 // HAL failed to switch user
945 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
946 break;
felipealdfdf8512020-06-01 09:35:45 -0700947 default:
948 // Shouldn't happen because UserHalService validates the status
949 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700950 }
951
952 if (mRequestIdForUserSwitchInProcess == 0) {
953 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
954 }
Mayank Garg59f22192020-03-27 00:51:45 -0700955 }
felipealdfdf8512020-06-01 09:35:45 -0700956 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700957 });
958 }
959
Mayank Garga55c3092020-05-28 03:19:24 -0700960 @Override
961 public UserRemovalResult removeUser(@UserIdInt int userId) {
962 checkManageUsersPermission("removeUser");
963 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
964 // If the requested user is the current user, return error.
965 if (ActivityManager.getCurrentUser() == userId) {
966 return logAndGetResults(userId,
967 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
968 }
969
970 // If requested user is the only admin user, return error.
971 UserInfo userInfo = mUserManager.getUserInfo(userId);
972 if (userInfo == null) {
973 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
974 }
975
976 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
977 new android.hardware.automotive.vehicle.V2_0.UserInfo();
978 halUser.userId = userInfo.id;
979 halUser.flags = UserHalHelper.convertFlags(userInfo);
980 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
981
982 // Do not delete last admin user.
983 if (UserHalHelper.isAdmin(halUser.flags)) {
984 int size = usersInfo.existingUsers.size();
985 int totalAdminUsers = 0;
986 for (int i = 0; i < size; i++) {
987 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
988 totalAdminUsers++;
989 }
990 }
991 if (totalAdminUsers == 1) {
992 return logAndGetResults(userId,
993 UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
994 }
995 }
996
997 // First remove user from android and then remove from HAL because HAL remove user is one
998 // way call.
999 if (!mUserManager.removeUser(userId)) {
1000 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1001 }
1002
Mayank Garg9ed099e2020-06-04 16:05:20 -07001003 if (isUserHalSupported()) {
1004 RemoveUserRequest request = new RemoveUserRequest();
1005 request.removedUserInfo = halUser;
Mayank Garg4adef862020-06-16 18:12:28 -07001006 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg9ed099e2020-06-04 16:05:20 -07001007 mHal.removeUser(request);
1008 }
1009
Mayank Garga55c3092020-05-28 03:19:24 -07001010 return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
1011 }
1012
1013 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1014 @UserRemovalResult.Status int result) {
1015 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1016 return new UserRemovalResult(result);
1017 }
1018
Mayank Garg587f1942020-05-06 01:41:34 -07001019 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1020 if (mUserSwitchUiReceiver == null) {
1021 Log.w(TAG_USER, "No User switch UI receiver.");
1022 return;
1023 }
1024
felipealdfdf8512020-06-01 09:35:45 -07001025 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001026 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001027 mUserSwitchUiReceiver.send(targetUserId, null);
1028 } catch (RemoteException e) {
1029 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1030 }
1031 }
1032
felipeal5e3ede42020-04-23 18:04:07 -07001033 @Override
felipealdfdf8512020-06-01 09:35:45 -07001034 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1035 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
1036 Objects.requireNonNull(userType, "user type cannot be null");
1037 Objects.requireNonNull(receiver, "receiver cannot be null");
1038 checkManageOrCreateUsersPermission("createUser");
1039 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
1040 userType, flags, timeoutMs);
1041
1042 UserInfo newUser;
1043 try {
1044 newUser = mUserManager.createUser(name, userType, flags);
1045 if (newUser == null) {
1046 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1047 + " and flags " + UserInfo.flagsToString(flags));
1048 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1049 return;
1050 }
1051 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1052 Log.d(TAG, "Created user: " + newUser.toFullString());
1053 }
1054 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
1055 UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
1056 } catch (RuntimeException e) {
1057 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1058 + UserInfo.flagsToString(flags), e);
1059 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1060 return;
1061 }
1062
Mayank Garg9ed099e2020-06-04 16:05:20 -07001063 if (!isUserHalSupported()) {
1064 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1065 return;
1066 }
1067
felipealdfdf8512020-06-01 09:35:45 -07001068 CreateUserRequest request = new CreateUserRequest();
1069 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1070 if (!TextUtils.isEmpty(name)) {
1071 request.newUserName = name;
1072 }
1073 request.newUserInfo.userId = newUser.id;
1074 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1075 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1076 Log.d(TAG, "Create user request: " + request);
1077 }
1078
1079 try {
1080 mHal.createUser(request, timeoutMs, (status, resp) -> {
1081 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1082 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1083 Log.d(TAG, "createUserResponse: status="
1084 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1085 }
1086 UserInfo user = null; // user returned in the result
1087 if (status != HalCallback.STATUS_OK) {
1088 Log.w(TAG, "invalid callback status ("
1089 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1090 + resp);
1091 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1092 resultStatus, resp.errorMessage);
1093 removeUser(newUser, "HAL call failed with "
1094 + UserHalHelper.halCallbackStatusToString(status));
1095 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1096 return;
1097 }
1098
1099 switch (resp.status) {
1100 case CreateUserStatus.SUCCESS:
1101 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1102 user = newUser;
1103 break;
1104 case CreateUserStatus.FAILURE:
1105 // HAL failed to switch user
1106 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1107 break;
1108 default:
1109 // Shouldn't happen because UserHalService validates the status
1110 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1111 }
1112 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1113 resultStatus, resp.errorMessage);
1114 if (user == null) {
1115 removeUser(newUser, "HAL returned "
1116 + UserCreationResult.statusToString(resultStatus));
1117 }
1118 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1119 });
1120 } catch (Exception e) {
1121 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1122 removeUser(newUser, "mHal.createUser() failed");
1123 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1124 }
1125 }
1126
1127 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1128 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1129 try {
1130 if (!mUserManager.removeUser(user.id)) {
1131 Log.w(TAG, "Failed to remove user " + user.toFullString());
1132 }
1133 } catch (Exception e) {
1134 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1135 }
1136 }
1137
1138 @Override
felipeal159a2a42020-05-08 10:32:11 -07001139 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001140 if (!isUserHalUserAssociationSupported()) {
1141 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1142 }
1143
felipeal5e3ede42020-04-23 18:04:07 -07001144 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1145 checkManageUsersPermission("getUserIdentificationAssociation");
1146
1147 int uid = getCallingUid();
1148 int userId = UserHandle.getUserId(uid);
1149 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1150
1151 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1152 request.userInfo.userId = userId;
1153 request.userInfo.flags = getHalUserInfoFlags(userId);
1154
1155 request.numberAssociationTypes = types.length;
1156 for (int i = 0; i < types.length; i++) {
1157 request.associationTypes.add(types[i]);
1158 }
1159
1160 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1161 if (halResponse == null) {
1162 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1163 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001164 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001165 }
1166
1167 int[] values = new int[halResponse.associations.size()];
1168 for (int i = 0; i < values.length; i++) {
1169 values[i] = halResponse.associations.get(i).value;
1170 }
1171 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1172
felipeal159a2a42020-05-08 10:32:11 -07001173 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1174 }
1175
1176 @Override
1177 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1178 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001179 if (!isUserHalUserAssociationSupported()) {
1180 result.complete(
1181 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1182 return;
1183 }
1184
felipeal159a2a42020-05-08 10:32:11 -07001185 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1186 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1187 if (types.length != values.length) {
1188 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1189 + Arrays.toString(values) + ") should have the same length");
1190 }
1191 checkManageUsersPermission("setUserIdentificationAssociation");
1192
1193 int uid = getCallingUid();
1194 int userId = UserHandle.getUserId(uid);
1195 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1196
1197 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1198 request.userInfo.userId = userId;
1199 request.userInfo.flags = getHalUserInfoFlags(userId);
1200
1201 request.numberAssociations = types.length;
1202 for (int i = 0; i < types.length; i++) {
1203 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1204 association.type = types[i];
1205 association.value = values[i];
1206 request.associations.add(association);
1207 }
1208
1209 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1210 if (status != HalCallback.STATUS_OK) {
1211 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1212 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1213 + resp);
1214 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1215 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1216 result.complete(UserIdentificationAssociationResponse.forFailure());
1217 return;
1218 }
1219 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1220 resp.errorMessage);
1221 result.complete(
1222 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1223 return;
1224 }
1225 int respSize = resp.associations.size();
1226 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1227 resp.errorMessage);
1228
1229 int[] responseTypes = new int[respSize];
1230 for (int i = 0; i < respSize; i++) {
1231 responseTypes[i] = resp.associations.get(i).value;
1232 }
1233 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1234 .forSuccess(responseTypes, resp.errorMessage);
1235 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1236 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1237 + ", converted=" + response);
1238 }
1239 result.complete(response);
1240 });
felipeal5e3ede42020-04-23 18:04:07 -07001241 }
1242
1243 /**
1244 * Gets the User HAL flags for the given user.
1245 *
1246 * @throws IllegalArgumentException if the user does not exist.
1247 */
1248 private int getHalUserInfoFlags(@UserIdInt int userId) {
1249 UserInfo user = mUserManager.getUserInfo(userId);
1250 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1251 return UserHalHelper.convertFlags(user);
1252 }
1253
Mayank Garg0e239142020-04-14 19:16:31 -07001254 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1255 @Nullable Bundle resultData) {
1256 try {
1257 receiver.send(resultCode, resultData);
1258 } catch (RemoteException e) {
1259 // ignore
1260 Log.w(TAG_USER, "error while sending results", e);
1261 }
1262 }
1263
felipealdfdf8512020-06-01 09:35:45 -07001264 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001265 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001266 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001267 }
1268
felipealdfdf8512020-06-01 09:35:45 -07001269 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001270 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1271 receiver.complete(new UserSwitchResult(status, errorMessage));
1272 }
1273
felipealdfdf8512020-06-01 09:35:45 -07001274 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1275 @UserCreationResult.Status int status) {
1276 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1277 }
1278
1279 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1280 @UserCreationResult.Status int status, @NonNull UserInfo user,
1281 @Nullable String errorMessage) {
1282 if (TextUtils.isEmpty(errorMessage)) {
1283 errorMessage = null;
1284 }
1285 receiver.complete(new UserCreationResult(status, user, errorMessage));
1286 }
1287
Mayank Garg6307fe42020-04-15 23:09:03 -07001288 /**
1289 * Calls activity manager for user switch.
1290 *
1291 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1292 *
1293 * @param requestId for the user switch request
1294 * @param targetUserId of the target user
1295 *
1296 * @hide
1297 */
1298 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1299 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1300 targetUserId);
1301 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1302
1303 try {
1304 boolean result = mAm.switchUser(targetUserId);
1305 if (result) {
1306 updateUserSwitchInProcess(requestId, targetUserId);
1307 } else {
1308 postSwitchHalResponse(requestId, targetUserId);
1309 }
1310 } catch (RemoteException e) {
1311 // ignore
1312 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1313 }
1314 }
1315
1316 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1317 synchronized (mLockUser) {
1318 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1319 // Some other user switch is in process.
1320 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1321 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1322 + " is in process. Abandoning it as a new user switch is requested"
1323 + " for the target user: " + targetUserId);
1324 }
1325 }
1326 mUserIdForUserSwitchInProcess = targetUserId;
1327 mRequestIdForUserSwitchInProcess = requestId;
1328 }
1329 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001330
Mayank Garg7a114c82020-04-08 21:25:06 -07001331 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001332 if (!isUserHalSupported()) return;
1333
felipealdfdf8512020-06-01 09:35:45 -07001334 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001335 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1336 targetUserId, usersInfo.currentUser.userId);
1337 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1338 request.requestId = requestId;
1339 mHal.postSwitchResponse(request);
1340 }
1341
1342 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1343 @NonNull UsersInfo usersInfo) {
1344 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001345 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1346 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1347 halTargetUser.userId = targetUser.id;
1348 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001349 SwitchUserRequest request = new SwitchUserRequest();
1350 request.targetUser = halTargetUser;
1351 request.usersInfo = usersInfo;
1352 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001353 }
1354
Mayank Garg59f22192020-03-27 00:51:45 -07001355 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001356 * Checks if the User HAL is supported.
1357 */
1358 public boolean isUserHalSupported() {
1359 return mHal.isSupported();
1360 }
1361
Mayank Garg587f1942020-05-06 01:41:34 -07001362 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001363 * Checks if the User HAL user association is supported.
1364 */
1365 @Override
1366 public boolean isUserHalUserAssociationSupported() {
1367 return mHal.isUserAssociationSupported();
1368 }
1369
1370 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001371 * Sets a callback which is invoked before user switch.
1372 *
1373 * <p>
1374 * This method should only be called by the Car System UI. The purpose of this call is to notify
1375 * Car System UI to show the user switch UI before the user switch.
1376 */
1377 @Override
1378 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001379 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001380
1381 // Confirm that caller is system UI.
1382 String systemUiPackageName = getSystemUiPackageName();
1383 if (systemUiPackageName == null) {
1384 throw new IllegalStateException("System UI package not found.");
1385 }
1386
1387 try {
1388 int systemUiUid = mContext
1389 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1390 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1391 int callerUid = Binder.getCallingUid();
1392 if (systemUiUid != callerUid) {
1393 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1394 + " is allowed to make this call");
1395 }
1396 } catch (NameNotFoundException e) {
1397 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1398 }
1399
Mayank Garg587f1942020-05-06 01:41:34 -07001400 mUserSwitchUiReceiver = receiver;
1401 }
1402
Mayank Garga480dd92020-05-14 03:14:57 -07001403 // TODO(157082995): This information can be taken from
1404 // PackageManageInternalImpl.getSystemUiServiceComponent
1405 @Nullable
1406 private String getSystemUiPackageName() {
1407 try {
1408 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1409 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1410 return componentName.getPackageName();
1411 } catch (RuntimeException e) {
1412 Log.w(TAG_USER, "error while getting system UI package name.", e);
1413 return null;
1414 }
1415 }
1416
Keun young Park13a7a822019-04-04 15:53:08 -07001417 private void updateDefaultUserRestriction() {
1418 // We want to set restrictions on system and guest users only once. These are persisted
1419 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1420 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001421 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1422 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001423 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001424 // Only apply the system user restrictions if the system user is headless.
1425 if (UserManager.isHeadlessSystemUserMode()) {
1426 setSystemUserRestrictions();
1427 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001428 Settings.Global.putInt(mContext.getContentResolver(),
1429 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001430 }
1431
Eric Jeong1545f3b2019-09-16 13:56:52 -07001432 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001433 return !mUserManager.getUserInfo(userId).isEphemeral();
1434 }
1435
Antonio Kantekc8114752020-03-05 21:37:39 -08001436 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001437 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1438 */
1439 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1440 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001441 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001442 }
1443
1444 /**
1445 * Removes previously added {@link UserLifecycleListener}.
1446 */
1447 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1448 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001449 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001450 }
1451
Eric Jeongc91f9452019-08-30 15:04:21 -07001452 /** Adds callback to listen to passenger activity events. */
1453 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001454 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001455 mPassengerCallbacks.add(callback);
1456 }
1457
1458 /** Removes previously added callback to listen passenger events. */
1459 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001460 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001461 mPassengerCallbacks.remove(callback);
1462 }
1463
1464 /** Sets the implementation of ZoneUserBindingHelper. */
1465 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1466 synchronized (mLockHelper) {
1467 mZoneUserBindingHelper = helper;
1468 }
1469 }
1470
felipeal98900c82020-04-09 09:05:02 -07001471 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001472 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001473 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001474 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001475 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001476 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1477 updateDefaultUserRestriction();
1478 tasks = new ArrayList<>(mUser0UnlockTasks);
1479 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001480 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001481 }
1482 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001483 Integer user = userId;
1484 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001485 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001486 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001487 mBackgroundUsersToRestart.remove(user);
1488 mBackgroundUsersToRestart.add(0, user);
1489 }
1490 // -1 for user 0
1491 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001492 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001493 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001494 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001495 + ", dropping least recently user from restart list:" + userToDrop);
1496 // Drop the least recently used user.
1497 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1498 }
1499 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001500 }
1501 }
1502 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001503 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001504 for (Runnable r : tasks) {
1505 r.run();
1506 }
1507 }
1508 }
1509
1510 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001511 * Starts all background users that were active in system.
1512 *
Keun young Parkfb656372019-03-12 18:37:55 -07001513 * @return list of background users started successfully.
1514 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001515 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001516 public ArrayList<Integer> startAllBackgroundUsers() {
1517 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001518 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001519 users = new ArrayList<>(mBackgroundUsersToRestart);
1520 mBackgroundUsersRestartedHere.clear();
1521 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001522 }
1523 ArrayList<Integer> startedUsers = new ArrayList<>();
1524 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001525 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001526 continue;
1527 }
1528 try {
1529 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001530 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1531 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001532 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001533 } else if (mAm.unlockUser(user, null, null, null)) {
1534 startedUsers.add(user);
1535 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001536 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001537 if (mUserManager.isUserRunning(user)) {
1538 // add to started list so that it can be stopped later.
1539 startedUsers.add(user);
1540 }
Keun young Parkfb656372019-03-12 18:37:55 -07001541 }
1542 }
1543 } catch (RemoteException e) {
1544 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001545 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001546 }
1547 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001548 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001549 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001550 ArrayList<Integer> usersToRemove = new ArrayList<>();
1551 for (Integer user : mBackgroundUsersToRestart) {
1552 if (!startedUsers.contains(user)) {
1553 usersToRemove.add(user);
1554 }
1555 }
1556 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1557 }
Keun young Parkfb656372019-03-12 18:37:55 -07001558 return startedUsers;
1559 }
1560
1561 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001562 * Stops all background users that were active in system.
1563 *
1564 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001565 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001566 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001567 if (userId == UserHandle.USER_SYSTEM) {
1568 return false;
1569 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001570 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001571 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001572 return false;
1573 }
1574 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001575 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001576 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001577 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001578 Integer user = userId;
1579 mBackgroundUsersRestartedHere.remove(user);
1580 }
1581 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1582 return false;
1583 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001584 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001585 return false;
1586 }
1587 } catch (RemoteException e) {
1588 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001589 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001590 }
1591 return true;
1592 }
1593
1594 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001595 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001596 */
felipeale8c5dce2020-04-15 11:27:06 -07001597 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1598 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1599 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001600
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001601 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001602 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001603 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001604 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1605 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001606 }
1607
felipeale8c5dce2020-04-15 11:27:06 -07001608 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001609 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001610
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001611 mHandler.post(() -> {
1612 handleNotifyServiceUserLifecycleListeners(event);
1613 handleNotifyAppUserLifecycleListeners(event);
1614 });
felipeale8c5dce2020-04-15 11:27:06 -07001615
Keun young Park1fced442020-05-29 09:26:29 -07001616 if (timestampMs != 0) {
1617 // Finally, update metrics.
1618 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1619 }
felipeale8c5dce2020-04-15 11:27:06 -07001620 }
1621
Mayank Garg7a114c82020-04-08 21:25:06 -07001622 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001623 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001624 || mUserIdForUserSwitchInProcess != userId
1625 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001626 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1627 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1628 }
1629 return;
1630 }
felipealf7368962020-04-16 12:55:19 -07001631 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1632 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001633 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001634 }
1635
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001636 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1637 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001638 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001639 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1640 Log.d(TAG_USER, "No app listener to be notified of " + event);
1641 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001642 return;
1643 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001644 // Must use a different TimingsTraceLog because it's another thread
1645 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1646 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1647 }
felipeal2a84d512020-04-06 18:52:15 -07001648 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001649 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001650 int eventType = event.getEventType();
1651 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001652 for (int i = 0; i < listenersSize; i++) {
1653 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001654
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001655 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1656 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001657 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001658
felipealde1e16d2020-06-03 13:20:48 -07001659 int fromUserId = event.getPreviousUserId();
1660 if (fromUserId != UserHandle.USER_NULL) {
1661 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001662 }
1663
felipeal2a84d512020-04-06 18:52:15 -07001664 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001665 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001666 }
felipealde1e16d2020-06-03 13:20:48 -07001667 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1668 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001669 try {
felipealde1e16d2020-06-03 13:20:48 -07001670 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001671 listener.send(userId, data);
1672 } catch (RemoteException e) {
1673 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1674 } finally {
1675 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001676 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001677 }
1678 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001679 }
1680
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001681 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001682 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1683 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001684 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001685 return;
felipeal2a84d512020-04-06 18:52:15 -07001686 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1687 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1688 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001689 }
felipeal2a84d512020-04-06 18:52:15 -07001690
felipealde1e16d2020-06-03 13:20:48 -07001691 int userId = event.getUserId();
1692 int eventType = event.getEventType();
1693 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001694 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001695 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001696 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1697 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001698 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001699 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001700 listener.onEvent(event);
1701 } catch (RuntimeException e) {
1702 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001703 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001704 } finally {
1705 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001706 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001707 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001708 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001709 }
1710
Mayank Garge5de0f92020-04-23 21:38:38 -07001711 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001712 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001713 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001714 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001715
Mayank Garge5de0f92020-04-23 21:38:38 -07001716 // Switch HAL users if user switch is not requested by CarUserService
1717 notifyHalLegacySwitch(fromUserId, toUserId);
1718
felipealbf327652020-06-03 11:33:29 -07001719 mCarUserManagerHelper.setLastActiveUser(toUserId);
1720
Eric Jeongc91f9452019-08-30 15:04:21 -07001721 if (mLastPassengerId != UserHandle.USER_NULL) {
1722 stopPassengerInternal(mLastPassengerId, false);
1723 }
1724 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1725 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001726 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001727 }
felipeal98900c82020-04-09 09:05:02 -07001728 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001729 }
1730
Mayank Garge5de0f92020-04-23 21:38:38 -07001731 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1732 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001733 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1734 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1735 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1736 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1737 }
1738 return;
1739 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001740 }
1741
Mayank Garg9ed099e2020-06-04 16:05:20 -07001742 if (!isUserHalSupported()) return;
1743
Mayank Garge5de0f92020-04-23 21:38:38 -07001744 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001745 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001746 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1747 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001748 }
1749
Pavel Maltsev17e81832019-04-04 14:38:41 -07001750 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001751 * Runs the given runnable when user 0 is unlocked. If user 0 is already unlocked, it is
Keun-young Parkd462a912019-02-11 08:53:42 -08001752 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001753 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001754 * @param r Runnable to run.
1755 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001756 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001757 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001758 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001759 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001760 if (mUser0Unlocked) {
1761 runNow = true;
1762 } else {
1763 mUser0UnlockTasks.add(r);
1764 }
1765 }
1766 if (runNow) {
1767 r.run();
1768 }
1769 }
1770
Keun young Parkf3523cd2019-04-08 10:09:17 -07001771 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001772 @NonNull
1773 ArrayList<Integer> getBackgroundUsersToRestart() {
1774 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001775 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001776 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1777 }
1778 return backgroundUsersToRestart;
1779 }
1780
Ying Zheng1ab32b62018-06-26 12:47:26 -07001781 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001782 // Disable Location service for system user.
1783 LocationManager locationManager =
1784 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001785 locationManager.setLocationEnabledForUser(
1786 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001787 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001788
1789 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001790 * Assigns a default icon to a user according to the user's id.
1791 *
1792 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001793 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001794 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001795 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1796 Bitmap bitmap = UserIcons.convertToBitmap(
1797 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1798 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001799 }
1800
Eric Jeong1545f3b2019-09-16 13:56:52 -07001801 private interface UserFilter {
1802 boolean isEligibleUser(UserInfo user);
1803 }
1804
1805 /** Returns all users who are matched by the given filter. */
1806 private List<UserInfo> getUsers(UserFilter filter) {
1807 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1808
1809 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1810 UserInfo user = iterator.next();
1811 if (!filter.isEligibleUser(user)) {
1812 iterator.remove();
1813 }
1814 }
1815 return users;
1816 }
1817
1818 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001819 * Enforces that apps which have the
1820 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1821 * can make certain calls to the CarUserManager.
1822 *
1823 * @param message used as message if SecurityException is thrown.
1824 * @throws SecurityException if the caller is not system or root.
1825 */
1826 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001827 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1828 }
1829
felipealdfdf8512020-06-01 09:35:45 -07001830 private static void checkManageOrCreateUsersPermission(String message) {
1831 checkAtLeastOnePermission(message,
1832 android.Manifest.permission.MANAGE_USERS,
1833 android.Manifest.permission.CREATE_USERS);
1834 }
1835
felipeal2d0483c2019-11-02 14:07:22 -07001836 private static void checkManageUsersOrDumpPermission(String message) {
1837 checkAtLeastOnePermission(message,
1838 android.Manifest.permission.MANAGE_USERS,
1839 android.Manifest.permission.DUMP);
1840 }
1841
Felipe Leme5528ff72020-02-10 19:05:14 -08001842 private void checkInteractAcrossUsersPermission(String message) {
1843 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1844 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1845 }
1846
felipeal2d0483c2019-11-02 14:07:22 -07001847 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001848 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001849 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1850 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001851 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001852 }
1853 }
1854
felipeal2d0483c2019-11-02 14:07:22 -07001855 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1856 for (String permission : permissions) {
1857 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1858 /* exported = */ true)
1859 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1860 return true;
1861 }
1862 }
1863 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001864 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001865
1866 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1867 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1868 // Count all users that are managed profiles of the given user.
1869 int managedProfilesCount = 0;
1870 for (UserInfo user : users) {
1871 if (user.isManagedProfile() && user.profileGroupId == userId) {
1872 managedProfilesCount++;
1873 }
1874 }
1875 return managedProfilesCount;
1876 }
1877
1878 /**
1879 * Starts the first passenger of the given driver and assigns the passenger to the front
1880 * passenger zone.
1881 *
1882 * @param driverId User id of the driver.
1883 * @return whether it succeeds.
1884 */
1885 private boolean startFirstPassenger(@UserIdInt int driverId) {
1886 int zoneId = getAvailablePassengerZone();
1887 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1888 Log.w(TAG_USER, "passenger occupant zone is not found");
1889 return false;
1890 }
1891 List<UserInfo> passengers = getPassengers(driverId);
1892 if (passengers.size() < 1) {
1893 Log.w(TAG_USER, "passenger is not found");
1894 return false;
1895 }
1896 // Only one passenger is supported. If there are two or more passengers, the first passenger
1897 // is chosen.
1898 int passengerId = passengers.get(0).id;
1899 if (!startPassenger(passengerId, zoneId)) {
1900 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1901 return false;
1902 }
1903 return true;
1904 }
1905
1906 private int getAvailablePassengerZone() {
1907 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1908 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1909 for (int occupantType : occupantTypes) {
1910 int zoneId = getZoneId(occupantType);
1911 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1912 return zoneId;
1913 }
1914 }
1915 return OccupantZoneInfo.INVALID_ZONE_ID;
1916 }
1917
1918 /**
1919 * Creates a new passenger user when there is no passenger user.
1920 */
1921 private void setupPassengerUser() {
1922 int currentUser = ActivityManager.getCurrentUser();
1923 int profileCount = getNumberOfManagedProfiles(currentUser);
1924 if (profileCount > 0) {
1925 Log.w(TAG_USER, "max profile of user" + currentUser
1926 + " is exceeded: current profile count is " + profileCount);
1927 return;
1928 }
1929 // TODO(b/140311342): Use resource string for the default passenger name.
1930 UserInfo passenger = createPassenger("Passenger", currentUser);
1931 if (passenger == null) {
1932 // Couldn't create user, most likely because there are too many.
1933 Log.w(TAG_USER, "cannot create a passenger user");
1934 return;
1935 }
1936 }
1937
1938 @NonNull
1939 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1940 ZoneUserBindingHelper helper = null;
1941 synchronized (mLockHelper) {
1942 if (mZoneUserBindingHelper == null) {
1943 Log.w(TAG_USER, "implementation is not delegated");
1944 return new ArrayList<OccupantZoneInfo>();
1945 }
1946 helper = mZoneUserBindingHelper;
1947 }
1948 return helper.getOccupantZones(occupantType);
1949 }
1950
1951 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1952 ZoneUserBindingHelper helper = null;
1953 synchronized (mLockHelper) {
1954 if (mZoneUserBindingHelper == null) {
1955 Log.w(TAG_USER, "implementation is not delegated");
1956 return false;
1957 }
1958 helper = mZoneUserBindingHelper;
1959 }
1960 return helper.assignUserToOccupantZone(userId, zoneId);
1961 }
1962
1963 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1964 ZoneUserBindingHelper helper = null;
1965 synchronized (mLockHelper) {
1966 if (mZoneUserBindingHelper == null) {
1967 Log.w(TAG_USER, "implementation is not delegated");
1968 return false;
1969 }
1970 helper = mZoneUserBindingHelper;
1971 }
1972 return helper.unassignUserFromOccupantZone(userId);
1973 }
1974
1975 private boolean isPassengerDisplayAvailable() {
1976 ZoneUserBindingHelper helper = null;
1977 synchronized (mLockHelper) {
1978 if (mZoneUserBindingHelper == null) {
1979 Log.w(TAG_USER, "implementation is not delegated");
1980 return false;
1981 }
1982 helper = mZoneUserBindingHelper;
1983 }
1984 return helper.isPassengerDisplayAvailable();
1985 }
1986
1987 /**
1988 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1989 * zone is returned.
1990 *
1991 * @param occupantType The type of an occupant.
1992 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1993 * if not found.
1994 */
1995 private int getZoneId(@OccupantTypeEnum int occupantType) {
1996 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1997 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1998 }
Mayank Garg9732d602020-08-09 21:02:40 -07001999
2000 /**
2001 * Manages the required number of pre-created users.
2002 */
2003 public void preCreateUsers() {
2004 mUserPreCreator.managePreCreatedUsers();
2005 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002006}