blob: 0c8b4d8bddadabdeb9285f0bcf6517700a447140 [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;
Louis Chang3bf2f202020-08-18 13:04:28 +080025import android.app.ActivityTaskManager.RootTaskInfo;
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;
felipeal19e3d732020-03-18 12:07:32 -070041import android.car.userlib.HalCallback;
42import android.car.userlib.UserHalHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070043import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070044import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.pm.PackageManager;
46import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070047import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070048import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070049import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070050import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070051import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
52import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070053import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080054import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070055import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070056import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070057import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070058import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
59import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080062import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070063import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070064import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080065import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070066import android.os.Handler;
67import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070068import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080069import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070070import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070071import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070072import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070073import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070074import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070075import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080077import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080078import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070079
80import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070081import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070082import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080083import com.android.car.hal.UserHalService;
Mayank Garg94f3eb92020-08-12 12:38:58 -070084import com.android.car.internal.CommonConstants;
85import com.android.car.internal.EventLogTags;
86import com.android.car.internal.UserHelperLite;
Mayank Garg4bdfbf72020-08-06 13:27:43 -070087import com.android.car.power.CarPowerManagementService;
Mayank Garg665c20b2020-08-07 16:19:28 -070088import com.android.car.user.InitialUserSetter.InitialUserInfo;
Keun-young Parkd462a912019-02-11 08:53:42 -080089import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070090import com.android.internal.annotations.VisibleForTesting;
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. */
Mayank Garg94f3eb92020-08-12 12:38:58 -0700123 public static final String BUNDLE_USER_ID = CommonConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800124 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Mayank Garg94f3eb92020-08-12 12:38:58 -0700125 public static final String BUNDLE_USER_FLAGS = CommonConstants.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. */
Mayank Garg94f3eb92020-08-12 12:38:58 -0700127 public static final String BUNDLE_USER_NAME = CommonConstants.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 =
Mayank Garg94f3eb92020-08-12 12:38:58 -0700132 CommonConstants.BUNDLE_USER_LOCALES;
felipeala68ecef2020-05-19 12:46:08 -0700133 /**
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 =
Mayank Garg94f3eb92020-08-12 12:38:58 -0700137 CommonConstants.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
Mayank Garg7e1450b2020-08-07 18:15:15 -0700204 // TODO(b/163566866): Use mSwitchGuestUserBeforeSleep for new create guest request
205 private final boolean mSwitchGuestUserBeforeSleep;
206
felipeal61ce3732020-04-03 11:01:00 -0700207 @Nullable
208 @GuardedBy("mLockUser")
209 private UserInfo mInitialUser;
210
Mayank Garg71661ea2020-04-29 01:25:03 -0700211 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700212
Mayank Garg587f1942020-05-06 01:41:34 -0700213 private IResultReceiver mUserSwitchUiReceiver;
214
Eric Jeongc91f9452019-08-30 15:04:21 -0700215 /** Interface for callbaks related to passenger activities. */
216 public interface PassengerCallback {
217 /** Called when passenger is started at a certain zone. */
218 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
219 /** Called when passenger is stopped. */
220 void onPassengerStopped(@UserIdInt int passengerId);
221 }
222
223 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
224 public interface ZoneUserBindingHelper {
225 /** Gets occupant zones corresponding to the occupant type. */
226 @NonNull
227 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
228 /** Assigns the user to the occupant zone. */
229 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
230 /** Makes the occupant zone unoccupied. */
231 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
232 /** Returns whether there is a passenger display. */
233 boolean isPassengerDisplayAvailable();
234 }
235
236 private final Object mLockHelper = new Object();
237 @GuardedBy("mLockHelper")
238 private ZoneUserBindingHelper mZoneUserBindingHelper;
239
Felipe Leme58412202020-01-09 13:45:33 -0800240 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700241 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
242 @NonNull IActivityManager am, int maxRunningUsers) {
243 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
Mayank Garg70732a82020-08-05 20:17:47 -0700244 new UserMetrics(), /* initialUserSetter= */ null);
Mayank Garg71661ea2020-04-29 01:25:03 -0700245 }
246
247 @VisibleForTesting
248 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
249 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
Mayank Garg70732a82020-08-05 20:17:47 -0700250 @NonNull IActivityManager am, int maxRunningUsers, @NonNull UserMetrics userMetrics,
251 @Nullable InitialUserSetter initialUserSetter) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700252 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
253 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700254 }
255 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800256 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700257 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700258 mAm = am;
259 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700260 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700261 mLastPassengerId = UserHandle.USER_NULL;
Mayank Garg71661ea2020-04-29 01:25:03 -0700262 mUserMetrics = userMetrics;
Mayank Garg70732a82020-08-05 20:17:47 -0700263 if (initialUserSetter == null) {
264 mInitialUserSetter = new InitialUserSetter(context, (u) -> setInitialUser(u));
265 } else {
266 mInitialUserSetter = initialUserSetter;
267 }
Mayank Garg9732d602020-08-09 21:02:40 -0700268 mUserPreCreator = new UserPreCreator(mUserManager);
Mayank Garg7e1450b2020-08-07 18:15:15 -0700269 Resources resources = context.getResources();
270 mEnablePassengerSupport = resources.getBoolean(R.bool.enablePassengerSupport);
271 mSwitchGuestUserBeforeSleep = resources.getBoolean(
272 R.bool.config_switchGuestUserBeforeGoingSleep);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700273 }
274
275 @Override
276 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700277 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
278 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700279 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700280 }
281
282 @Override
283 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700284 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
285 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700286 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700287 }
288
289 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700290 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700291 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700292 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800293 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700294 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700295 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700296 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700297 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700298 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
299 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700300 }
301 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
302 List<UserInfo> allDrivers = getAllDrivers();
303 int driversSize = allDrivers.size();
304 writer.println("NumberOfDrivers: " + driversSize);
305 for (int i = 0; i < driversSize; i++) {
306 int driverId = allDrivers.get(i).id;
307 writer.print(indent + "#" + i + ": id=" + driverId);
308 List<UserInfo> passengers = getPassengers(driverId);
309 int passengersSize = passengers.size();
310 writer.print(" NumberPassengers: " + passengersSize);
311 if (passengersSize > 0) {
312 writer.print(" [");
313 for (int j = 0; j < passengersSize; j++) {
314 writer.print(passengers.get(j).id);
315 if (j < passengersSize - 1) {
316 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700317 }
felipeal2d0483c2019-11-02 14:07:22 -0700318 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700319 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700320 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700321 writer.println();
322 }
323 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
324 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
325 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700326
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700327 writer.println("Relevant overlayable properties");
328 Resources res = mContext.getResources();
329 writer.printf("%sowner_name=%s\n", indent,
330 res.getString(com.android.internal.R.string.owner_name));
331 writer.printf("%sdefault_guest_name=%s\n", indent,
332 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700333 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700334 writer.printf("Request Id for the user switch in process=%d\n ",
335 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700336 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700337
felipealbf327652020-06-03 11:33:29 -0700338 writer.println("Relevant Global settings");
339 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
340 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
341
felipeale8c5dce2020-04-15 11:27:06 -0700342 dumpUserMetrics(writer);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700343
344 mInitialUserSetter.dump(writer);
felipeale8c5dce2020-04-15 11:27:06 -0700345 }
346
felipealbf327652020-06-03 11:33:29 -0700347 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
348 String value = Settings.Global.getString(mContext.getContentResolver(), property);
349 writer.printf("%s%s=%s\n", indent, property, value);
350 }
351
felipeale8c5dce2020-04-15 11:27:06 -0700352 /**
353 * Dumps user metrics.
354 */
355 public void dumpUserMetrics(@NonNull PrintWriter writer) {
356 mUserMetrics.dump(writer);
357 }
358
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700359 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
360 CountDownLatch latch = new CountDownLatch(1);
361 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700362 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700363 handleDumpAppLifecycleListeners(writer, indent);
364 latch.countDown();
365 });
366 int timeout = 5;
367 try {
368 if (!latch.await(timeout, TimeUnit.SECONDS)) {
369 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
370 timeout);
371 }
372 } catch (InterruptedException e) {
373 Thread.currentThread().interrupt();
374 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
375 }
376 }
377
felipealde1e16d2020-06-03 13:20:48 -0700378 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700379 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700380 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700381 return;
382 }
felipealde1e16d2020-06-03 13:20:48 -0700383 int size = mUserLifecycleListeners.size();
384 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
385 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700386 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700387 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700388 }
389 }
390
391 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700392 int size = mAppLifecycleListeners.size();
393 if (size == 0) {
394 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700395 return;
396 }
felipealde1e16d2020-06-03 13:20:48 -0700397 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
398 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700399 int uid = mAppLifecycleListeners.keyAt(i);
400 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700401 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800402 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700403 }
404
405 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700406 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700407 */
408 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700409 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700410 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000411 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700412
413 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
414 @Override
415 protected void onCompleted(UserCreationResult result, Throwable err) {
416 if (result == null) {
417 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
418 } else {
419 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
420 assignDefaultIcon(result.getUser());
421 }
422 }
423 super.onCompleted(result, err);
424 };
425 };
426 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700427 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700428 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
429 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
430 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
431 return future;
432 }
433 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700434 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700435 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
436 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700437 }
438
439 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700440 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 */
442 @Override
443 @Nullable
444 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
445 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000446 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 UserInfo driver = mUserManager.getUserInfo(driverId);
448 if (driver == null) {
449 Log.w(TAG_USER, "the driver is invalid");
450 return null;
451 }
452 if (driver.isGuest()) {
453 Log.w(TAG_USER, "a guest driver cannot create a passenger");
454 return null;
455 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700456 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700457 UserInfo user = mUserManager.createProfileForUser(name,
458 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700459 if (user == null) {
460 // Couldn't create user, most likely because there are too many.
461 Log.w(TAG_USER, "can't create a profile for user" + driverId);
462 return null;
463 }
464 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700465 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700466 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700467 return user;
468 }
469
470 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700471 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700472 */
473 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700474 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700475 checkManageUsersPermission("switchDriver");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700476 if (UserHelperLite.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700477 // System user doesn't associate with real person, can not be switched to.
478 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
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 }
482 int userSwitchable = mUserManager.getUserSwitchability();
483 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
484 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700485 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700486 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700487 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700488 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700489 }
490
491 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800492 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
493 *
494 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700495 */
496 @Override
497 @NonNull
498 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700499 checkManageUsersOrDumpPermission("getAllDrivers");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700500 return getUsers((user) -> !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700501 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700502 }
503
504 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800505 * Returns all passengers under the given driver.
506 *
507 * @param driverId User id of a driver.
508 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700509 */
510 @Override
511 @NonNull
512 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700513 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700514 return getUsers((user) -> {
Mayank Garg94f3eb92020-08-12 12:38:58 -0700515 return !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Eric Jeong40f8fa32020-05-12 12:23:33 -0700516 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700517 });
518 }
519
520 /**
521 * @see CarUserManager.startPassenger
522 */
523 @Override
524 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
525 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700526 synchronized (mLockUser) {
527 try {
528 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
529 Log.w(TAG_USER, "could not start passenger");
530 return false;
531 }
532 } catch (RemoteException e) {
533 // ignore
534 Log.w(TAG_USER, "error while starting passenger", e);
535 return false;
536 }
537 if (!assignUserToOccupantZone(passengerId, zoneId)) {
538 Log.w(TAG_USER, "could not assign passenger to zone");
539 return false;
540 }
541 mLastPassengerId = passengerId;
542 }
543 for (PassengerCallback callback : mPassengerCallbacks) {
544 callback.onPassengerStarted(passengerId, zoneId);
545 }
546 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700547 }
548
549 /**
550 * @see CarUserManager.stopPassenger
551 */
552 @Override
553 public boolean stopPassenger(@UserIdInt int passengerId) {
554 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700555 return stopPassengerInternal(passengerId, true);
556 }
557
558 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
559 synchronized (mLockUser) {
560 UserInfo passenger = mUserManager.getUserInfo(passengerId);
561 if (passenger == null) {
562 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
563 return false;
564 }
565 if (mLastPassengerId != passengerId) {
566 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
567 return true;
568 }
569 if (checkCurrentDriver) {
570 int currentUser = ActivityManager.getCurrentUser();
571 if (passenger.profileGroupId != currentUser) {
572 Log.w(TAG_USER, "passenger " + passengerId
573 + " is not a profile of the current user");
574 return false;
575 }
576 }
577 // Passenger is a profile, so cannot be stopped through activity manager.
578 // Instead, activities started by the passenger are stopped and the passenger is
579 // unassigned from the zone.
580 stopAllTasks(passengerId);
581 if (!unassignUserFromOccupantZone(passengerId)) {
582 Log.w(TAG_USER, "could not unassign user from occupant zone");
583 return false;
584 }
585 mLastPassengerId = UserHandle.USER_NULL;
586 }
587 for (PassengerCallback callback : mPassengerCallbacks) {
588 callback.onPassengerStopped(passengerId);
589 }
590 return true;
591 }
592
593 private void stopAllTasks(@UserIdInt int userId) {
594 try {
Louis Chang3bf2f202020-08-18 13:04:28 +0800595 for (RootTaskInfo info : mAm.getAllRootTaskInfos()) {
596 for (int i = 0; i < info.childTaskIds.length; i++) {
597 if (info.childTaskUserIds[i] == userId) {
598 int taskId = info.childTaskIds[i];
Eric Jeongc91f9452019-08-30 15:04:21 -0700599 if (!mAm.removeTask(taskId)) {
600 Log.w(TAG_USER, "could not remove task " + taskId);
601 }
602 }
603 }
604 }
605 } catch (RemoteException e) {
606 Log.e(TAG_USER, "could not get stack info", e);
607 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700608 }
609
Felipe Leme5528ff72020-02-10 19:05:14 -0800610 @Override
611 public void setLifecycleListenerForUid(IResultReceiver listener) {
612 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700613 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800614 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
615
616 try {
617 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
618 } catch (RemoteException e) {
619 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
620 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700621 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800622 }
623
624 private void onListenerDeath(int uid) {
625 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700626 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800627 }
628
629 @Override
630 public void resetLifecycleListenerForUid() {
631 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700632 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800633 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700634 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800635 }
636
Felipe Lemee3cab982020-03-12 11:39:29 -0700637 /**
felipeal61ce3732020-04-03 11:01:00 -0700638 * Gets the initial foreground user after the device boots or resumes from suspension.
639 *
640 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
641 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
642 * method returns {@code null}.
643 *
644 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
645 * (like switching to the last active user), and this method will return the result of such
646 * operation.
647 *
648 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
649 * {@code null}.
650 *
651 * @hide
652 */
653 @Nullable
654 public UserInfo getInitialUser() {
655 checkInteractAcrossUsersPermission("getInitialUser");
656 synchronized (mLockUser) {
657 return mInitialUser;
658 }
659 }
660
felipeal61ce3732020-04-03 11:01:00 -0700661 /**
662 * Sets the initial foreground user after the device boots or resumes from suspension.
663 */
664 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700665 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
666 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700667 synchronized (mLockUser) {
668 mInitialUser = user;
669 }
670 if (user == null) {
671 // This mean InitialUserSetter failed and could not fallback, so the initial user was
672 // not switched (and most likely is SYSTEM_USER).
673 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
674 Log.wtf(TAG_USER, "Initial user set to null");
675 }
676 }
677
Mayank Garg7e1450b2020-08-07 18:15:15 -0700678 private void initResumeReplaceGuest() {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700679 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 /**
Mayank Garg7e1450b2020-08-07 18:15:15 -0700691 * Calls to switch user at the power resume or suspend.
692 *
693 * <p><b>Note:</b> Should be used only by {@link CarPowerManagementService}
694 *
695 * @param onSuspend true if called during suspend, false if called during resume.
696 * @param allowUserSwitch true if OEM configuration allows user switching.
697 */
698 public void switchUserIfNecessary(boolean onSuspend, boolean allowUserSwitch) {
699 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
700 Log.d(TAG_USER, "switchUserIfNecessary(" + onSuspend + ", " + allowUserSwitch + "):"
701 + ", mSwitchGuestUserBeforeSleep=" + mSwitchGuestUserBeforeSleep);
702 }
703
704 if (onSuspend) {
705 if (mSwitchGuestUserBeforeSleep) {
706 initResumeReplaceGuest();
707 }
708 } else {
709 if (!allowUserSwitch) {
710 if (!mSwitchGuestUserBeforeSleep) {
711 initResumeReplaceGuest();
712 }
713 return;
714 }
715
716 initBootUser(InitialUserInfoRequestType.RESUME);
717 }
718 }
719
720 /**
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700721 * Calls to start user at the android startup.
Mayank Garg70732a82020-08-05 20:17:47 -0700722 */
723 public void initBootUser() {
724 int requestType = getInitialUserInfoRequestType();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700725 initBootUser(requestType);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700726 }
727
Mayank Garg7e1450b2020-08-07 18:15:15 -0700728 private void initBootUser(int requestType) {
729 boolean replaceGuest =
730 requestType == InitialUserInfoRequestType.RESUME && !mSwitchGuestUserBeforeSleep;
Mayank Garg70732a82020-08-05 20:17:47 -0700731 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
732 mHalTimeoutMs);
733 checkManageUsersPermission("startInitialUser");
734
735 if (!isUserHalSupported()) {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700736 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700737 return;
738 }
739
740 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
741 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
742 if (resp != null) {
743 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
744 status, resp.action, resp.userToSwitchOrCreate.userId,
745 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
746
747 String userLocales = resp.userLocales;
748 InitialUserInfo info;
749 switch (resp.action) {
750 case InitialUserInfoResponseAction.SWITCH:
751 int userId = resp.userToSwitchOrCreate.userId;
752 if (userId <= 0) {
753 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700754 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700755 break;
756 }
757 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
758 .setUserLocales(userLocales)
759 .setSwitchUserId(userId)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700760 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700761 .build();
762 mInitialUserSetter.set(info);
763 break;
764
765 case InitialUserInfoResponseAction.CREATE:
766 int halFlags = resp.userToSwitchOrCreate.flags;
767 String userName = resp.userNameToCreate;
768 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
769 .setUserLocales(userLocales)
770 .setNewUserName(userName)
771 .setNewUserFlags(halFlags)
772 .build();
773 mInitialUserSetter.set(info);
774 break;
775
776 case InitialUserInfoResponseAction.DEFAULT:
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700777 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700778 break;
779 default:
780 Log.w(TAG_USER, "invalid response action on " + resp);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700781 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700782 break;
783
784 }
785 } else {
786 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700787 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700788 }
789 });
790 }
791
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700792 private void fallbackToDefaultInitialUserBehavior(String userLocales, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700793 InitialUserInfo info = new InitialUserSetter.Builder(
794 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
795 .setUserLocales(userLocales)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700796 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700797 .build();
798 mInitialUserSetter.set(info);
799 }
800
801 @VisibleForTesting
802 int getInitialUserInfoRequestType() {
803 if (!mCarUserManagerHelper.hasInitialUser()) {
804 return InitialUserInfoRequestType.FIRST_BOOT;
805 }
806 if (mContext.getPackageManager().isDeviceUpgrading()) {
807 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
808 }
809 return InitialUserInfoRequestType.COLD_BOOT;
810 }
811
812 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700813 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
814 *
815 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700816 * When everything works well, the workflow is:
817 * <ol>
818 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
819 * type, current user id, target user id, and a callback.
820 * <li> HAL called back with SUCCESS.
821 * <li> {@link IActivityManager} is called for Android user switch.
822 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
823 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
824 * request type, current user id, and target user id. In this case, the current and target
825 * user IDs would be same.
826 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700827 *
828 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700829 * Corner cases:
830 * <ul>
831 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700832 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700833 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
834 * {@code STATUS_HAL_INTERNAL_FAILURE}.
835 * <li> If HAL user switch call is successful, but android user switch call fails,
836 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
837 * target user id, but in this case the current and target user IDs would be different.
838 * <li> If another user switch request for the same target user is received while previous
839 * request is in process, receiver would receive
840 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
841 * <li> If a user switch request is received while another user switch request for different
842 * target user is in process, the previous request would be abandoned and new request will be
843 * processed. No POST_SWITCH would be sent for the previous request.
844 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700845 *
Mayank Garge19c2922020-03-30 18:05:53 -0700846 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700847 * @param timeoutMs - timeout for HAL to wait
848 * @param receiver - receiver for the results
849 */
Mayank Garge19c2922020-03-30 18:05:53 -0700850 @Override
851 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700852 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700853 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700854 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700855 Objects.requireNonNull(receiver);
856 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700857 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700858
felipealf7368962020-04-16 12:55:19 -0700859 int currentUser = ActivityManager.getCurrentUser();
860 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700861 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
862 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
863 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700864 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700865 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700866 return;
867 }
868
Mayank Garg9ed099e2020-06-04 16:05:20 -0700869 // If User Hal is not supported, just android user switch.
870 if (!isUserHalSupported()) {
871 try {
872 if (mAm.switchUser(targetUserId)) {
873 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
874 return;
875 }
876 } catch (RemoteException e) {
877 // ignore
878 Log.w(TAG_USER,
879 "error while switching user " + targetUser.toFullString(), e);
880 }
881 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
882 return;
883 }
884
Mayank Garg7a114c82020-04-08 21:25:06 -0700885 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700886 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
887 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
888 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
889 }
890
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700891 // If there is another request for the same target user, return another request in
892 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
893 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
894 // user switch request in process for different target user, but that request is now
895 // ignored.
felipealf7368962020-04-16 12:55:19 -0700896 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700897 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
898 Log.d(TAG_USER,
899 "Another user switch request in process for the requested target user: "
900 + targetUserId);
901 }
902
903 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700904 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700905 return;
906 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700907 else {
908 mUserIdForUserSwitchInProcess = targetUserId;
909 mRequestIdForUserSwitchInProcess = 0;
910 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700911 }
912
felipealdfdf8512020-06-01 09:35:45 -0700913 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700914 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
915
916 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700917 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
918 Log.d(TAG, "switch response: status="
919 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
920 }
921
felipeale5bf0322020-04-16 15:10:57 -0700922 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700923
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700924 synchronized (mLockUser) {
925 if (status != HalCallback.STATUS_OK) {
926 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
927 Log.w(TAG, "invalid callback status ("
928 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
929 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700930 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700931 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
932 return;
933 }
felipealf7368962020-04-16 12:55:19 -0700934
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700935 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
936 resp.errorMessage);
937
938 if (mUserIdForUserSwitchInProcess != targetUserId) {
939 // Another user switch request received while HAL responded. No need to process
940 // this request further
941 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
942 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
943 + "abondoned for : " + targetUserId + ". Current user in process: "
944 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700945 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700946 resultStatus =
947 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700948 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700949 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
950 return;
951 }
952
953 switch (resp.status) {
954 case SwitchUserStatus.SUCCESS:
955 boolean switched;
956 try {
957 switched = mAm.switchUser(targetUserId);
958 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700959 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700960 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
961 mRequestIdForUserSwitchInProcess = resp.requestId;
962 } else {
963 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
964 postSwitchHalResponse(resp.requestId, targetUserId);
965 }
966 } catch (RemoteException e) {
967 // ignore
968 Log.w(TAG_USER,
969 "error while switching user " + targetUser.toFullString(), e);
970 }
971 break;
972 case SwitchUserStatus.FAILURE:
973 // HAL failed to switch user
974 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
975 break;
felipealdfdf8512020-06-01 09:35:45 -0700976 default:
977 // Shouldn't happen because UserHalService validates the status
978 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700979 }
980
981 if (mRequestIdForUserSwitchInProcess == 0) {
982 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
983 }
Mayank Garg59f22192020-03-27 00:51:45 -0700984 }
felipealdfdf8512020-06-01 09:35:45 -0700985 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700986 });
987 }
988
Mayank Garga55c3092020-05-28 03:19:24 -0700989 @Override
990 public UserRemovalResult removeUser(@UserIdInt int userId) {
991 checkManageUsersPermission("removeUser");
992 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
993 // If the requested user is the current user, return error.
994 if (ActivityManager.getCurrentUser() == userId) {
995 return logAndGetResults(userId,
996 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
997 }
998
999 // If requested user is the only admin user, return error.
1000 UserInfo userInfo = mUserManager.getUserInfo(userId);
1001 if (userInfo == null) {
1002 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
1003 }
1004
1005 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1006 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1007 halUser.userId = userInfo.id;
1008 halUser.flags = UserHalHelper.convertFlags(userInfo);
1009 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1010
1011 // Do not delete last admin user.
1012 if (UserHalHelper.isAdmin(halUser.flags)) {
1013 int size = usersInfo.existingUsers.size();
1014 int totalAdminUsers = 0;
1015 for (int i = 0; i < size; i++) {
1016 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
1017 totalAdminUsers++;
1018 }
1019 }
1020 if (totalAdminUsers == 1) {
1021 return logAndGetResults(userId,
1022 UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
1023 }
1024 }
1025
1026 // First remove user from android and then remove from HAL because HAL remove user is one
1027 // way call.
1028 if (!mUserManager.removeUser(userId)) {
1029 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1030 }
1031
Mayank Garg9ed099e2020-06-04 16:05:20 -07001032 if (isUserHalSupported()) {
1033 RemoveUserRequest request = new RemoveUserRequest();
1034 request.removedUserInfo = halUser;
Mayank Garg4adef862020-06-16 18:12:28 -07001035 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg9ed099e2020-06-04 16:05:20 -07001036 mHal.removeUser(request);
1037 }
1038
Mayank Garga55c3092020-05-28 03:19:24 -07001039 return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
1040 }
1041
1042 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1043 @UserRemovalResult.Status int result) {
1044 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1045 return new UserRemovalResult(result);
1046 }
1047
Mayank Garg587f1942020-05-06 01:41:34 -07001048 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1049 if (mUserSwitchUiReceiver == null) {
1050 Log.w(TAG_USER, "No User switch UI receiver.");
1051 return;
1052 }
1053
felipealdfdf8512020-06-01 09:35:45 -07001054 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001055 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001056 mUserSwitchUiReceiver.send(targetUserId, null);
1057 } catch (RemoteException e) {
1058 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1059 }
1060 }
1061
felipeal5e3ede42020-04-23 18:04:07 -07001062 @Override
felipealdfdf8512020-06-01 09:35:45 -07001063 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1064 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
1065 Objects.requireNonNull(userType, "user type cannot be null");
1066 Objects.requireNonNull(receiver, "receiver cannot be null");
1067 checkManageOrCreateUsersPermission("createUser");
Mayank Garg94f3eb92020-08-12 12:38:58 -07001068 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
1069 UserHelperLite.safeName(name), userType, flags, timeoutMs);
felipealdfdf8512020-06-01 09:35:45 -07001070
1071 UserInfo newUser;
1072 try {
1073 newUser = mUserManager.createUser(name, userType, flags);
1074 if (newUser == null) {
1075 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1076 + " and flags " + UserInfo.flagsToString(flags));
1077 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1078 return;
1079 }
1080 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1081 Log.d(TAG, "Created user: " + newUser.toFullString());
1082 }
1083 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
Mayank Garg94f3eb92020-08-12 12:38:58 -07001084 UserHelperLite.safeName(newUser.name), newUser.userType, newUser.flags);
felipealdfdf8512020-06-01 09:35:45 -07001085 } catch (RuntimeException e) {
1086 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1087 + UserInfo.flagsToString(flags), e);
1088 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1089 return;
1090 }
1091
Mayank Garg9ed099e2020-06-04 16:05:20 -07001092 if (!isUserHalSupported()) {
1093 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1094 return;
1095 }
1096
felipealdfdf8512020-06-01 09:35:45 -07001097 CreateUserRequest request = new CreateUserRequest();
1098 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1099 if (!TextUtils.isEmpty(name)) {
1100 request.newUserName = name;
1101 }
1102 request.newUserInfo.userId = newUser.id;
1103 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1104 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1105 Log.d(TAG, "Create user request: " + request);
1106 }
1107
1108 try {
1109 mHal.createUser(request, timeoutMs, (status, resp) -> {
1110 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1111 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1112 Log.d(TAG, "createUserResponse: status="
1113 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1114 }
1115 UserInfo user = null; // user returned in the result
1116 if (status != HalCallback.STATUS_OK) {
1117 Log.w(TAG, "invalid callback status ("
1118 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1119 + resp);
1120 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1121 resultStatus, resp.errorMessage);
1122 removeUser(newUser, "HAL call failed with "
1123 + UserHalHelper.halCallbackStatusToString(status));
1124 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1125 return;
1126 }
1127
1128 switch (resp.status) {
1129 case CreateUserStatus.SUCCESS:
1130 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1131 user = newUser;
1132 break;
1133 case CreateUserStatus.FAILURE:
1134 // HAL failed to switch user
1135 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1136 break;
1137 default:
1138 // Shouldn't happen because UserHalService validates the status
1139 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1140 }
1141 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1142 resultStatus, resp.errorMessage);
1143 if (user == null) {
1144 removeUser(newUser, "HAL returned "
1145 + UserCreationResult.statusToString(resultStatus));
1146 }
1147 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1148 });
1149 } catch (Exception e) {
1150 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1151 removeUser(newUser, "mHal.createUser() failed");
1152 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1153 }
1154 }
1155
1156 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1157 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1158 try {
1159 if (!mUserManager.removeUser(user.id)) {
1160 Log.w(TAG, "Failed to remove user " + user.toFullString());
1161 }
1162 } catch (Exception e) {
1163 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1164 }
1165 }
1166
1167 @Override
felipeal159a2a42020-05-08 10:32:11 -07001168 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001169 if (!isUserHalUserAssociationSupported()) {
1170 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1171 }
1172
felipeal5e3ede42020-04-23 18:04:07 -07001173 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1174 checkManageUsersPermission("getUserIdentificationAssociation");
1175
1176 int uid = getCallingUid();
1177 int userId = UserHandle.getUserId(uid);
1178 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1179
1180 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1181 request.userInfo.userId = userId;
1182 request.userInfo.flags = getHalUserInfoFlags(userId);
1183
1184 request.numberAssociationTypes = types.length;
1185 for (int i = 0; i < types.length; i++) {
1186 request.associationTypes.add(types[i]);
1187 }
1188
1189 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1190 if (halResponse == null) {
1191 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1192 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001193 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001194 }
1195
1196 int[] values = new int[halResponse.associations.size()];
1197 for (int i = 0; i < values.length; i++) {
1198 values[i] = halResponse.associations.get(i).value;
1199 }
1200 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1201
felipeal159a2a42020-05-08 10:32:11 -07001202 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1203 }
1204
1205 @Override
1206 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1207 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001208 if (!isUserHalUserAssociationSupported()) {
1209 result.complete(
1210 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1211 return;
1212 }
1213
felipeal159a2a42020-05-08 10:32:11 -07001214 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1215 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1216 if (types.length != values.length) {
1217 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1218 + Arrays.toString(values) + ") should have the same length");
1219 }
1220 checkManageUsersPermission("setUserIdentificationAssociation");
1221
1222 int uid = getCallingUid();
1223 int userId = UserHandle.getUserId(uid);
1224 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1225
1226 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1227 request.userInfo.userId = userId;
1228 request.userInfo.flags = getHalUserInfoFlags(userId);
1229
1230 request.numberAssociations = types.length;
1231 for (int i = 0; i < types.length; i++) {
1232 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1233 association.type = types[i];
1234 association.value = values[i];
1235 request.associations.add(association);
1236 }
1237
1238 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1239 if (status != HalCallback.STATUS_OK) {
1240 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1241 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1242 + resp);
1243 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1244 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1245 result.complete(UserIdentificationAssociationResponse.forFailure());
1246 return;
1247 }
1248 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1249 resp.errorMessage);
1250 result.complete(
1251 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1252 return;
1253 }
1254 int respSize = resp.associations.size();
1255 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1256 resp.errorMessage);
1257
1258 int[] responseTypes = new int[respSize];
1259 for (int i = 0; i < respSize; i++) {
1260 responseTypes[i] = resp.associations.get(i).value;
1261 }
1262 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1263 .forSuccess(responseTypes, resp.errorMessage);
1264 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1265 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1266 + ", converted=" + response);
1267 }
1268 result.complete(response);
1269 });
felipeal5e3ede42020-04-23 18:04:07 -07001270 }
1271
1272 /**
1273 * Gets the User HAL flags for the given user.
1274 *
1275 * @throws IllegalArgumentException if the user does not exist.
1276 */
1277 private int getHalUserInfoFlags(@UserIdInt int userId) {
1278 UserInfo user = mUserManager.getUserInfo(userId);
1279 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1280 return UserHalHelper.convertFlags(user);
1281 }
1282
Mayank Garg0e239142020-04-14 19:16:31 -07001283 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1284 @Nullable Bundle resultData) {
1285 try {
1286 receiver.send(resultCode, resultData);
1287 } catch (RemoteException e) {
1288 // ignore
1289 Log.w(TAG_USER, "error while sending results", e);
1290 }
1291 }
1292
felipealdfdf8512020-06-01 09:35:45 -07001293 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001294 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001295 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001296 }
1297
felipealdfdf8512020-06-01 09:35:45 -07001298 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001299 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1300 receiver.complete(new UserSwitchResult(status, errorMessage));
1301 }
1302
felipealdfdf8512020-06-01 09:35:45 -07001303 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1304 @UserCreationResult.Status int status) {
1305 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1306 }
1307
1308 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1309 @UserCreationResult.Status int status, @NonNull UserInfo user,
1310 @Nullable String errorMessage) {
1311 if (TextUtils.isEmpty(errorMessage)) {
1312 errorMessage = null;
1313 }
1314 receiver.complete(new UserCreationResult(status, user, errorMessage));
1315 }
1316
Mayank Garg6307fe42020-04-15 23:09:03 -07001317 /**
1318 * Calls activity manager for user switch.
1319 *
1320 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1321 *
1322 * @param requestId for the user switch request
1323 * @param targetUserId of the target user
1324 *
1325 * @hide
1326 */
1327 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1328 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1329 targetUserId);
1330 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1331
1332 try {
1333 boolean result = mAm.switchUser(targetUserId);
1334 if (result) {
1335 updateUserSwitchInProcess(requestId, targetUserId);
1336 } else {
1337 postSwitchHalResponse(requestId, targetUserId);
1338 }
1339 } catch (RemoteException e) {
1340 // ignore
1341 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1342 }
1343 }
1344
1345 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1346 synchronized (mLockUser) {
1347 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1348 // Some other user switch is in process.
1349 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1350 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1351 + " is in process. Abandoning it as a new user switch is requested"
1352 + " for the target user: " + targetUserId);
1353 }
1354 }
1355 mUserIdForUserSwitchInProcess = targetUserId;
1356 mRequestIdForUserSwitchInProcess = requestId;
1357 }
1358 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001359
Mayank Garg7a114c82020-04-08 21:25:06 -07001360 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001361 if (!isUserHalSupported()) return;
1362
felipealdfdf8512020-06-01 09:35:45 -07001363 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001364 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1365 targetUserId, usersInfo.currentUser.userId);
1366 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1367 request.requestId = requestId;
1368 mHal.postSwitchResponse(request);
1369 }
1370
1371 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1372 @NonNull UsersInfo usersInfo) {
1373 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001374 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1375 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1376 halTargetUser.userId = targetUser.id;
1377 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001378 SwitchUserRequest request = new SwitchUserRequest();
1379 request.targetUser = halTargetUser;
1380 request.usersInfo = usersInfo;
1381 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001382 }
1383
Mayank Garg59f22192020-03-27 00:51:45 -07001384 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001385 * Checks if the User HAL is supported.
1386 */
1387 public boolean isUserHalSupported() {
1388 return mHal.isSupported();
1389 }
1390
Mayank Garg587f1942020-05-06 01:41:34 -07001391 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001392 * Checks if the User HAL user association is supported.
1393 */
1394 @Override
1395 public boolean isUserHalUserAssociationSupported() {
1396 return mHal.isUserAssociationSupported();
1397 }
1398
1399 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001400 * Sets a callback which is invoked before user switch.
1401 *
1402 * <p>
1403 * This method should only be called by the Car System UI. The purpose of this call is to notify
1404 * Car System UI to show the user switch UI before the user switch.
1405 */
1406 @Override
1407 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001408 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001409
1410 // Confirm that caller is system UI.
1411 String systemUiPackageName = getSystemUiPackageName();
1412 if (systemUiPackageName == null) {
1413 throw new IllegalStateException("System UI package not found.");
1414 }
1415
1416 try {
1417 int systemUiUid = mContext
1418 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1419 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1420 int callerUid = Binder.getCallingUid();
1421 if (systemUiUid != callerUid) {
1422 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1423 + " is allowed to make this call");
1424 }
1425 } catch (NameNotFoundException e) {
1426 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1427 }
1428
Mayank Garg587f1942020-05-06 01:41:34 -07001429 mUserSwitchUiReceiver = receiver;
1430 }
1431
Mayank Garga480dd92020-05-14 03:14:57 -07001432 // TODO(157082995): This information can be taken from
1433 // PackageManageInternalImpl.getSystemUiServiceComponent
1434 @Nullable
1435 private String getSystemUiPackageName() {
1436 try {
1437 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1438 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1439 return componentName.getPackageName();
1440 } catch (RuntimeException e) {
1441 Log.w(TAG_USER, "error while getting system UI package name.", e);
1442 return null;
1443 }
1444 }
1445
Keun young Park13a7a822019-04-04 15:53:08 -07001446 private void updateDefaultUserRestriction() {
1447 // We want to set restrictions on system and guest users only once. These are persisted
1448 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1449 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001450 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1451 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001452 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001453 // Only apply the system user restrictions if the system user is headless.
1454 if (UserManager.isHeadlessSystemUserMode()) {
1455 setSystemUserRestrictions();
1456 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001457 Settings.Global.putInt(mContext.getContentResolver(),
1458 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001459 }
1460
Eric Jeong1545f3b2019-09-16 13:56:52 -07001461 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001462 return !mUserManager.getUserInfo(userId).isEphemeral();
1463 }
1464
Antonio Kantekc8114752020-03-05 21:37:39 -08001465 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001466 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1467 */
1468 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1469 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001470 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001471 }
1472
1473 /**
1474 * Removes previously added {@link UserLifecycleListener}.
1475 */
1476 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1477 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001478 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001479 }
1480
Eric Jeongc91f9452019-08-30 15:04:21 -07001481 /** Adds callback to listen to passenger activity events. */
1482 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001483 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001484 mPassengerCallbacks.add(callback);
1485 }
1486
1487 /** Removes previously added callback to listen passenger events. */
1488 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001489 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001490 mPassengerCallbacks.remove(callback);
1491 }
1492
1493 /** Sets the implementation of ZoneUserBindingHelper. */
1494 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1495 synchronized (mLockHelper) {
1496 mZoneUserBindingHelper = helper;
1497 }
1498 }
1499
felipeal98900c82020-04-09 09:05:02 -07001500 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001501 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001502 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001503 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001504 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001505 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1506 updateDefaultUserRestriction();
1507 tasks = new ArrayList<>(mUser0UnlockTasks);
1508 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001509 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001510 }
1511 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001512 Integer user = userId;
1513 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001514 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001515 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001516 mBackgroundUsersToRestart.remove(user);
1517 mBackgroundUsersToRestart.add(0, user);
1518 }
1519 // -1 for user 0
1520 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001521 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001522 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001523 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001524 + ", dropping least recently user from restart list:" + userToDrop);
1525 // Drop the least recently used user.
1526 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1527 }
1528 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001529 }
1530 }
1531 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001532 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001533 for (Runnable r : tasks) {
1534 r.run();
1535 }
1536 }
1537 }
1538
1539 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001540 * Starts all background users that were active in system.
1541 *
Keun young Parkfb656372019-03-12 18:37:55 -07001542 * @return list of background users started successfully.
1543 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001544 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001545 public ArrayList<Integer> startAllBackgroundUsers() {
1546 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001547 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001548 users = new ArrayList<>(mBackgroundUsersToRestart);
1549 mBackgroundUsersRestartedHere.clear();
1550 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001551 }
1552 ArrayList<Integer> startedUsers = new ArrayList<>();
1553 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001554 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001555 continue;
1556 }
1557 try {
1558 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001559 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1560 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001561 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001562 } else if (mAm.unlockUser(user, null, null, null)) {
1563 startedUsers.add(user);
1564 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001565 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001566 if (mUserManager.isUserRunning(user)) {
1567 // add to started list so that it can be stopped later.
1568 startedUsers.add(user);
1569 }
Keun young Parkfb656372019-03-12 18:37:55 -07001570 }
1571 }
1572 } catch (RemoteException e) {
1573 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001574 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001575 }
1576 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001577 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001578 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001579 ArrayList<Integer> usersToRemove = new ArrayList<>();
1580 for (Integer user : mBackgroundUsersToRestart) {
1581 if (!startedUsers.contains(user)) {
1582 usersToRemove.add(user);
1583 }
1584 }
1585 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1586 }
Keun young Parkfb656372019-03-12 18:37:55 -07001587 return startedUsers;
1588 }
1589
1590 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001591 * Stops all background users that were active in system.
1592 *
1593 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001594 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001595 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001596 if (userId == UserHandle.USER_SYSTEM) {
1597 return false;
1598 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001599 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001600 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001601 return false;
1602 }
1603 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001604 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001605 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001606 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001607 Integer user = userId;
1608 mBackgroundUsersRestartedHere.remove(user);
1609 }
1610 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1611 return false;
1612 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001613 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001614 return false;
1615 }
1616 } catch (RemoteException e) {
1617 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001618 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001619 }
1620 return true;
1621 }
1622
1623 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001624 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001625 */
felipeale8c5dce2020-04-15 11:27:06 -07001626 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1627 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1628 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001629
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001630 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001631 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001632 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001633 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1634 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001635 }
1636
felipeale8c5dce2020-04-15 11:27:06 -07001637 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001638 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001639
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001640 mHandler.post(() -> {
1641 handleNotifyServiceUserLifecycleListeners(event);
1642 handleNotifyAppUserLifecycleListeners(event);
1643 });
felipeale8c5dce2020-04-15 11:27:06 -07001644
Keun young Park1fced442020-05-29 09:26:29 -07001645 if (timestampMs != 0) {
1646 // Finally, update metrics.
1647 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1648 }
felipeale8c5dce2020-04-15 11:27:06 -07001649 }
1650
Mayank Garg7a114c82020-04-08 21:25:06 -07001651 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001652 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001653 || mUserIdForUserSwitchInProcess != userId
1654 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001655 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1656 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1657 }
1658 return;
1659 }
felipealf7368962020-04-16 12:55:19 -07001660 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1661 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001662 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001663 }
1664
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001665 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1666 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001667 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001668 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1669 Log.d(TAG_USER, "No app listener to be notified of " + event);
1670 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001671 return;
1672 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001673 // Must use a different TimingsTraceLog because it's another thread
1674 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1675 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1676 }
felipeal2a84d512020-04-06 18:52:15 -07001677 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001678 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001679 int eventType = event.getEventType();
1680 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001681 for (int i = 0; i < listenersSize; i++) {
1682 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001683
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001684 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1685 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001686 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001687
felipealde1e16d2020-06-03 13:20:48 -07001688 int fromUserId = event.getPreviousUserId();
1689 if (fromUserId != UserHandle.USER_NULL) {
1690 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001691 }
1692
felipeal2a84d512020-04-06 18:52:15 -07001693 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001694 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001695 }
felipealde1e16d2020-06-03 13:20:48 -07001696 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1697 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001698 try {
felipealde1e16d2020-06-03 13:20:48 -07001699 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001700 listener.send(userId, data);
1701 } catch (RemoteException e) {
1702 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1703 } finally {
1704 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001705 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001706 }
1707 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001708 }
1709
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001710 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001711 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1712 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001713 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001714 return;
felipeal2a84d512020-04-06 18:52:15 -07001715 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1716 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1717 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001718 }
felipeal2a84d512020-04-06 18:52:15 -07001719
felipealde1e16d2020-06-03 13:20:48 -07001720 int userId = event.getUserId();
1721 int eventType = event.getEventType();
1722 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001723 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001724 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001725 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1726 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001727 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001728 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001729 listener.onEvent(event);
1730 } catch (RuntimeException e) {
1731 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001732 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001733 } finally {
1734 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001735 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001736 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001737 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001738 }
1739
Mayank Garge5de0f92020-04-23 21:38:38 -07001740 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001741 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001742 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001743 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001744
Mayank Garge5de0f92020-04-23 21:38:38 -07001745 // Switch HAL users if user switch is not requested by CarUserService
1746 notifyHalLegacySwitch(fromUserId, toUserId);
1747
felipealbf327652020-06-03 11:33:29 -07001748 mCarUserManagerHelper.setLastActiveUser(toUserId);
1749
Eric Jeongc91f9452019-08-30 15:04:21 -07001750 if (mLastPassengerId != UserHandle.USER_NULL) {
1751 stopPassengerInternal(mLastPassengerId, false);
1752 }
1753 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1754 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001755 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001756 }
felipeal98900c82020-04-09 09:05:02 -07001757 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001758 }
1759
Mayank Garge5de0f92020-04-23 21:38:38 -07001760 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1761 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001762 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1763 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1764 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1765 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1766 }
1767 return;
1768 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001769 }
1770
Mayank Garg9ed099e2020-06-04 16:05:20 -07001771 if (!isUserHalSupported()) return;
1772
Mayank Garge5de0f92020-04-23 21:38:38 -07001773 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001774 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001775 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1776 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001777 }
1778
Pavel Maltsev17e81832019-04-04 14:38:41 -07001779 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001780 * 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 -08001781 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001782 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001783 * @param r Runnable to run.
1784 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001785 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001786 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001787 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001788 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001789 if (mUser0Unlocked) {
1790 runNow = true;
1791 } else {
1792 mUser0UnlockTasks.add(r);
1793 }
1794 }
1795 if (runNow) {
1796 r.run();
1797 }
1798 }
1799
Keun young Parkf3523cd2019-04-08 10:09:17 -07001800 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001801 @NonNull
1802 ArrayList<Integer> getBackgroundUsersToRestart() {
1803 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001804 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001805 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1806 }
1807 return backgroundUsersToRestart;
1808 }
1809
Ying Zheng1ab32b62018-06-26 12:47:26 -07001810 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001811 // Disable Location service for system user.
1812 LocationManager locationManager =
1813 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001814 locationManager.setLocationEnabledForUser(
1815 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001816 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001817
1818 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001819 * Assigns a default icon to a user according to the user's id.
1820 *
1821 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001822 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001823 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001824 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1825 Bitmap bitmap = UserIcons.convertToBitmap(
1826 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1827 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001828 }
1829
Eric Jeong1545f3b2019-09-16 13:56:52 -07001830 private interface UserFilter {
1831 boolean isEligibleUser(UserInfo user);
1832 }
1833
1834 /** Returns all users who are matched by the given filter. */
1835 private List<UserInfo> getUsers(UserFilter filter) {
1836 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1837
1838 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1839 UserInfo user = iterator.next();
1840 if (!filter.isEligibleUser(user)) {
1841 iterator.remove();
1842 }
1843 }
1844 return users;
1845 }
1846
1847 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001848 * Enforces that apps which have the
1849 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1850 * can make certain calls to the CarUserManager.
1851 *
1852 * @param message used as message if SecurityException is thrown.
1853 * @throws SecurityException if the caller is not system or root.
1854 */
1855 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001856 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1857 }
1858
felipealdfdf8512020-06-01 09:35:45 -07001859 private static void checkManageOrCreateUsersPermission(String message) {
1860 checkAtLeastOnePermission(message,
1861 android.Manifest.permission.MANAGE_USERS,
1862 android.Manifest.permission.CREATE_USERS);
1863 }
1864
felipeal2d0483c2019-11-02 14:07:22 -07001865 private static void checkManageUsersOrDumpPermission(String message) {
1866 checkAtLeastOnePermission(message,
1867 android.Manifest.permission.MANAGE_USERS,
1868 android.Manifest.permission.DUMP);
1869 }
1870
Felipe Leme5528ff72020-02-10 19:05:14 -08001871 private void checkInteractAcrossUsersPermission(String message) {
1872 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1873 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1874 }
1875
felipeal2d0483c2019-11-02 14:07:22 -07001876 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001877 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001878 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1879 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001880 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001881 }
1882 }
1883
felipeal2d0483c2019-11-02 14:07:22 -07001884 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1885 for (String permission : permissions) {
1886 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1887 /* exported = */ true)
1888 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1889 return true;
1890 }
1891 }
1892 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001893 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001894
1895 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1896 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1897 // Count all users that are managed profiles of the given user.
1898 int managedProfilesCount = 0;
1899 for (UserInfo user : users) {
1900 if (user.isManagedProfile() && user.profileGroupId == userId) {
1901 managedProfilesCount++;
1902 }
1903 }
1904 return managedProfilesCount;
1905 }
1906
1907 /**
1908 * Starts the first passenger of the given driver and assigns the passenger to the front
1909 * passenger zone.
1910 *
1911 * @param driverId User id of the driver.
1912 * @return whether it succeeds.
1913 */
1914 private boolean startFirstPassenger(@UserIdInt int driverId) {
1915 int zoneId = getAvailablePassengerZone();
1916 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1917 Log.w(TAG_USER, "passenger occupant zone is not found");
1918 return false;
1919 }
1920 List<UserInfo> passengers = getPassengers(driverId);
1921 if (passengers.size() < 1) {
1922 Log.w(TAG_USER, "passenger is not found");
1923 return false;
1924 }
1925 // Only one passenger is supported. If there are two or more passengers, the first passenger
1926 // is chosen.
1927 int passengerId = passengers.get(0).id;
1928 if (!startPassenger(passengerId, zoneId)) {
1929 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1930 return false;
1931 }
1932 return true;
1933 }
1934
1935 private int getAvailablePassengerZone() {
1936 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1937 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1938 for (int occupantType : occupantTypes) {
1939 int zoneId = getZoneId(occupantType);
1940 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1941 return zoneId;
1942 }
1943 }
1944 return OccupantZoneInfo.INVALID_ZONE_ID;
1945 }
1946
1947 /**
1948 * Creates a new passenger user when there is no passenger user.
1949 */
1950 private void setupPassengerUser() {
1951 int currentUser = ActivityManager.getCurrentUser();
1952 int profileCount = getNumberOfManagedProfiles(currentUser);
1953 if (profileCount > 0) {
1954 Log.w(TAG_USER, "max profile of user" + currentUser
1955 + " is exceeded: current profile count is " + profileCount);
1956 return;
1957 }
1958 // TODO(b/140311342): Use resource string for the default passenger name.
1959 UserInfo passenger = createPassenger("Passenger", currentUser);
1960 if (passenger == null) {
1961 // Couldn't create user, most likely because there are too many.
1962 Log.w(TAG_USER, "cannot create a passenger user");
1963 return;
1964 }
1965 }
1966
1967 @NonNull
1968 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1969 ZoneUserBindingHelper helper = null;
1970 synchronized (mLockHelper) {
1971 if (mZoneUserBindingHelper == null) {
1972 Log.w(TAG_USER, "implementation is not delegated");
1973 return new ArrayList<OccupantZoneInfo>();
1974 }
1975 helper = mZoneUserBindingHelper;
1976 }
1977 return helper.getOccupantZones(occupantType);
1978 }
1979
1980 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1981 ZoneUserBindingHelper helper = null;
1982 synchronized (mLockHelper) {
1983 if (mZoneUserBindingHelper == null) {
1984 Log.w(TAG_USER, "implementation is not delegated");
1985 return false;
1986 }
1987 helper = mZoneUserBindingHelper;
1988 }
1989 return helper.assignUserToOccupantZone(userId, zoneId);
1990 }
1991
1992 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1993 ZoneUserBindingHelper helper = null;
1994 synchronized (mLockHelper) {
1995 if (mZoneUserBindingHelper == null) {
1996 Log.w(TAG_USER, "implementation is not delegated");
1997 return false;
1998 }
1999 helper = mZoneUserBindingHelper;
2000 }
2001 return helper.unassignUserFromOccupantZone(userId);
2002 }
2003
2004 private boolean isPassengerDisplayAvailable() {
2005 ZoneUserBindingHelper helper = null;
2006 synchronized (mLockHelper) {
2007 if (mZoneUserBindingHelper == null) {
2008 Log.w(TAG_USER, "implementation is not delegated");
2009 return false;
2010 }
2011 helper = mZoneUserBindingHelper;
2012 }
2013 return helper.isPassengerDisplayAvailable();
2014 }
2015
2016 /**
2017 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
2018 * zone is returned.
2019 *
2020 * @param occupantType The type of an occupant.
2021 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
2022 * if not found.
2023 */
2024 private int getZoneId(@OccupantTypeEnum int occupantType) {
2025 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
2026 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
2027 }
Mayank Garg9732d602020-08-09 21:02:40 -07002028
2029 /**
2030 * Manages the required number of pre-created users.
2031 */
2032 public void preCreateUsers() {
2033 mUserPreCreator.managePreCreatedUsers();
2034 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002035}