blob: 8c2634c399382c3b146134f34c34a90a235ddca5 [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.user;
18
Eric Jeong1545f3b2019-09-16 13:56:52 -070019import static com.android.car.CarLog.TAG_USER;
20
21import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070022import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070024import android.app.ActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070025import android.app.ActivityManager.StackInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070026import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070027import android.car.CarOccupantZoneManager;
28import android.car.CarOccupantZoneManager.OccupantTypeEnum;
29import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070030import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070031import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080032import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080033import android.car.user.CarUserManager.UserLifecycleEvent;
felipeale8c5dce2020-04-15 11:27:06 -070034import android.car.user.CarUserManager.UserLifecycleEventType;
Antonio Kantekc8114752020-03-05 21:37:39 -080035import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070036import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070037import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070038import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070039import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070040import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070041import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070042import android.car.userlib.HalCallback;
Mayank Garg70732a82020-08-05 20:17:47 -070043import android.car.userlib.InitialUserSetter;
44import android.car.userlib.InitialUserSetter.InitialUserInfo;
felipeal19e3d732020-03-18 12:07:32 -070045import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070046import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070047import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070048import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070049import android.content.pm.PackageManager;
50import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070051import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070052import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070053import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070054import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070055import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
56import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070057import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemee3cab982020-03-12 11:39:29 -070058import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080059import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070060import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070061import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070062import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070063import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
64import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070065import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
66import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080067import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070068import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070069import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080070import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070071import android.os.Handler;
72import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070073import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080074import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070075import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070076import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070077import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070078import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070079import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070080import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080082import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080083import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070084
85import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070086import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070087import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080088import com.android.car.hal.UserHalService;
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;
felipeal312416a2020-04-14 12:28:24 -070091import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070092import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080093import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070094import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070095import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070096import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070097import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070098
99import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -0800100import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -0700101import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700102import java.util.Iterator;
103import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000104import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700105import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700106import java.util.concurrent.CountDownLatch;
107import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700108
109/**
110 * User service for cars. Manages users at boot time. Including:
111 *
112 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700113 * <li> Creates a user used as driver.
114 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700115 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700116 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700117 * <ol/>
118 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700119public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800120
felipealf7368962020-04-16 12:55:19 -0700121 private static final String TAG = TAG_USER;
122
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800123 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700124 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800125 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700126 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800127 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700128 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
felipeala68ecef2020-05-19 12:46:08 -0700129 /**
130 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
131 */
132 public static final String BUNDLE_USER_LOCALES =
133 CarUserServiceConstants.BUNDLE_USER_LOCALES;
134 /**
135 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
136 */
felipeal1a9410d2020-05-06 13:30:05 -0700137 public static final String BUNDLE_INITIAL_INFO_ACTION =
138 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800139
Mayank Garg9ed099e2020-06-04 16:05:20 -0700140 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
141
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700142 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700143 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700144 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700145 private final UserManager mUserManager;
146 private final int mMaxRunningUsers;
Mayank Garg70732a82020-08-05 20:17:47 -0700147 private final InitialUserSetter mInitialUserSetter;
Eric Jeongc91f9452019-08-30 15:04:21 -0700148 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700149
Eric Jeongc91f9452019-08-30 15:04:21 -0700150 private final Object mLockUser = new Object();
151 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800152 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700153 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800154 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700155 // Only one passenger is supported.
156 @GuardedBy("mLockUser")
157 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700158 /**
159 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800160 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700161 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700162 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700163 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
164 /**
165 * Keep the list of background users started here. This is wholly for debugging purpose.
166 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700168 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
169
Felipe Leme58412202020-01-09 13:45:33 -0800170 private final UserHalService mHal;
171
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700172 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700173 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
174 getClass().getSimpleName());
175 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700176
Felipe Leme5528ff72020-02-10 19:05:14 -0800177 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800178 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700179 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800180 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700181 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800182
183 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800184 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700185 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800186 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700187 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800188
Mayank Garg7a114c82020-04-08 21:25:06 -0700189 /**
190 * User Id for the user switch in process, if any.
191 */
192 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700193 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700194 /**
195 * Request Id for the user switch in process, if any.
196 */
197 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700198 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700199 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
200
Eric Jeongc91f9452019-08-30 15:04:21 -0700201 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
202 new CopyOnWriteArrayList<>();
203
felipeal61ce3732020-04-03 11:01:00 -0700204 @Nullable
205 @GuardedBy("mLockUser")
206 private UserInfo mInitialUser;
207
Mayank Garg71661ea2020-04-29 01:25:03 -0700208 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700209
Mayank Garg587f1942020-05-06 01:41:34 -0700210 private IResultReceiver mUserSwitchUiReceiver;
211
Eric Jeongc91f9452019-08-30 15:04:21 -0700212 /** Interface for callbaks related to passenger activities. */
213 public interface PassengerCallback {
214 /** Called when passenger is started at a certain zone. */
215 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
216 /** Called when passenger is stopped. */
217 void onPassengerStopped(@UserIdInt int passengerId);
218 }
219
220 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
221 public interface ZoneUserBindingHelper {
222 /** Gets occupant zones corresponding to the occupant type. */
223 @NonNull
224 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
225 /** Assigns the user to the occupant zone. */
226 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
227 /** Makes the occupant zone unoccupied. */
228 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
229 /** Returns whether there is a passenger display. */
230 boolean isPassengerDisplayAvailable();
231 }
232
233 private final Object mLockHelper = new Object();
234 @GuardedBy("mLockHelper")
235 private ZoneUserBindingHelper mZoneUserBindingHelper;
236
Felipe Leme58412202020-01-09 13:45:33 -0800237 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700238 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
239 @NonNull IActivityManager am, int maxRunningUsers) {
240 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
Mayank Garg70732a82020-08-05 20:17:47 -0700241 new UserMetrics(), /* initialUserSetter= */ null);
Mayank Garg71661ea2020-04-29 01:25:03 -0700242 }
243
244 @VisibleForTesting
245 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
246 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
Mayank Garg70732a82020-08-05 20:17:47 -0700247 @NonNull IActivityManager am, int maxRunningUsers, @NonNull UserMetrics userMetrics,
248 @Nullable InitialUserSetter initialUserSetter) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700249 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
250 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700251 }
252 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800253 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700254 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700255 mAm = am;
256 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700257 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700258 mLastPassengerId = UserHandle.USER_NULL;
259 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700260 mUserMetrics = userMetrics;
Mayank Garg70732a82020-08-05 20:17:47 -0700261 if (initialUserSetter == null) {
262 mInitialUserSetter = new InitialUserSetter(context, (u) -> setInitialUser(u));
263 } else {
264 mInitialUserSetter = initialUserSetter;
265 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700266 }
267
268 @Override
269 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700270 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
271 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700272 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700273 }
274
275 @Override
276 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700277 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
278 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700279 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700280 }
281
282 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700283 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700284 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700285 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800286 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700287 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700288 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700289 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700290 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700291 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
292 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700293 }
294 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
295 List<UserInfo> allDrivers = getAllDrivers();
296 int driversSize = allDrivers.size();
297 writer.println("NumberOfDrivers: " + driversSize);
298 for (int i = 0; i < driversSize; i++) {
299 int driverId = allDrivers.get(i).id;
300 writer.print(indent + "#" + i + ": id=" + driverId);
301 List<UserInfo> passengers = getPassengers(driverId);
302 int passengersSize = passengers.size();
303 writer.print(" NumberPassengers: " + passengersSize);
304 if (passengersSize > 0) {
305 writer.print(" [");
306 for (int j = 0; j < passengersSize; j++) {
307 writer.print(passengers.get(j).id);
308 if (j < passengersSize - 1) {
309 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700310 }
felipeal2d0483c2019-11-02 14:07:22 -0700311 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700312 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700313 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700314 writer.println();
315 }
316 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
317 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
318 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700319
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700320 writer.println("Relevant overlayable properties");
321 Resources res = mContext.getResources();
322 writer.printf("%sowner_name=%s\n", indent,
323 res.getString(com.android.internal.R.string.owner_name));
324 writer.printf("%sdefault_guest_name=%s\n", indent,
325 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700326 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700327 writer.printf("Request Id for the user switch in process=%d\n ",
328 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700329 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700330
felipealbf327652020-06-03 11:33:29 -0700331 writer.println("Relevant Global settings");
332 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
333 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
334
felipeale8c5dce2020-04-15 11:27:06 -0700335 dumpUserMetrics(writer);
336 }
337
felipealbf327652020-06-03 11:33:29 -0700338 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
339 String value = Settings.Global.getString(mContext.getContentResolver(), property);
340 writer.printf("%s%s=%s\n", indent, property, value);
341 }
342
felipeale8c5dce2020-04-15 11:27:06 -0700343 /**
344 * Dumps user metrics.
345 */
346 public void dumpUserMetrics(@NonNull PrintWriter writer) {
347 mUserMetrics.dump(writer);
348 }
349
350 /**
351 * Dumps first user unlocking time.
352 */
353 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
354 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700355 }
356
357 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
358 CountDownLatch latch = new CountDownLatch(1);
359 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700360 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700361 handleDumpAppLifecycleListeners(writer, indent);
362 latch.countDown();
363 });
364 int timeout = 5;
365 try {
366 if (!latch.await(timeout, TimeUnit.SECONDS)) {
367 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
368 timeout);
369 }
370 } catch (InterruptedException e) {
371 Thread.currentThread().interrupt();
372 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
373 }
374 }
375
felipealde1e16d2020-06-03 13:20:48 -0700376 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700377 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700378 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700379 return;
380 }
felipealde1e16d2020-06-03 13:20:48 -0700381 int size = mUserLifecycleListeners.size();
382 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
383 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700384 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700385 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700386 }
387 }
388
389 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700390 int size = mAppLifecycleListeners.size();
391 if (size == 0) {
392 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700393 return;
394 }
felipealde1e16d2020-06-03 13:20:48 -0700395 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
396 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700397 int uid = mAppLifecycleListeners.keyAt(i);
398 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700399 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800400 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700401 }
402
403 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700404 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700405 */
406 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700407 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700408 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000409 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700410
411 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
412 @Override
413 protected void onCompleted(UserCreationResult result, Throwable err) {
414 if (result == null) {
415 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
416 } else {
417 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
418 assignDefaultIcon(result.getUser());
419 }
420 }
421 super.onCompleted(result, err);
422 };
423 };
424 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700425 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700426 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
427 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
428 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
429 return future;
430 }
431 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700432 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700433 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
434 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700435 }
436
437 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700438 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700439 */
440 @Override
441 @Nullable
442 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
443 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000444 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700445 UserInfo driver = mUserManager.getUserInfo(driverId);
446 if (driver == null) {
447 Log.w(TAG_USER, "the driver is invalid");
448 return null;
449 }
450 if (driver.isGuest()) {
451 Log.w(TAG_USER, "a guest driver cannot create a passenger");
452 return null;
453 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700454 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700455 UserInfo user = mUserManager.createProfileForUser(name,
456 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700457 if (user == null) {
458 // Couldn't create user, most likely because there are too many.
459 Log.w(TAG_USER, "can't create a profile for user" + driverId);
460 return null;
461 }
462 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700463 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700464 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700465 return user;
466 }
467
468 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700469 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700470 */
471 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700472 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700473 checkManageUsersPermission("switchDriver");
Eric Jeong25666cf2020-05-14 15:16:27 -0700474 if (UserHelper.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700475 // System user doesn't associate with real person, can not be switched to.
476 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700477 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700478 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700479 }
480 int userSwitchable = mUserManager.getUserSwitchability();
481 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
482 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700483 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700484 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700485 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700486 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700487 }
488
489 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800490 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
491 *
492 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700493 */
494 @Override
495 @NonNull
496 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700497 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700498 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700499 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700500 }
501
502 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800503 * Returns all passengers under the given driver.
504 *
505 * @param driverId User id of a driver.
506 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700507 */
508 @Override
509 @NonNull
510 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700511 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700512 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700513 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
514 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700515 });
516 }
517
518 /**
519 * @see CarUserManager.startPassenger
520 */
521 @Override
522 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
523 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700524 synchronized (mLockUser) {
525 try {
526 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
527 Log.w(TAG_USER, "could not start passenger");
528 return false;
529 }
530 } catch (RemoteException e) {
531 // ignore
532 Log.w(TAG_USER, "error while starting passenger", e);
533 return false;
534 }
535 if (!assignUserToOccupantZone(passengerId, zoneId)) {
536 Log.w(TAG_USER, "could not assign passenger to zone");
537 return false;
538 }
539 mLastPassengerId = passengerId;
540 }
541 for (PassengerCallback callback : mPassengerCallbacks) {
542 callback.onPassengerStarted(passengerId, zoneId);
543 }
544 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700545 }
546
547 /**
548 * @see CarUserManager.stopPassenger
549 */
550 @Override
551 public boolean stopPassenger(@UserIdInt int passengerId) {
552 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700553 return stopPassengerInternal(passengerId, true);
554 }
555
556 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
557 synchronized (mLockUser) {
558 UserInfo passenger = mUserManager.getUserInfo(passengerId);
559 if (passenger == null) {
560 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
561 return false;
562 }
563 if (mLastPassengerId != passengerId) {
564 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
565 return true;
566 }
567 if (checkCurrentDriver) {
568 int currentUser = ActivityManager.getCurrentUser();
569 if (passenger.profileGroupId != currentUser) {
570 Log.w(TAG_USER, "passenger " + passengerId
571 + " is not a profile of the current user");
572 return false;
573 }
574 }
575 // Passenger is a profile, so cannot be stopped through activity manager.
576 // Instead, activities started by the passenger are stopped and the passenger is
577 // unassigned from the zone.
578 stopAllTasks(passengerId);
579 if (!unassignUserFromOccupantZone(passengerId)) {
580 Log.w(TAG_USER, "could not unassign user from occupant zone");
581 return false;
582 }
583 mLastPassengerId = UserHandle.USER_NULL;
584 }
585 for (PassengerCallback callback : mPassengerCallbacks) {
586 callback.onPassengerStopped(passengerId);
587 }
588 return true;
589 }
590
591 private void stopAllTasks(@UserIdInt int userId) {
592 try {
593 for (StackInfo info : mAm.getAllStackInfos()) {
594 for (int i = 0; i < info.taskIds.length; i++) {
595 if (info.taskUserIds[i] == userId) {
596 int taskId = info.taskIds[i];
597 if (!mAm.removeTask(taskId)) {
598 Log.w(TAG_USER, "could not remove task " + taskId);
599 }
600 }
601 }
602 }
603 } catch (RemoteException e) {
604 Log.e(TAG_USER, "could not get stack info", e);
605 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700606 }
607
Felipe Leme5528ff72020-02-10 19:05:14 -0800608 @Override
609 public void setLifecycleListenerForUid(IResultReceiver listener) {
610 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700611 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800612 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
613
614 try {
615 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
616 } catch (RemoteException e) {
617 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
618 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700619 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800620 }
621
622 private void onListenerDeath(int uid) {
623 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700624 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800625 }
626
627 @Override
628 public void resetLifecycleListenerForUid() {
629 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700630 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800631 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700632 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800633 }
634
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800635 @Override
636 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800637 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700638 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
639 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800640 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700641 checkManageUsersPermission("getInitialInfo");
Mayank Garg9ed099e2020-06-04 16:05:20 -0700642 if (!isUserHalSupported()) {
643 sendResult(receiver, HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
644 return;
645 }
felipealdfdf8512020-06-01 09:35:45 -0700646 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800647 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700648 Bundle resultData = null;
649 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700650 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
651 status, resp.action, resp.userToSwitchOrCreate.userId,
felipeala68ecef2020-05-19 12:46:08 -0700652 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
Mayank Garg0e239142020-04-14 19:16:31 -0700653 switch (resp.action) {
654 case InitialUserInfoResponseAction.SWITCH:
655 resultData = new Bundle();
656 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
657 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
658 break;
659 case InitialUserInfoResponseAction.CREATE:
660 resultData = new Bundle();
661 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
662 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
663 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
664 break;
665 case InitialUserInfoResponseAction.DEFAULT:
666 resultData = new Bundle();
667 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
668 break;
669 default:
670 // That's ok, it will be the same as DEFAULT...
671 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800672 }
felipeal312416a2020-04-14 12:28:24 -0700673 } else {
674 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800675 }
felipeala68ecef2020-05-19 12:46:08 -0700676 if (resultData != null && !TextUtils.isEmpty(resp.userLocales)) {
677 resultData.putString(BUNDLE_USER_LOCALES, resp.userLocales);
678 }
679
Mayank Garg0e239142020-04-14 19:16:31 -0700680 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800681 });
682 }
683
Felipe Lemee3cab982020-03-12 11:39:29 -0700684 /**
felipeal61ce3732020-04-03 11:01:00 -0700685 * Gets the initial foreground user after the device boots or resumes from suspension.
686 *
687 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
688 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
689 * method returns {@code null}.
690 *
691 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
692 * (like switching to the last active user), and this method will return the result of such
693 * operation.
694 *
695 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
696 * {@code null}.
697 *
698 * @hide
699 */
700 @Nullable
701 public UserInfo getInitialUser() {
702 checkInteractAcrossUsersPermission("getInitialUser");
703 synchronized (mLockUser) {
704 return mInitialUser;
705 }
706 }
707
felipeal61ce3732020-04-03 11:01:00 -0700708 /**
709 * Sets the initial foreground user after the device boots or resumes from suspension.
710 */
711 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700712 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
713 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700714 synchronized (mLockUser) {
715 mInitialUser = user;
716 }
717 if (user == null) {
718 // This mean InitialUserSetter failed and could not fallback, so the initial user was
719 // not switched (and most likely is SYSTEM_USER).
720 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
721 Log.wtf(TAG_USER, "Initial user set to null");
722 }
723 }
724
725 /**
Mayank Garg70732a82020-08-05 20:17:47 -0700726 * Call to start user at the android startup.
727 */
728 public void initBootUser() {
729 int requestType = getInitialUserInfoRequestType();
730 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
731 mHalTimeoutMs);
732 checkManageUsersPermission("startInitialUser");
733
734 if (!isUserHalSupported()) {
735 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null);
736 return;
737 }
738
739 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
740 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
741 if (resp != null) {
742 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
743 status, resp.action, resp.userToSwitchOrCreate.userId,
744 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
745
746 String userLocales = resp.userLocales;
747 InitialUserInfo info;
748 switch (resp.action) {
749 case InitialUserInfoResponseAction.SWITCH:
750 int userId = resp.userToSwitchOrCreate.userId;
751 if (userId <= 0) {
752 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
753 fallbackToDefaultInitialUserBehavior(userLocales);
754 break;
755 }
756 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
757 .setUserLocales(userLocales)
758 .setSwitchUserId(userId)
759 .build();
760 mInitialUserSetter.set(info);
761 break;
762
763 case InitialUserInfoResponseAction.CREATE:
764 int halFlags = resp.userToSwitchOrCreate.flags;
765 String userName = resp.userNameToCreate;
766 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
767 .setUserLocales(userLocales)
768 .setNewUserName(userName)
769 .setNewUserFlags(halFlags)
770 .build();
771 mInitialUserSetter.set(info);
772 break;
773
774 case InitialUserInfoResponseAction.DEFAULT:
775 fallbackToDefaultInitialUserBehavior(userLocales);
776 break;
777 default:
778 Log.w(TAG_USER, "invalid response action on " + resp);
779 fallbackToDefaultInitialUserBehavior(/* user locale */ null);
780 break;
781
782 }
783 } else {
784 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
785 fallbackToDefaultInitialUserBehavior(/* user locale */ null);
786 }
787 });
788 }
789
790 private void fallbackToDefaultInitialUserBehavior(String userLocales) {
791 InitialUserInfo info = new InitialUserSetter.Builder(
792 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
793 .setUserLocales(userLocales)
794 .build();
795 mInitialUserSetter.set(info);
796 }
797
798 @VisibleForTesting
799 int getInitialUserInfoRequestType() {
800 if (!mCarUserManagerHelper.hasInitialUser()) {
801 return InitialUserInfoRequestType.FIRST_BOOT;
802 }
803 if (mContext.getPackageManager().isDeviceUpgrading()) {
804 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
805 }
806 return InitialUserInfoRequestType.COLD_BOOT;
807 }
808
809 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700810 * Calls the User HAL to get the initial user info.
811 *
812 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
813 * @param callback callback to receive the results.
814 */
815 public void getInitialUserInfo(int requestType,
816 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700817 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
818 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700819 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700820 checkManageUsersPermission("getInitialUserInfo");
Mayank Garg9ed099e2020-06-04 16:05:20 -0700821 if (!isUserHalSupported()) {
822 callback.onResponse(HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
823 return;
824 }
felipealdfdf8512020-06-01 09:35:45 -0700825 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemee3cab982020-03-12 11:39:29 -0700826 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
827 }
828
829 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700830 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
831 *
832 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700833 * When everything works well, the workflow is:
834 * <ol>
835 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
836 * type, current user id, target user id, and a callback.
837 * <li> HAL called back with SUCCESS.
838 * <li> {@link IActivityManager} is called for Android user switch.
839 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
840 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
841 * request type, current user id, and target user id. In this case, the current and target
842 * user IDs would be same.
843 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700844 *
845 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700846 * Corner cases:
847 * <ul>
848 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700849 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700850 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
851 * {@code STATUS_HAL_INTERNAL_FAILURE}.
852 * <li> If HAL user switch call is successful, but android user switch call fails,
853 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
854 * target user id, but in this case the current and target user IDs would be different.
855 * <li> If another user switch request for the same target user is received while previous
856 * request is in process, receiver would receive
857 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
858 * <li> If a user switch request is received while another user switch request for different
859 * target user is in process, the previous request would be abandoned and new request will be
860 * processed. No POST_SWITCH would be sent for the previous request.
861 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700862 *
Mayank Garge19c2922020-03-30 18:05:53 -0700863 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700864 * @param timeoutMs - timeout for HAL to wait
865 * @param receiver - receiver for the results
866 */
Mayank Garge19c2922020-03-30 18:05:53 -0700867 @Override
868 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700869 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700870 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700871 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700872 Objects.requireNonNull(receiver);
873 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700874 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700875
felipealf7368962020-04-16 12:55:19 -0700876 int currentUser = ActivityManager.getCurrentUser();
877 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700878 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
879 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
880 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700881 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700882 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700883 return;
884 }
885
Mayank Garg9ed099e2020-06-04 16:05:20 -0700886 // If User Hal is not supported, just android user switch.
887 if (!isUserHalSupported()) {
888 try {
889 if (mAm.switchUser(targetUserId)) {
890 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
891 return;
892 }
893 } catch (RemoteException e) {
894 // ignore
895 Log.w(TAG_USER,
896 "error while switching user " + targetUser.toFullString(), e);
897 }
898 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
899 return;
900 }
901
Mayank Garg7a114c82020-04-08 21:25:06 -0700902 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700903 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
904 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
905 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
906 }
907
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700908 // If there is another request for the same target user, return another request in
909 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
910 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
911 // user switch request in process for different target user, but that request is now
912 // ignored.
felipealf7368962020-04-16 12:55:19 -0700913 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700914 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
915 Log.d(TAG_USER,
916 "Another user switch request in process for the requested target user: "
917 + targetUserId);
918 }
919
920 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700921 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700922 return;
923 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700924 else {
925 mUserIdForUserSwitchInProcess = targetUserId;
926 mRequestIdForUserSwitchInProcess = 0;
927 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700928 }
929
felipealdfdf8512020-06-01 09:35:45 -0700930 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700931 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
932
933 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700934 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
935 Log.d(TAG, "switch response: status="
936 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
937 }
938
felipeale5bf0322020-04-16 15:10:57 -0700939 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700940
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700941 synchronized (mLockUser) {
942 if (status != HalCallback.STATUS_OK) {
943 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
944 Log.w(TAG, "invalid callback status ("
945 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
946 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700947 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700948 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
949 return;
950 }
felipealf7368962020-04-16 12:55:19 -0700951
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700952 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
953 resp.errorMessage);
954
955 if (mUserIdForUserSwitchInProcess != targetUserId) {
956 // Another user switch request received while HAL responded. No need to process
957 // this request further
958 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
959 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
960 + "abondoned for : " + targetUserId + ". Current user in process: "
961 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700962 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700963 resultStatus =
964 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700965 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700966 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
967 return;
968 }
969
970 switch (resp.status) {
971 case SwitchUserStatus.SUCCESS:
972 boolean switched;
973 try {
974 switched = mAm.switchUser(targetUserId);
975 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700976 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700977 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
978 mRequestIdForUserSwitchInProcess = resp.requestId;
979 } else {
980 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
981 postSwitchHalResponse(resp.requestId, targetUserId);
982 }
983 } catch (RemoteException e) {
984 // ignore
985 Log.w(TAG_USER,
986 "error while switching user " + targetUser.toFullString(), e);
987 }
988 break;
989 case SwitchUserStatus.FAILURE:
990 // HAL failed to switch user
991 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
992 break;
felipealdfdf8512020-06-01 09:35:45 -0700993 default:
994 // Shouldn't happen because UserHalService validates the status
995 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700996 }
997
998 if (mRequestIdForUserSwitchInProcess == 0) {
999 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
1000 }
Mayank Garg59f22192020-03-27 00:51:45 -07001001 }
felipealdfdf8512020-06-01 09:35:45 -07001002 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -07001003 });
1004 }
1005
Mayank Garga55c3092020-05-28 03:19:24 -07001006 @Override
1007 public UserRemovalResult removeUser(@UserIdInt int userId) {
1008 checkManageUsersPermission("removeUser");
1009 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
1010 // If the requested user is the current user, return error.
1011 if (ActivityManager.getCurrentUser() == userId) {
1012 return logAndGetResults(userId,
1013 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
1014 }
1015
1016 // If requested user is the only admin user, return error.
1017 UserInfo userInfo = mUserManager.getUserInfo(userId);
1018 if (userInfo == null) {
1019 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
1020 }
1021
1022 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1023 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1024 halUser.userId = userInfo.id;
1025 halUser.flags = UserHalHelper.convertFlags(userInfo);
1026 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1027
1028 // Do not delete last admin user.
1029 if (UserHalHelper.isAdmin(halUser.flags)) {
1030 int size = usersInfo.existingUsers.size();
1031 int totalAdminUsers = 0;
1032 for (int i = 0; i < size; i++) {
1033 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
1034 totalAdminUsers++;
1035 }
1036 }
1037 if (totalAdminUsers == 1) {
1038 return logAndGetResults(userId,
1039 UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
1040 }
1041 }
1042
1043 // First remove user from android and then remove from HAL because HAL remove user is one
1044 // way call.
1045 if (!mUserManager.removeUser(userId)) {
1046 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1047 }
1048
Mayank Garg9ed099e2020-06-04 16:05:20 -07001049 if (isUserHalSupported()) {
1050 RemoveUserRequest request = new RemoveUserRequest();
1051 request.removedUserInfo = halUser;
Mayank Garg4adef862020-06-16 18:12:28 -07001052 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg9ed099e2020-06-04 16:05:20 -07001053 mHal.removeUser(request);
1054 }
1055
Mayank Garga55c3092020-05-28 03:19:24 -07001056 return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
1057 }
1058
1059 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1060 @UserRemovalResult.Status int result) {
1061 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1062 return new UserRemovalResult(result);
1063 }
1064
Mayank Garg587f1942020-05-06 01:41:34 -07001065 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1066 if (mUserSwitchUiReceiver == null) {
1067 Log.w(TAG_USER, "No User switch UI receiver.");
1068 return;
1069 }
1070
felipealdfdf8512020-06-01 09:35:45 -07001071 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001072 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001073 mUserSwitchUiReceiver.send(targetUserId, null);
1074 } catch (RemoteException e) {
1075 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1076 }
1077 }
1078
felipeal5e3ede42020-04-23 18:04:07 -07001079 @Override
felipealdfdf8512020-06-01 09:35:45 -07001080 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1081 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
1082 Objects.requireNonNull(userType, "user type cannot be null");
1083 Objects.requireNonNull(receiver, "receiver cannot be null");
1084 checkManageOrCreateUsersPermission("createUser");
1085 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
1086 userType, flags, timeoutMs);
1087
1088 UserInfo newUser;
1089 try {
1090 newUser = mUserManager.createUser(name, userType, flags);
1091 if (newUser == null) {
1092 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1093 + " and flags " + UserInfo.flagsToString(flags));
1094 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1095 return;
1096 }
1097 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1098 Log.d(TAG, "Created user: " + newUser.toFullString());
1099 }
1100 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
1101 UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
1102 } catch (RuntimeException e) {
1103 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1104 + UserInfo.flagsToString(flags), e);
1105 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1106 return;
1107 }
1108
Mayank Garg9ed099e2020-06-04 16:05:20 -07001109 if (!isUserHalSupported()) {
1110 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1111 return;
1112 }
1113
felipealdfdf8512020-06-01 09:35:45 -07001114 CreateUserRequest request = new CreateUserRequest();
1115 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1116 if (!TextUtils.isEmpty(name)) {
1117 request.newUserName = name;
1118 }
1119 request.newUserInfo.userId = newUser.id;
1120 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1121 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1122 Log.d(TAG, "Create user request: " + request);
1123 }
1124
1125 try {
1126 mHal.createUser(request, timeoutMs, (status, resp) -> {
1127 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1128 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1129 Log.d(TAG, "createUserResponse: status="
1130 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1131 }
1132 UserInfo user = null; // user returned in the result
1133 if (status != HalCallback.STATUS_OK) {
1134 Log.w(TAG, "invalid callback status ("
1135 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1136 + resp);
1137 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1138 resultStatus, resp.errorMessage);
1139 removeUser(newUser, "HAL call failed with "
1140 + UserHalHelper.halCallbackStatusToString(status));
1141 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1142 return;
1143 }
1144
1145 switch (resp.status) {
1146 case CreateUserStatus.SUCCESS:
1147 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1148 user = newUser;
1149 break;
1150 case CreateUserStatus.FAILURE:
1151 // HAL failed to switch user
1152 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1153 break;
1154 default:
1155 // Shouldn't happen because UserHalService validates the status
1156 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1157 }
1158 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1159 resultStatus, resp.errorMessage);
1160 if (user == null) {
1161 removeUser(newUser, "HAL returned "
1162 + UserCreationResult.statusToString(resultStatus));
1163 }
1164 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1165 });
1166 } catch (Exception e) {
1167 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1168 removeUser(newUser, "mHal.createUser() failed");
1169 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1170 }
1171 }
1172
1173 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1174 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1175 try {
1176 if (!mUserManager.removeUser(user.id)) {
1177 Log.w(TAG, "Failed to remove user " + user.toFullString());
1178 }
1179 } catch (Exception e) {
1180 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1181 }
1182 }
1183
1184 @Override
felipeal159a2a42020-05-08 10:32:11 -07001185 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001186 if (!isUserHalUserAssociationSupported()) {
1187 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1188 }
1189
felipeal5e3ede42020-04-23 18:04:07 -07001190 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1191 checkManageUsersPermission("getUserIdentificationAssociation");
1192
1193 int uid = getCallingUid();
1194 int userId = UserHandle.getUserId(uid);
1195 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1196
1197 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1198 request.userInfo.userId = userId;
1199 request.userInfo.flags = getHalUserInfoFlags(userId);
1200
1201 request.numberAssociationTypes = types.length;
1202 for (int i = 0; i < types.length; i++) {
1203 request.associationTypes.add(types[i]);
1204 }
1205
1206 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1207 if (halResponse == null) {
1208 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1209 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001210 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001211 }
1212
1213 int[] values = new int[halResponse.associations.size()];
1214 for (int i = 0; i < values.length; i++) {
1215 values[i] = halResponse.associations.get(i).value;
1216 }
1217 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1218
felipeal159a2a42020-05-08 10:32:11 -07001219 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1220 }
1221
1222 @Override
1223 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1224 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001225 if (!isUserHalUserAssociationSupported()) {
1226 result.complete(
1227 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1228 return;
1229 }
1230
felipeal159a2a42020-05-08 10:32:11 -07001231 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1232 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1233 if (types.length != values.length) {
1234 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1235 + Arrays.toString(values) + ") should have the same length");
1236 }
1237 checkManageUsersPermission("setUserIdentificationAssociation");
1238
1239 int uid = getCallingUid();
1240 int userId = UserHandle.getUserId(uid);
1241 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1242
1243 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1244 request.userInfo.userId = userId;
1245 request.userInfo.flags = getHalUserInfoFlags(userId);
1246
1247 request.numberAssociations = types.length;
1248 for (int i = 0; i < types.length; i++) {
1249 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1250 association.type = types[i];
1251 association.value = values[i];
1252 request.associations.add(association);
1253 }
1254
1255 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1256 if (status != HalCallback.STATUS_OK) {
1257 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1258 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1259 + resp);
1260 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1261 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1262 result.complete(UserIdentificationAssociationResponse.forFailure());
1263 return;
1264 }
1265 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1266 resp.errorMessage);
1267 result.complete(
1268 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1269 return;
1270 }
1271 int respSize = resp.associations.size();
1272 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1273 resp.errorMessage);
1274
1275 int[] responseTypes = new int[respSize];
1276 for (int i = 0; i < respSize; i++) {
1277 responseTypes[i] = resp.associations.get(i).value;
1278 }
1279 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1280 .forSuccess(responseTypes, resp.errorMessage);
1281 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1282 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1283 + ", converted=" + response);
1284 }
1285 result.complete(response);
1286 });
felipeal5e3ede42020-04-23 18:04:07 -07001287 }
1288
1289 /**
1290 * Gets the User HAL flags for the given user.
1291 *
1292 * @throws IllegalArgumentException if the user does not exist.
1293 */
1294 private int getHalUserInfoFlags(@UserIdInt int userId) {
1295 UserInfo user = mUserManager.getUserInfo(userId);
1296 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1297 return UserHalHelper.convertFlags(user);
1298 }
1299
Mayank Garg0e239142020-04-14 19:16:31 -07001300 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1301 @Nullable Bundle resultData) {
1302 try {
1303 receiver.send(resultCode, resultData);
1304 } catch (RemoteException e) {
1305 // ignore
1306 Log.w(TAG_USER, "error while sending results", e);
1307 }
1308 }
1309
felipealdfdf8512020-06-01 09:35:45 -07001310 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001311 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001312 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001313 }
1314
felipealdfdf8512020-06-01 09:35:45 -07001315 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001316 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1317 receiver.complete(new UserSwitchResult(status, errorMessage));
1318 }
1319
felipealdfdf8512020-06-01 09:35:45 -07001320 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1321 @UserCreationResult.Status int status) {
1322 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1323 }
1324
1325 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1326 @UserCreationResult.Status int status, @NonNull UserInfo user,
1327 @Nullable String errorMessage) {
1328 if (TextUtils.isEmpty(errorMessage)) {
1329 errorMessage = null;
1330 }
1331 receiver.complete(new UserCreationResult(status, user, errorMessage));
1332 }
1333
Mayank Garg6307fe42020-04-15 23:09:03 -07001334 /**
1335 * Calls activity manager for user switch.
1336 *
1337 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1338 *
1339 * @param requestId for the user switch request
1340 * @param targetUserId of the target user
1341 *
1342 * @hide
1343 */
1344 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1345 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1346 targetUserId);
1347 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1348
1349 try {
1350 boolean result = mAm.switchUser(targetUserId);
1351 if (result) {
1352 updateUserSwitchInProcess(requestId, targetUserId);
1353 } else {
1354 postSwitchHalResponse(requestId, targetUserId);
1355 }
1356 } catch (RemoteException e) {
1357 // ignore
1358 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1359 }
1360 }
1361
1362 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1363 synchronized (mLockUser) {
1364 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1365 // Some other user switch is in process.
1366 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1367 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1368 + " is in process. Abandoning it as a new user switch is requested"
1369 + " for the target user: " + targetUserId);
1370 }
1371 }
1372 mUserIdForUserSwitchInProcess = targetUserId;
1373 mRequestIdForUserSwitchInProcess = requestId;
1374 }
1375 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001376
Mayank Garg7a114c82020-04-08 21:25:06 -07001377 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001378 if (!isUserHalSupported()) return;
1379
felipealdfdf8512020-06-01 09:35:45 -07001380 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001381 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1382 targetUserId, usersInfo.currentUser.userId);
1383 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1384 request.requestId = requestId;
1385 mHal.postSwitchResponse(request);
1386 }
1387
1388 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1389 @NonNull UsersInfo usersInfo) {
1390 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001391 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1392 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1393 halTargetUser.userId = targetUser.id;
1394 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001395 SwitchUserRequest request = new SwitchUserRequest();
1396 request.targetUser = halTargetUser;
1397 request.usersInfo = usersInfo;
1398 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001399 }
1400
Mayank Garg59f22192020-03-27 00:51:45 -07001401 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001402 * Checks if the User HAL is supported.
1403 */
1404 public boolean isUserHalSupported() {
1405 return mHal.isSupported();
1406 }
1407
Mayank Garg587f1942020-05-06 01:41:34 -07001408 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001409 * Checks if the User HAL user association is supported.
1410 */
1411 @Override
1412 public boolean isUserHalUserAssociationSupported() {
1413 return mHal.isUserAssociationSupported();
1414 }
1415
1416 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001417 * Sets a callback which is invoked before user switch.
1418 *
1419 * <p>
1420 * This method should only be called by the Car System UI. The purpose of this call is to notify
1421 * Car System UI to show the user switch UI before the user switch.
1422 */
1423 @Override
1424 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001425 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001426
1427 // Confirm that caller is system UI.
1428 String systemUiPackageName = getSystemUiPackageName();
1429 if (systemUiPackageName == null) {
1430 throw new IllegalStateException("System UI package not found.");
1431 }
1432
1433 try {
1434 int systemUiUid = mContext
1435 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1436 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1437 int callerUid = Binder.getCallingUid();
1438 if (systemUiUid != callerUid) {
1439 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1440 + " is allowed to make this call");
1441 }
1442 } catch (NameNotFoundException e) {
1443 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1444 }
1445
Mayank Garg587f1942020-05-06 01:41:34 -07001446 mUserSwitchUiReceiver = receiver;
1447 }
1448
Mayank Garga480dd92020-05-14 03:14:57 -07001449 // TODO(157082995): This information can be taken from
1450 // PackageManageInternalImpl.getSystemUiServiceComponent
1451 @Nullable
1452 private String getSystemUiPackageName() {
1453 try {
1454 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1455 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1456 return componentName.getPackageName();
1457 } catch (RuntimeException e) {
1458 Log.w(TAG_USER, "error while getting system UI package name.", e);
1459 return null;
1460 }
1461 }
1462
Keun young Park13a7a822019-04-04 15:53:08 -07001463 private void updateDefaultUserRestriction() {
1464 // We want to set restrictions on system and guest users only once. These are persisted
1465 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1466 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001467 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1468 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001469 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001470 // Only apply the system user restrictions if the system user is headless.
1471 if (UserManager.isHeadlessSystemUserMode()) {
1472 setSystemUserRestrictions();
1473 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001474 Settings.Global.putInt(mContext.getContentResolver(),
1475 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001476 }
1477
Eric Jeong1545f3b2019-09-16 13:56:52 -07001478 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001479 return !mUserManager.getUserInfo(userId).isEphemeral();
1480 }
1481
Antonio Kantekc8114752020-03-05 21:37:39 -08001482 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001483 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1484 */
1485 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1486 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001487 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001488 }
1489
1490 /**
1491 * Removes previously added {@link UserLifecycleListener}.
1492 */
1493 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1494 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001495 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001496 }
1497
Eric Jeongc91f9452019-08-30 15:04:21 -07001498 /** Adds callback to listen to passenger activity events. */
1499 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001500 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001501 mPassengerCallbacks.add(callback);
1502 }
1503
1504 /** Removes previously added callback to listen passenger events. */
1505 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001506 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001507 mPassengerCallbacks.remove(callback);
1508 }
1509
1510 /** Sets the implementation of ZoneUserBindingHelper. */
1511 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1512 synchronized (mLockHelper) {
1513 mZoneUserBindingHelper = helper;
1514 }
1515 }
1516
felipeal98900c82020-04-09 09:05:02 -07001517 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001518 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001519 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001520 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001521 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001522 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1523 updateDefaultUserRestriction();
1524 tasks = new ArrayList<>(mUser0UnlockTasks);
1525 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001526 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001527 }
1528 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001529 Integer user = userId;
1530 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001531 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001532 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001533 mBackgroundUsersToRestart.remove(user);
1534 mBackgroundUsersToRestart.add(0, user);
1535 }
1536 // -1 for user 0
1537 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001538 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001539 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001540 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001541 + ", dropping least recently user from restart list:" + userToDrop);
1542 // Drop the least recently used user.
1543 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1544 }
1545 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001546 }
1547 }
1548 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001549 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001550 for (Runnable r : tasks) {
1551 r.run();
1552 }
1553 }
1554 }
1555
1556 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001557 * Starts all background users that were active in system.
1558 *
Keun young Parkfb656372019-03-12 18:37:55 -07001559 * @return list of background users started successfully.
1560 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001561 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001562 public ArrayList<Integer> startAllBackgroundUsers() {
1563 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001564 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001565 users = new ArrayList<>(mBackgroundUsersToRestart);
1566 mBackgroundUsersRestartedHere.clear();
1567 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001568 }
1569 ArrayList<Integer> startedUsers = new ArrayList<>();
1570 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001571 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001572 continue;
1573 }
1574 try {
1575 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001576 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1577 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001578 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001579 } else if (mAm.unlockUser(user, null, null, null)) {
1580 startedUsers.add(user);
1581 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001582 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001583 if (mUserManager.isUserRunning(user)) {
1584 // add to started list so that it can be stopped later.
1585 startedUsers.add(user);
1586 }
Keun young Parkfb656372019-03-12 18:37:55 -07001587 }
1588 }
1589 } catch (RemoteException e) {
1590 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001591 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001592 }
1593 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001594 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001595 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001596 ArrayList<Integer> usersToRemove = new ArrayList<>();
1597 for (Integer user : mBackgroundUsersToRestart) {
1598 if (!startedUsers.contains(user)) {
1599 usersToRemove.add(user);
1600 }
1601 }
1602 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1603 }
Keun young Parkfb656372019-03-12 18:37:55 -07001604 return startedUsers;
1605 }
1606
1607 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001608 * Stops all background users that were active in system.
1609 *
1610 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001611 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001612 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001613 if (userId == UserHandle.USER_SYSTEM) {
1614 return false;
1615 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001616 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001617 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001618 return false;
1619 }
1620 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001621 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001622 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001623 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001624 Integer user = userId;
1625 mBackgroundUsersRestartedHere.remove(user);
1626 }
1627 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1628 return false;
1629 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001630 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001631 return false;
1632 }
1633 } catch (RemoteException e) {
1634 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001635 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001636 }
1637 return true;
1638 }
1639
1640 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001641 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001642 */
felipeale8c5dce2020-04-15 11:27:06 -07001643 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1644 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1645 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001646
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001647 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001648 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001649 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001650 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1651 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001652 }
1653
felipeale8c5dce2020-04-15 11:27:06 -07001654 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001655 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001656
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001657 mHandler.post(() -> {
1658 handleNotifyServiceUserLifecycleListeners(event);
1659 handleNotifyAppUserLifecycleListeners(event);
1660 });
felipeale8c5dce2020-04-15 11:27:06 -07001661
Keun young Park1fced442020-05-29 09:26:29 -07001662 if (timestampMs != 0) {
1663 // Finally, update metrics.
1664 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1665 }
felipeale8c5dce2020-04-15 11:27:06 -07001666 }
1667
1668 /**
1669 * Sets the first user unlocking metrics.
1670 */
1671 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1672 int halResponseTime) {
1673 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001674 }
1675
Mayank Garg7a114c82020-04-08 21:25:06 -07001676 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001677 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001678 || mUserIdForUserSwitchInProcess != userId
1679 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001680 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1681 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1682 }
1683 return;
1684 }
felipealf7368962020-04-16 12:55:19 -07001685 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1686 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001687 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001688 }
1689
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001690 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1691 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001692 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001693 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1694 Log.d(TAG_USER, "No app listener to be notified of " + event);
1695 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001696 return;
1697 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001698 // Must use a different TimingsTraceLog because it's another thread
1699 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1700 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1701 }
felipeal2a84d512020-04-06 18:52:15 -07001702 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001703 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001704 int eventType = event.getEventType();
1705 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001706 for (int i = 0; i < listenersSize; i++) {
1707 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001708
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001709 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1710 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001711 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001712
felipealde1e16d2020-06-03 13:20:48 -07001713 int fromUserId = event.getPreviousUserId();
1714 if (fromUserId != UserHandle.USER_NULL) {
1715 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001716 }
1717
felipeal2a84d512020-04-06 18:52:15 -07001718 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001719 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001720 }
felipealde1e16d2020-06-03 13:20:48 -07001721 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1722 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001723 try {
felipealde1e16d2020-06-03 13:20:48 -07001724 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001725 listener.send(userId, data);
1726 } catch (RemoteException e) {
1727 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1728 } finally {
1729 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001730 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001731 }
1732 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001733 }
1734
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001735 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001736 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1737 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001738 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001739 return;
felipeal2a84d512020-04-06 18:52:15 -07001740 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1741 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1742 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001743 }
felipeal2a84d512020-04-06 18:52:15 -07001744
felipealde1e16d2020-06-03 13:20:48 -07001745 int userId = event.getUserId();
1746 int eventType = event.getEventType();
1747 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001748 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001749 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001750 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1751 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001752 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001753 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001754 listener.onEvent(event);
1755 } catch (RuntimeException e) {
1756 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001757 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001758 } finally {
1759 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001760 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001761 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001762 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001763 }
1764
Mayank Garge5de0f92020-04-23 21:38:38 -07001765 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001766 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001767 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001768 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001769
Mayank Garge5de0f92020-04-23 21:38:38 -07001770 // Switch HAL users if user switch is not requested by CarUserService
1771 notifyHalLegacySwitch(fromUserId, toUserId);
1772
felipealbf327652020-06-03 11:33:29 -07001773 mCarUserManagerHelper.setLastActiveUser(toUserId);
1774
Eric Jeongc91f9452019-08-30 15:04:21 -07001775 if (mLastPassengerId != UserHandle.USER_NULL) {
1776 stopPassengerInternal(mLastPassengerId, false);
1777 }
1778 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1779 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001780 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001781 }
felipeal98900c82020-04-09 09:05:02 -07001782 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001783 }
1784
Mayank Garge5de0f92020-04-23 21:38:38 -07001785 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1786 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001787 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1788 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1789 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1790 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1791 }
1792 return;
1793 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001794 }
1795
Mayank Garg9ed099e2020-06-04 16:05:20 -07001796 if (!isUserHalSupported()) return;
1797
Mayank Garge5de0f92020-04-23 21:38:38 -07001798 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001799 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001800 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1801 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001802 }
1803
Pavel Maltsev17e81832019-04-04 14:38:41 -07001804 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001805 * 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 -08001806 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001807 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001808 * @param r Runnable to run.
1809 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001810 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001811 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001812 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001813 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001814 if (mUser0Unlocked) {
1815 runNow = true;
1816 } else {
1817 mUser0UnlockTasks.add(r);
1818 }
1819 }
1820 if (runNow) {
1821 r.run();
1822 }
1823 }
1824
Keun young Parkf3523cd2019-04-08 10:09:17 -07001825 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001826 @NonNull
1827 ArrayList<Integer> getBackgroundUsersToRestart() {
1828 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001829 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001830 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1831 }
1832 return backgroundUsersToRestart;
1833 }
1834
Ying Zheng1ab32b62018-06-26 12:47:26 -07001835 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001836 // Disable Location service for system user.
1837 LocationManager locationManager =
1838 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001839 locationManager.setLocationEnabledForUser(
1840 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001841 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001842
1843 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001844 * Assigns a default icon to a user according to the user's id.
1845 *
1846 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001847 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001848 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001849 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1850 Bitmap bitmap = UserIcons.convertToBitmap(
1851 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1852 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001853 }
1854
Eric Jeong1545f3b2019-09-16 13:56:52 -07001855 private interface UserFilter {
1856 boolean isEligibleUser(UserInfo user);
1857 }
1858
1859 /** Returns all users who are matched by the given filter. */
1860 private List<UserInfo> getUsers(UserFilter filter) {
1861 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1862
1863 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1864 UserInfo user = iterator.next();
1865 if (!filter.isEligibleUser(user)) {
1866 iterator.remove();
1867 }
1868 }
1869 return users;
1870 }
1871
1872 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001873 * Enforces that apps which have the
1874 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1875 * can make certain calls to the CarUserManager.
1876 *
1877 * @param message used as message if SecurityException is thrown.
1878 * @throws SecurityException if the caller is not system or root.
1879 */
1880 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001881 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1882 }
1883
felipealdfdf8512020-06-01 09:35:45 -07001884 private static void checkManageOrCreateUsersPermission(String message) {
1885 checkAtLeastOnePermission(message,
1886 android.Manifest.permission.MANAGE_USERS,
1887 android.Manifest.permission.CREATE_USERS);
1888 }
1889
felipeal2d0483c2019-11-02 14:07:22 -07001890 private static void checkManageUsersOrDumpPermission(String message) {
1891 checkAtLeastOnePermission(message,
1892 android.Manifest.permission.MANAGE_USERS,
1893 android.Manifest.permission.DUMP);
1894 }
1895
Felipe Leme5528ff72020-02-10 19:05:14 -08001896 private void checkInteractAcrossUsersPermission(String message) {
1897 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1898 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1899 }
1900
felipeal2d0483c2019-11-02 14:07:22 -07001901 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001902 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001903 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1904 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001905 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001906 }
1907 }
1908
felipeal2d0483c2019-11-02 14:07:22 -07001909 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1910 for (String permission : permissions) {
1911 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1912 /* exported = */ true)
1913 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1914 return true;
1915 }
1916 }
1917 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001918 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001919
1920 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1921 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1922 // Count all users that are managed profiles of the given user.
1923 int managedProfilesCount = 0;
1924 for (UserInfo user : users) {
1925 if (user.isManagedProfile() && user.profileGroupId == userId) {
1926 managedProfilesCount++;
1927 }
1928 }
1929 return managedProfilesCount;
1930 }
1931
1932 /**
1933 * Starts the first passenger of the given driver and assigns the passenger to the front
1934 * passenger zone.
1935 *
1936 * @param driverId User id of the driver.
1937 * @return whether it succeeds.
1938 */
1939 private boolean startFirstPassenger(@UserIdInt int driverId) {
1940 int zoneId = getAvailablePassengerZone();
1941 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1942 Log.w(TAG_USER, "passenger occupant zone is not found");
1943 return false;
1944 }
1945 List<UserInfo> passengers = getPassengers(driverId);
1946 if (passengers.size() < 1) {
1947 Log.w(TAG_USER, "passenger is not found");
1948 return false;
1949 }
1950 // Only one passenger is supported. If there are two or more passengers, the first passenger
1951 // is chosen.
1952 int passengerId = passengers.get(0).id;
1953 if (!startPassenger(passengerId, zoneId)) {
1954 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1955 return false;
1956 }
1957 return true;
1958 }
1959
1960 private int getAvailablePassengerZone() {
1961 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1962 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1963 for (int occupantType : occupantTypes) {
1964 int zoneId = getZoneId(occupantType);
1965 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1966 return zoneId;
1967 }
1968 }
1969 return OccupantZoneInfo.INVALID_ZONE_ID;
1970 }
1971
1972 /**
1973 * Creates a new passenger user when there is no passenger user.
1974 */
1975 private void setupPassengerUser() {
1976 int currentUser = ActivityManager.getCurrentUser();
1977 int profileCount = getNumberOfManagedProfiles(currentUser);
1978 if (profileCount > 0) {
1979 Log.w(TAG_USER, "max profile of user" + currentUser
1980 + " is exceeded: current profile count is " + profileCount);
1981 return;
1982 }
1983 // TODO(b/140311342): Use resource string for the default passenger name.
1984 UserInfo passenger = createPassenger("Passenger", currentUser);
1985 if (passenger == null) {
1986 // Couldn't create user, most likely because there are too many.
1987 Log.w(TAG_USER, "cannot create a passenger user");
1988 return;
1989 }
1990 }
1991
1992 @NonNull
1993 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1994 ZoneUserBindingHelper helper = null;
1995 synchronized (mLockHelper) {
1996 if (mZoneUserBindingHelper == null) {
1997 Log.w(TAG_USER, "implementation is not delegated");
1998 return new ArrayList<OccupantZoneInfo>();
1999 }
2000 helper = mZoneUserBindingHelper;
2001 }
2002 return helper.getOccupantZones(occupantType);
2003 }
2004
2005 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
2006 ZoneUserBindingHelper helper = null;
2007 synchronized (mLockHelper) {
2008 if (mZoneUserBindingHelper == null) {
2009 Log.w(TAG_USER, "implementation is not delegated");
2010 return false;
2011 }
2012 helper = mZoneUserBindingHelper;
2013 }
2014 return helper.assignUserToOccupantZone(userId, zoneId);
2015 }
2016
2017 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
2018 ZoneUserBindingHelper helper = null;
2019 synchronized (mLockHelper) {
2020 if (mZoneUserBindingHelper == null) {
2021 Log.w(TAG_USER, "implementation is not delegated");
2022 return false;
2023 }
2024 helper = mZoneUserBindingHelper;
2025 }
2026 return helper.unassignUserFromOccupantZone(userId);
2027 }
2028
2029 private boolean isPassengerDisplayAvailable() {
2030 ZoneUserBindingHelper helper = null;
2031 synchronized (mLockHelper) {
2032 if (mZoneUserBindingHelper == null) {
2033 Log.w(TAG_USER, "implementation is not delegated");
2034 return false;
2035 }
2036 helper = mZoneUserBindingHelper;
2037 }
2038 return helper.isPassengerDisplayAvailable();
2039 }
2040
2041 /**
2042 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
2043 * zone is returned.
2044 *
2045 * @param occupantType The type of an occupant.
2046 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
2047 * if not found.
2048 */
2049 private int getZoneId(@OccupantTypeEnum int occupantType) {
2050 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
2051 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
2052 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002053}