blob: 701f39d51db1d77c25763b890f8d4779cf4cb065 [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;
felipeal159a2a42020-05-08 10:32:11 -070036import android.car.user.UserIdentificationAssociationResponse;
felipeale5bf0322020-04-16 15:10:57 -070037import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070038import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070039import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070040import android.car.userlib.HalCallback;
41import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070042import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070043import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070044import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070045import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070046import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080047import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070048import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070049import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
50import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070051import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
52import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080053import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070054import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070055import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080056import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070057import android.os.Handler;
58import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070059import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080060import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070061import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070062import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070063import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070064import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070065import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070066import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070067import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080068import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080069import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070070
71import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070072import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070073import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080074import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080075import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070076import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070077import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070078import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080079import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070080import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070081import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070082import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070083import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070084
85import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080086import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070087import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070088import java.util.Iterator;
89import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000090import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070091import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070092import java.util.concurrent.CountDownLatch;
93import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070094
95/**
96 * User service for cars. Manages users at boot time. Including:
97 *
98 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070099 * <li> Creates a user used as driver.
100 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700101 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700102 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700103 * <ol/>
104 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700105public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800106
felipealf7368962020-04-16 12:55:19 -0700107 private static final String TAG = TAG_USER;
108
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800109 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700110 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800111 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700112 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800113 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700114 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800115 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700116 public static final String BUNDLE_INITIAL_INFO_ACTION =
117 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800118
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700119 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700120 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700121 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700122 private final UserManager mUserManager;
123 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700124 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700125
Eric Jeongc91f9452019-08-30 15:04:21 -0700126 private final Object mLockUser = new Object();
127 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800128 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700129 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800130 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700131 // Only one passenger is supported.
132 @GuardedBy("mLockUser")
133 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700134 /**
135 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800136 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700137 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700138 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700139 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
140 /**
141 * Keep the list of background users started here. This is wholly for debugging purpose.
142 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700143 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700144 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
145
Felipe Leme58412202020-01-09 13:45:33 -0800146 private final UserHalService mHal;
147
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700148 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700149 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
150 getClass().getSimpleName());
151 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700152
Felipe Leme5528ff72020-02-10 19:05:14 -0800153 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800154 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700155 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800156 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700157 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800158
159 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800160 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700161 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800162 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700163 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800164
Mayank Garg7a114c82020-04-08 21:25:06 -0700165 /**
166 * User Id for the user switch in process, if any.
167 */
168 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700169 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700170 /**
171 * Request Id for the user switch in process, if any.
172 */
173 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700174 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700175 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
176
Eric Jeongc91f9452019-08-30 15:04:21 -0700177 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
178 new CopyOnWriteArrayList<>();
179
felipeal61ce3732020-04-03 11:01:00 -0700180 @Nullable
181 @GuardedBy("mLockUser")
182 private UserInfo mInitialUser;
183
Mayank Garg71661ea2020-04-29 01:25:03 -0700184 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700185
Mayank Garg587f1942020-05-06 01:41:34 -0700186 private IResultReceiver mUserSwitchUiReceiver;
187
Eric Jeongc91f9452019-08-30 15:04:21 -0700188 /** Interface for callbaks related to passenger activities. */
189 public interface PassengerCallback {
190 /** Called when passenger is started at a certain zone. */
191 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
192 /** Called when passenger is stopped. */
193 void onPassengerStopped(@UserIdInt int passengerId);
194 }
195
196 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
197 public interface ZoneUserBindingHelper {
198 /** Gets occupant zones corresponding to the occupant type. */
199 @NonNull
200 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
201 /** Assigns the user to the occupant zone. */
202 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
203 /** Makes the occupant zone unoccupied. */
204 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
205 /** Returns whether there is a passenger display. */
206 boolean isPassengerDisplayAvailable();
207 }
208
209 private final Object mLockHelper = new Object();
210 @GuardedBy("mLockHelper")
211 private ZoneUserBindingHelper mZoneUserBindingHelper;
212
Felipe Leme58412202020-01-09 13:45:33 -0800213 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700214 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
215 @NonNull IActivityManager am, int maxRunningUsers) {
216 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
217 new UserMetrics());
218 }
219
220 @VisibleForTesting
221 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
222 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
223 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700224 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
225 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700226 }
227 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800228 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700229 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700230 mAm = am;
231 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700232 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700233 mLastPassengerId = UserHandle.USER_NULL;
234 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700235 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700236 }
237
238 @Override
239 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700240 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
241 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700242 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700243 }
244
245 @Override
246 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700247 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
248 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700249 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700250 }
251
252 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700253 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700254 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700255 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800256 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700257 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700258 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700259 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700260 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700261 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
262 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700263 }
264 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
265 List<UserInfo> allDrivers = getAllDrivers();
266 int driversSize = allDrivers.size();
267 writer.println("NumberOfDrivers: " + driversSize);
268 for (int i = 0; i < driversSize; i++) {
269 int driverId = allDrivers.get(i).id;
270 writer.print(indent + "#" + i + ": id=" + driverId);
271 List<UserInfo> passengers = getPassengers(driverId);
272 int passengersSize = passengers.size();
273 writer.print(" NumberPassengers: " + passengersSize);
274 if (passengersSize > 0) {
275 writer.print(" [");
276 for (int j = 0; j < passengersSize; j++) {
277 writer.print(passengers.get(j).id);
278 if (j < passengersSize - 1) {
279 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700280 }
felipeal2d0483c2019-11-02 14:07:22 -0700281 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700282 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700283 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700284 writer.println();
285 }
286 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
287 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
288 writer.printf("Initial user: %s\n", mInitialUser);
289 writer.println("Relevant overlayable properties");
290 Resources res = mContext.getResources();
291 writer.printf("%sowner_name=%s\n", indent,
292 res.getString(com.android.internal.R.string.owner_name));
293 writer.printf("%sdefault_guest_name=%s\n", indent,
294 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700295 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700296 writer.printf("Request Id for the user switch in process=%d\n ",
297 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700298
299 dumpUserMetrics(writer);
300 }
301
302 /**
303 * Dumps user metrics.
304 */
305 public void dumpUserMetrics(@NonNull PrintWriter writer) {
306 mUserMetrics.dump(writer);
307 }
308
309 /**
310 * Dumps first user unlocking time.
311 */
312 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
313 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700314 }
315
316 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
317 CountDownLatch latch = new CountDownLatch(1);
318 mHandler.post(() -> {
319 handleDumpUserLifecycleListeners(writer);
320 handleDumpAppLifecycleListeners(writer, indent);
321 latch.countDown();
322 });
323 int timeout = 5;
324 try {
325 if (!latch.await(timeout, TimeUnit.SECONDS)) {
326 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
327 timeout);
328 }
329 } catch (InterruptedException e) {
330 Thread.currentThread().interrupt();
331 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
332 }
333 }
334
335 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
336 if (mUserLifecycleListeners.isEmpty()) {
337 writer.println("No user lifecycle listeners");
338 return;
339 }
340 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
341 for (UserLifecycleListener listener : mUserLifecycleListeners) {
342 writer.printf("Listener %s\n", listener);
343 }
344 }
345
346 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
347 int numberListeners = mAppLifecycleListeners.size();
348 if (numberListeners == 0) {
349 writer.println("No lifecycle listeners");
350 return;
351 }
352 writer.printf("%d lifecycle listeners\n", numberListeners);
353 for (int i = 0; i < numberListeners; i++) {
354 int uid = mAppLifecycleListeners.keyAt(i);
355 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
356 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800357 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700358 }
359
360 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800361 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
362 *
363 * @param name The name of the driver to be created.
364 * @param admin Whether the created driver will be an admin.
365 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
366 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700367 */
368 @Override
369 @Nullable
370 public UserInfo createDriver(@NonNull String name, boolean admin) {
371 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000372 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700373 if (admin) {
374 return createNewAdminUser(name);
375 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700376 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700377 }
378
379 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800380 * Creates a passenger who is a profile of the given driver.
381 *
382 * @param name The name of the passenger to be created.
383 * @param driverId User id of the driver under whom a passenger is created.
384 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
385 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700386 */
387 @Override
388 @Nullable
389 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
390 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000391 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700392 UserInfo driver = mUserManager.getUserInfo(driverId);
393 if (driver == null) {
394 Log.w(TAG_USER, "the driver is invalid");
395 return null;
396 }
397 if (driver.isGuest()) {
398 Log.w(TAG_USER, "a guest driver cannot create a passenger");
399 return null;
400 }
Bookatz42fb1a62019-10-30 11:45:01 -0700401 UserInfo user = mUserManager.createProfileForUser(name,
402 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700403 if (user == null) {
404 // Couldn't create user, most likely because there are too many.
405 Log.w(TAG_USER, "can't create a profile for user" + driverId);
406 return null;
407 }
408 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700409 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700410 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700411 return user;
412 }
413
414 /**
415 * @see CarUserManager.switchDriver
416 */
417 @Override
418 public boolean switchDriver(@UserIdInt int driverId) {
419 checkManageUsersPermission("switchDriver");
420 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
421 // System user doesn't associate with real person, can not be switched to.
422 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
423 return false;
424 }
425 int userSwitchable = mUserManager.getUserSwitchability();
426 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
427 Log.w(TAG_USER, "current process is not allowed to switch user");
428 return false;
429 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700430 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700431 // The current user is already the given user.
432 return true;
433 }
434 try {
435 return mAm.switchUser(driverId);
436 } catch (RemoteException e) {
437 // ignore
438 Log.w(TAG_USER, "error while switching user", e);
439 }
440 return false;
441 }
442
443 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800444 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
445 *
446 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 */
448 @Override
449 @NonNull
450 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700451 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700452 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
453 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700454 }
455
456 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800457 * Returns all passengers under the given driver.
458 *
459 * @param driverId User id of a driver.
460 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700461 */
462 @Override
463 @NonNull
464 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700465 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700466 return getUsers((user) -> {
467 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
468 && user.profileGroupId == driverId;
469 });
470 }
471
472 /**
473 * @see CarUserManager.startPassenger
474 */
475 @Override
476 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
477 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700478 synchronized (mLockUser) {
479 try {
480 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
481 Log.w(TAG_USER, "could not start passenger");
482 return false;
483 }
484 } catch (RemoteException e) {
485 // ignore
486 Log.w(TAG_USER, "error while starting passenger", e);
487 return false;
488 }
489 if (!assignUserToOccupantZone(passengerId, zoneId)) {
490 Log.w(TAG_USER, "could not assign passenger to zone");
491 return false;
492 }
493 mLastPassengerId = passengerId;
494 }
495 for (PassengerCallback callback : mPassengerCallbacks) {
496 callback.onPassengerStarted(passengerId, zoneId);
497 }
498 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700499 }
500
501 /**
502 * @see CarUserManager.stopPassenger
503 */
504 @Override
505 public boolean stopPassenger(@UserIdInt int passengerId) {
506 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700507 return stopPassengerInternal(passengerId, true);
508 }
509
510 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
511 synchronized (mLockUser) {
512 UserInfo passenger = mUserManager.getUserInfo(passengerId);
513 if (passenger == null) {
514 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
515 return false;
516 }
517 if (mLastPassengerId != passengerId) {
518 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
519 return true;
520 }
521 if (checkCurrentDriver) {
522 int currentUser = ActivityManager.getCurrentUser();
523 if (passenger.profileGroupId != currentUser) {
524 Log.w(TAG_USER, "passenger " + passengerId
525 + " is not a profile of the current user");
526 return false;
527 }
528 }
529 // Passenger is a profile, so cannot be stopped through activity manager.
530 // Instead, activities started by the passenger are stopped and the passenger is
531 // unassigned from the zone.
532 stopAllTasks(passengerId);
533 if (!unassignUserFromOccupantZone(passengerId)) {
534 Log.w(TAG_USER, "could not unassign user from occupant zone");
535 return false;
536 }
537 mLastPassengerId = UserHandle.USER_NULL;
538 }
539 for (PassengerCallback callback : mPassengerCallbacks) {
540 callback.onPassengerStopped(passengerId);
541 }
542 return true;
543 }
544
545 private void stopAllTasks(@UserIdInt int userId) {
546 try {
547 for (StackInfo info : mAm.getAllStackInfos()) {
548 for (int i = 0; i < info.taskIds.length; i++) {
549 if (info.taskUserIds[i] == userId) {
550 int taskId = info.taskIds[i];
551 if (!mAm.removeTask(taskId)) {
552 Log.w(TAG_USER, "could not remove task " + taskId);
553 }
554 }
555 }
556 }
557 } catch (RemoteException e) {
558 Log.e(TAG_USER, "could not get stack info", e);
559 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700560 }
561
Felipe Leme5528ff72020-02-10 19:05:14 -0800562 @Override
563 public void setLifecycleListenerForUid(IResultReceiver listener) {
564 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700565 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800566 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
567
568 try {
569 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
570 } catch (RemoteException e) {
571 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
572 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700573 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800574 }
575
576 private void onListenerDeath(int uid) {
577 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700578 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800579 }
580
581 @Override
582 public void resetLifecycleListenerForUid() {
583 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700584 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800585 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700586 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800587 }
588
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800589 @Override
590 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800591 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700592 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
593 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800594 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700595 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800596 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800597 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700598 Bundle resultData = null;
599 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700600 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
601 status, resp.action, resp.userToSwitchOrCreate.userId,
602 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700603 switch (resp.action) {
604 case InitialUserInfoResponseAction.SWITCH:
605 resultData = new Bundle();
606 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
607 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
608 break;
609 case InitialUserInfoResponseAction.CREATE:
610 resultData = new Bundle();
611 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
612 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
613 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
614 break;
615 case InitialUserInfoResponseAction.DEFAULT:
616 resultData = new Bundle();
617 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
618 break;
619 default:
620 // That's ok, it will be the same as DEFAULT...
621 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800622 }
felipeal312416a2020-04-14 12:28:24 -0700623 } else {
624 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800625 }
Mayank Garg0e239142020-04-14 19:16:31 -0700626 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800627 });
628 }
629
Felipe Lemee3cab982020-03-12 11:39:29 -0700630 /**
felipeal61ce3732020-04-03 11:01:00 -0700631 * Gets the initial foreground user after the device boots or resumes from suspension.
632 *
633 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
634 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
635 * method returns {@code null}.
636 *
637 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
638 * (like switching to the last active user), and this method will return the result of such
639 * operation.
640 *
641 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
642 * {@code null}.
643 *
644 * @hide
645 */
646 @Nullable
647 public UserInfo getInitialUser() {
648 checkInteractAcrossUsersPermission("getInitialUser");
649 synchronized (mLockUser) {
650 return mInitialUser;
651 }
652 }
653
654 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
655 // some reason passing the whole UserInfo through a raw binder transaction is not working.
656 /**
657 * Sets the initial foreground user after the device boots or resumes from suspension.
658 */
659 public void setInitialUser(@UserIdInt int userId) {
660 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
661 : mUserManager.getUserInfo(userId);
662 setInitialUser(initialUser);
663 }
664
665 /**
666 * Sets the initial foreground user after the device boots or resumes from suspension.
667 */
668 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700669 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
670 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700671 synchronized (mLockUser) {
672 mInitialUser = user;
673 }
674 if (user == null) {
675 // This mean InitialUserSetter failed and could not fallback, so the initial user was
676 // not switched (and most likely is SYSTEM_USER).
677 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
678 Log.wtf(TAG_USER, "Initial user set to null");
679 }
680 }
681
682 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700683 * Calls the User HAL to get the initial user info.
684 *
685 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
686 * @param callback callback to receive the results.
687 */
688 public void getInitialUserInfo(int requestType,
689 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700690 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
691 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700692 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700693 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700694 UsersInfo usersInfo = getUsersInfo();
695 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
696 }
697
698 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700699 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
700 *
701 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700702 * When everything works well, the workflow is:
703 * <ol>
704 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
705 * type, current user id, target user id, and a callback.
706 * <li> HAL called back with SUCCESS.
707 * <li> {@link IActivityManager} is called for Android user switch.
708 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
709 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
710 * request type, current user id, and target user id. In this case, the current and target
711 * user IDs would be same.
712 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700713 *
714 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700715 * Corner cases:
716 * <ul>
717 * <li> If target user is already the current user, no user switch is performed and receiver
718 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
719 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
720 * {@code STATUS_HAL_INTERNAL_FAILURE}.
721 * <li> If HAL user switch call is successful, but android user switch call fails,
722 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
723 * target user id, but in this case the current and target user IDs would be different.
724 * <li> If another user switch request for the same target user is received while previous
725 * request is in process, receiver would receive
726 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
727 * <li> If a user switch request is received while another user switch request for different
728 * target user is in process, the previous request would be abandoned and new request will be
729 * processed. No POST_SWITCH would be sent for the previous request.
730 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700731 *
Mayank Garge19c2922020-03-30 18:05:53 -0700732 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700733 * @param timeoutMs - timeout for HAL to wait
734 * @param receiver - receiver for the results
735 */
Mayank Garge19c2922020-03-30 18:05:53 -0700736 @Override
737 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700738 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700739 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700740 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700741 Objects.requireNonNull(receiver);
742 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700743 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700744
felipealf7368962020-04-16 12:55:19 -0700745 int currentUser = ActivityManager.getCurrentUser();
746 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700747 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
748 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
749 }
felipeale5bf0322020-04-16 15:10:57 -0700750 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
751 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700752 return;
753 }
754
Mayank Garg7a114c82020-04-08 21:25:06 -0700755 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700756 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
757 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
758 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
759 }
760
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700761 // If there is another request for the same target user, return another request in
762 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
763 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
764 // user switch request in process for different target user, but that request is now
765 // ignored.
felipealf7368962020-04-16 12:55:19 -0700766 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700767 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
768 Log.d(TAG_USER,
769 "Another user switch request in process for the requested target user: "
770 + targetUserId);
771 }
772
773 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700774 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700775 return;
776 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700777 else {
778 mUserIdForUserSwitchInProcess = targetUserId;
779 mRequestIdForUserSwitchInProcess = 0;
780 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700781 }
782
Mayank Garg59f22192020-03-27 00:51:45 -0700783 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700784 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700785 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700786 halTargetUser.userId = targetUser.id;
787 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
788 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700789 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
790 Log.d(TAG, "switch response: status="
791 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
792 }
793
felipeale5bf0322020-04-16 15:10:57 -0700794 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700795
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700796 synchronized (mLockUser) {
797 if (status != HalCallback.STATUS_OK) {
798 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
799 Log.w(TAG, "invalid callback status ("
800 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
801 + resp);
802 sendResult(receiver, resultStatus);
803 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
804 return;
805 }
felipealf7368962020-04-16 12:55:19 -0700806
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700807 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
808 resp.errorMessage);
809
810 if (mUserIdForUserSwitchInProcess != targetUserId) {
811 // Another user switch request received while HAL responded. No need to process
812 // this request further
813 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
814 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
815 + "abondoned for : " + targetUserId + ". Current user in process: "
816 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700817 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700818 resultStatus =
819 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
820 sendResult(receiver, resultStatus);
821 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
822 return;
823 }
824
825 switch (resp.status) {
826 case SwitchUserStatus.SUCCESS:
827 boolean switched;
828 try {
829 switched = mAm.switchUser(targetUserId);
830 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700831 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700832 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
833 mRequestIdForUserSwitchInProcess = resp.requestId;
834 } else {
835 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
836 postSwitchHalResponse(resp.requestId, targetUserId);
837 }
838 } catch (RemoteException e) {
839 // ignore
840 Log.w(TAG_USER,
841 "error while switching user " + targetUser.toFullString(), e);
842 }
843 break;
844 case SwitchUserStatus.FAILURE:
845 // HAL failed to switch user
846 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
847 break;
848 }
849
850 if (mRequestIdForUserSwitchInProcess == 0) {
851 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
852 }
Mayank Garg59f22192020-03-27 00:51:45 -0700853 }
felipeale5bf0322020-04-16 15:10:57 -0700854 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700855 });
856 }
857
Mayank Garg587f1942020-05-06 01:41:34 -0700858 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
859 if (mUserSwitchUiReceiver == null) {
860 Log.w(TAG_USER, "No User switch UI receiver.");
861 return;
862 }
863
864 try {
865 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
866 mUserSwitchUiReceiver.send(targetUserId, null);
867 } catch (RemoteException e) {
868 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
869 }
870 }
871
felipeal5e3ede42020-04-23 18:04:07 -0700872 @Override
felipeal159a2a42020-05-08 10:32:11 -0700873 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
felipeal5e3ede42020-04-23 18:04:07 -0700874 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
875 checkManageUsersPermission("getUserIdentificationAssociation");
876
877 int uid = getCallingUid();
878 int userId = UserHandle.getUserId(uid);
879 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
880
881 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
882 request.userInfo.userId = userId;
883 request.userInfo.flags = getHalUserInfoFlags(userId);
884
885 request.numberAssociationTypes = types.length;
886 for (int i = 0; i < types.length; i++) {
887 request.associationTypes.add(types[i]);
888 }
889
890 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
891 if (halResponse == null) {
892 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
893 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -0700894 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -0700895 }
896
897 int[] values = new int[halResponse.associations.size()];
898 for (int i = 0; i < values.length; i++) {
899 values[i] = halResponse.associations.get(i).value;
900 }
901 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
902
felipeal159a2a42020-05-08 10:32:11 -0700903 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
904 }
905
906 @Override
907 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
908 AndroidFuture<UserIdentificationAssociationResponse> result) {
909 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
910 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
911 if (types.length != values.length) {
912 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
913 + Arrays.toString(values) + ") should have the same length");
914 }
915 checkManageUsersPermission("setUserIdentificationAssociation");
916
917 int uid = getCallingUid();
918 int userId = UserHandle.getUserId(uid);
919 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
920
921 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
922 request.userInfo.userId = userId;
923 request.userInfo.flags = getHalUserInfoFlags(userId);
924
925 request.numberAssociations = types.length;
926 for (int i = 0; i < types.length; i++) {
927 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
928 association.type = types[i];
929 association.value = values[i];
930 request.associations.add(association);
931 }
932
933 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
934 if (status != HalCallback.STATUS_OK) {
935 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
936 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
937 + resp);
938 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
939 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
940 result.complete(UserIdentificationAssociationResponse.forFailure());
941 return;
942 }
943 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
944 resp.errorMessage);
945 result.complete(
946 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
947 return;
948 }
949 int respSize = resp.associations.size();
950 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
951 resp.errorMessage);
952
953 int[] responseTypes = new int[respSize];
954 for (int i = 0; i < respSize; i++) {
955 responseTypes[i] = resp.associations.get(i).value;
956 }
957 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
958 .forSuccess(responseTypes, resp.errorMessage);
959 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
960 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
961 + ", converted=" + response);
962 }
963 result.complete(response);
964 });
felipeal5e3ede42020-04-23 18:04:07 -0700965 }
966
967 /**
968 * Gets the User HAL flags for the given user.
969 *
970 * @throws IllegalArgumentException if the user does not exist.
971 */
972 private int getHalUserInfoFlags(@UserIdInt int userId) {
973 UserInfo user = mUserManager.getUserInfo(userId);
974 Preconditions.checkArgument(user != null, "no user for id %d", userId);
975 return UserHalHelper.convertFlags(user);
976 }
977
Mayank Garg0e239142020-04-14 19:16:31 -0700978 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
979 @Nullable Bundle resultData) {
980 try {
981 receiver.send(resultCode, resultData);
982 } catch (RemoteException e) {
983 // ignore
984 Log.w(TAG_USER, "error while sending results", e);
985 }
986 }
987
felipeale5bf0322020-04-16 15:10:57 -0700988 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
989 @UserSwitchResult.Status int status) {
990 sendResult(receiver, status, /* errorMessage= */ null);
991 }
992
993 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
994 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
995 receiver.complete(new UserSwitchResult(status, errorMessage));
996 }
997
Mayank Garg6307fe42020-04-15 23:09:03 -0700998 /**
999 * Calls activity manager for user switch.
1000 *
1001 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1002 *
1003 * @param requestId for the user switch request
1004 * @param targetUserId of the target user
1005 *
1006 * @hide
1007 */
1008 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1009 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1010 targetUserId);
1011 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1012
1013 try {
1014 boolean result = mAm.switchUser(targetUserId);
1015 if (result) {
1016 updateUserSwitchInProcess(requestId, targetUserId);
1017 } else {
1018 postSwitchHalResponse(requestId, targetUserId);
1019 }
1020 } catch (RemoteException e) {
1021 // ignore
1022 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1023 }
1024 }
1025
1026 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1027 synchronized (mLockUser) {
1028 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1029 // Some other user switch is in process.
1030 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1031 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1032 + " is in process. Abandoning it as a new user switch is requested"
1033 + " for the target user: " + targetUserId);
1034 }
1035 }
1036 mUserIdForUserSwitchInProcess = targetUserId;
1037 mRequestIdForUserSwitchInProcess = requestId;
1038 }
1039 }
1040
Mayank Garg7a114c82020-04-08 21:25:06 -07001041 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
1042 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
1043 UsersInfo usersInfo = getUsersInfo();
1044 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1045 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1046 halTargetUser.userId = targetUser.id;
1047 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -07001048 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1049 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001050 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
1051 }
1052
Mayank Garg59f22192020-03-27 00:51:45 -07001053 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001054 * Checks if the User HAL is supported.
1055 */
1056 public boolean isUserHalSupported() {
1057 return mHal.isSupported();
1058 }
1059
Mayank Garg587f1942020-05-06 01:41:34 -07001060 /**
1061 * Sets a callback which is invoked before user switch.
1062 *
1063 * <p>
1064 * This method should only be called by the Car System UI. The purpose of this call is to notify
1065 * Car System UI to show the user switch UI before the user switch.
1066 */
1067 @Override
1068 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
1069 // TODO(b/154958003): check UID, only carSysUI should be allowed to set it.
Yan Zhu67a383e2020-05-11 20:46:24 -07001070 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garg587f1942020-05-06 01:41:34 -07001071 mUserSwitchUiReceiver = receiver;
1072 }
1073
felipeal159a2a42020-05-08 10:32:11 -07001074 // TODO(b/150413515): use helper to generate UsersInfo
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001075 private UsersInfo getUsersInfo() {
1076 UserInfo currentUser;
1077 try {
1078 currentUser = mAm.getCurrentUser();
1079 } catch (RemoteException e) {
1080 // shouldn't happen
1081 throw new IllegalStateException("Could not get current user: ", e);
1082 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001083 return getUsersInfo(currentUser);
1084 }
1085
felipeal159a2a42020-05-08 10:32:11 -07001086 // TODO(b/150413515): use helper to generate UsersInfo
Mayank Garge5de0f92020-04-23 21:38:38 -07001087 private UsersInfo getUsersInfo(@NonNull UserInfo currentUser) {
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001088 List<UserInfo> existingUsers = mUserManager.getUsers();
1089 int size = existingUsers.size();
1090
1091 UsersInfo usersInfo = new UsersInfo();
1092 usersInfo.numberUsers = size;
1093 usersInfo.currentUser.userId = currentUser.id;
1094 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
1095
1096 for (int i = 0; i < size; i++) {
1097 UserInfo androidUser = existingUsers.get(i);
1098 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1099 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1100 halUser.userId = androidUser.id;
1101 halUser.flags = UserHalHelper.convertFlags(androidUser);
1102 usersInfo.existingUsers.add(halUser);
1103 }
1104
1105 return usersInfo;
1106 }
1107
Eric Jeong1545f3b2019-09-16 13:56:52 -07001108 /** Returns whether the given user is a system user. */
1109 private static boolean isSystemUser(@UserIdInt int userId) {
1110 return userId == UserHandle.USER_SYSTEM;
1111 }
1112
Keun young Park13a7a822019-04-04 15:53:08 -07001113 private void updateDefaultUserRestriction() {
1114 // We want to set restrictions on system and guest users only once. These are persisted
1115 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1116 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001117 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1118 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001119 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001120 // Only apply the system user restrictions if the system user is headless.
1121 if (UserManager.isHeadlessSystemUserMode()) {
1122 setSystemUserRestrictions();
1123 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001124 Settings.Global.putInt(mContext.getContentResolver(),
1125 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001126 }
1127
Eric Jeong1545f3b2019-09-16 13:56:52 -07001128 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001129 return !mUserManager.getUserInfo(userId).isEphemeral();
1130 }
1131
Antonio Kantekc8114752020-03-05 21:37:39 -08001132 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001133 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1134 */
1135 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1136 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001137 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001138 }
1139
1140 /**
1141 * Removes previously added {@link UserLifecycleListener}.
1142 */
1143 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1144 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001145 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001146 }
1147
Eric Jeongc91f9452019-08-30 15:04:21 -07001148 /** Adds callback to listen to passenger activity events. */
1149 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001150 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001151 mPassengerCallbacks.add(callback);
1152 }
1153
1154 /** Removes previously added callback to listen passenger events. */
1155 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001156 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001157 mPassengerCallbacks.remove(callback);
1158 }
1159
1160 /** Sets the implementation of ZoneUserBindingHelper. */
1161 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1162 synchronized (mLockHelper) {
1163 mZoneUserBindingHelper = helper;
1164 }
1165 }
1166
felipeal98900c82020-04-09 09:05:02 -07001167 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001168 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001169 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001170 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001171 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001172 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1173 updateDefaultUserRestriction();
1174 tasks = new ArrayList<>(mUser0UnlockTasks);
1175 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001176 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001177 }
1178 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001179 Integer user = userId;
1180 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001181 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001182 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001183 mBackgroundUsersToRestart.remove(user);
1184 mBackgroundUsersToRestart.add(0, user);
1185 }
1186 // -1 for user 0
1187 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001188 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001189 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001190 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001191 + ", dropping least recently user from restart list:" + userToDrop);
1192 // Drop the least recently used user.
1193 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1194 }
1195 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001196 }
1197 }
1198 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001199 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001200 for (Runnable r : tasks) {
1201 r.run();
1202 }
1203 }
1204 }
1205
1206 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001207 * Starts all background users that were active in system.
1208 *
Keun young Parkfb656372019-03-12 18:37:55 -07001209 * @return list of background users started successfully.
1210 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001211 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001212 public ArrayList<Integer> startAllBackgroundUsers() {
1213 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001214 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001215 users = new ArrayList<>(mBackgroundUsersToRestart);
1216 mBackgroundUsersRestartedHere.clear();
1217 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001218 }
1219 ArrayList<Integer> startedUsers = new ArrayList<>();
1220 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001221 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001222 continue;
1223 }
1224 try {
1225 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001226 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1227 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001228 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001229 } else if (mAm.unlockUser(user, null, null, null)) {
1230 startedUsers.add(user);
1231 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001232 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001233 if (mUserManager.isUserRunning(user)) {
1234 // add to started list so that it can be stopped later.
1235 startedUsers.add(user);
1236 }
Keun young Parkfb656372019-03-12 18:37:55 -07001237 }
1238 }
1239 } catch (RemoteException e) {
1240 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001241 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001242 }
1243 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001244 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001245 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001246 ArrayList<Integer> usersToRemove = new ArrayList<>();
1247 for (Integer user : mBackgroundUsersToRestart) {
1248 if (!startedUsers.contains(user)) {
1249 usersToRemove.add(user);
1250 }
1251 }
1252 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1253 }
Keun young Parkfb656372019-03-12 18:37:55 -07001254 return startedUsers;
1255 }
1256
1257 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001258 * Stops all background users that were active in system.
1259 *
1260 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001261 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001262 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001263 if (userId == UserHandle.USER_SYSTEM) {
1264 return false;
1265 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001266 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001267 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001268 return false;
1269 }
1270 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001271 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001272 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001273 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001274 Integer user = userId;
1275 mBackgroundUsersRestartedHere.remove(user);
1276 }
1277 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1278 return false;
1279 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001280 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001281 return false;
1282 }
1283 } catch (RemoteException e) {
1284 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001285 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001286 }
1287 return true;
1288 }
1289
1290 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001291 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001292 */
felipeale8c5dce2020-04-15 11:27:06 -07001293 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1294 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1295 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001296
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001297 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001298 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001299 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001300 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1301 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001302 }
1303
felipeale8c5dce2020-04-15 11:27:06 -07001304 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001305 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001306
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001307 mHandler.post(() -> {
1308 handleNotifyServiceUserLifecycleListeners(event);
1309 handleNotifyAppUserLifecycleListeners(event);
1310 });
felipeale8c5dce2020-04-15 11:27:06 -07001311
1312 // Finally, update metrics.
1313 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1314 }
1315
1316 /**
1317 * Sets the first user unlocking metrics.
1318 */
1319 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1320 int halResponseTime) {
1321 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001322 }
1323
Mayank Garg7a114c82020-04-08 21:25:06 -07001324 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001325 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001326 || mUserIdForUserSwitchInProcess != userId
1327 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001328 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1329 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1330 }
1331 return;
1332 }
felipealf7368962020-04-16 12:55:19 -07001333 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1334 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001335 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001336 }
1337
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001338 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1339 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001340 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001341 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1342 Log.d(TAG_USER, "No app listener to be notified of " + event);
1343 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001344 return;
1345 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001346 // Must use a different TimingsTraceLog because it's another thread
1347 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1348 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1349 }
felipeal2a84d512020-04-06 18:52:15 -07001350 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001351 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1352 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1353 for (int i = 0; i < listenersSize; i++) {
1354 int uid = mAppLifecycleListeners.keyAt(i);
1355 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1356 Bundle data = new Bundle();
1357 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001358
1359 int fromUid = event.getPreviousUserId();
1360 if (fromUid != UserHandle.USER_NULL) {
1361 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1362 }
1363
felipeal2a84d512020-04-06 18:52:15 -07001364 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001365 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001366 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001367 try {
felipeal2a84d512020-04-06 18:52:15 -07001368 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001369 listener.send(userId, data);
1370 } catch (RemoteException e) {
1371 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1372 } finally {
1373 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001374 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001375 }
1376 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001377 }
1378
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001379 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001380 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1381 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001382 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001383 return;
felipeal2a84d512020-04-06 18:52:15 -07001384 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1385 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1386 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001387 }
felipeal2a84d512020-04-06 18:52:15 -07001388
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001389 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1390 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001391 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001392 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001393 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001394 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001395 listener.onEvent(event);
1396 } catch (RuntimeException e) {
1397 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001398 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001399 } finally {
1400 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001401 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001402 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001403 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001404 }
1405
Mayank Garge5de0f92020-04-23 21:38:38 -07001406 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1407 Log.i(TAG_USER, "onSwitchUser() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001408 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001409 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001410
Mayank Garge5de0f92020-04-23 21:38:38 -07001411 // Switch HAL users if user switch is not requested by CarUserService
1412 notifyHalLegacySwitch(fromUserId, toUserId);
1413
1414 if (!isSystemUser(toUserId)) {
1415 mCarUserManagerHelper.setLastActiveUser(toUserId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001416 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001417 if (mLastPassengerId != UserHandle.USER_NULL) {
1418 stopPassengerInternal(mLastPassengerId, false);
1419 }
1420 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1421 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001422 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001423 }
felipeal98900c82020-04-09 09:05:02 -07001424 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001425 }
1426
Mayank Garge5de0f92020-04-23 21:38:38 -07001427 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1428 synchronized (mLockUser) {
1429 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1430 }
1431
1432 // switch HAL user
1433 UserInfo targetUser = mUserManager.getUserInfo(toUserId);
1434 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1435 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1436 halTargetUser.userId = targetUser.id;
1437 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
1438 UserInfo currentUser = mUserManager.getUserInfo(fromUserId);
1439 UsersInfo usersInfo = getUsersInfo(currentUser);
1440 mHal.legacyUserSwitch(halTargetUser, usersInfo);
1441 }
1442
Pavel Maltsev17e81832019-04-04 14:38:41 -07001443 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001444 * 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 -08001445 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001446 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001447 * @param r Runnable to run.
1448 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001449 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001450 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001451 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001452 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001453 if (mUser0Unlocked) {
1454 runNow = true;
1455 } else {
1456 mUser0UnlockTasks.add(r);
1457 }
1458 }
1459 if (runNow) {
1460 r.run();
1461 }
1462 }
1463
Keun young Parkf3523cd2019-04-08 10:09:17 -07001464 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001465 @NonNull
1466 ArrayList<Integer> getBackgroundUsersToRestart() {
1467 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001468 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001469 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1470 }
1471 return backgroundUsersToRestart;
1472 }
1473
Ying Zheng1ab32b62018-06-26 12:47:26 -07001474 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001475 // Disable Location service for system user.
1476 LocationManager locationManager =
1477 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001478 locationManager.setLocationEnabledForUser(
1479 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001480 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001481
1482 /**
1483 * Creates a new user on the system, the created user would be granted admin role.
1484 *
1485 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001486 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001487 */
1488 @Nullable
1489 private UserInfo createNewAdminUser(String name) {
1490 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1491 // Only admins or system user can create other privileged users.
1492 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1493 return null;
1494 }
1495
1496 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1497 if (user == null) {
1498 // Couldn't create user, most likely because there are too many.
1499 Log.w(TAG_USER, "can't create admin user.");
1500 return null;
1501 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001502 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001503
1504 return user;
1505 }
1506
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001507 /**
1508 * Assigns a default icon to a user according to the user's id.
1509 *
1510 * @param userInfo User whose avatar is set to default icon.
1511 * @return Bitmap of the user icon.
1512 */
1513 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1514 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1515 Bitmap bitmap = UserIcons.convertToBitmap(
1516 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1517 mUserManager.setUserIcon(userInfo.id, bitmap);
1518 return bitmap;
1519 }
1520
Eric Jeong1545f3b2019-09-16 13:56:52 -07001521 private interface UserFilter {
1522 boolean isEligibleUser(UserInfo user);
1523 }
1524
1525 /** Returns all users who are matched by the given filter. */
1526 private List<UserInfo> getUsers(UserFilter filter) {
1527 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1528
1529 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1530 UserInfo user = iterator.next();
1531 if (!filter.isEligibleUser(user)) {
1532 iterator.remove();
1533 }
1534 }
1535 return users;
1536 }
1537
1538 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001539 * Enforces that apps which have the
1540 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1541 * can make certain calls to the CarUserManager.
1542 *
1543 * @param message used as message if SecurityException is thrown.
1544 * @throws SecurityException if the caller is not system or root.
1545 */
1546 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001547 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1548 }
1549
1550 private static void checkManageUsersOrDumpPermission(String message) {
1551 checkAtLeastOnePermission(message,
1552 android.Manifest.permission.MANAGE_USERS,
1553 android.Manifest.permission.DUMP);
1554 }
1555
Felipe Leme5528ff72020-02-10 19:05:14 -08001556 private void checkInteractAcrossUsersPermission(String message) {
1557 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1558 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1559 }
1560
felipeal2d0483c2019-11-02 14:07:22 -07001561 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001562 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001563 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1564 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001565 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001566 }
1567 }
1568
felipeal2d0483c2019-11-02 14:07:22 -07001569 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1570 for (String permission : permissions) {
1571 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1572 /* exported = */ true)
1573 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1574 return true;
1575 }
1576 }
1577 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001578 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001579
1580 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1581 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1582 // Count all users that are managed profiles of the given user.
1583 int managedProfilesCount = 0;
1584 for (UserInfo user : users) {
1585 if (user.isManagedProfile() && user.profileGroupId == userId) {
1586 managedProfilesCount++;
1587 }
1588 }
1589 return managedProfilesCount;
1590 }
1591
1592 /**
1593 * Starts the first passenger of the given driver and assigns the passenger to the front
1594 * passenger zone.
1595 *
1596 * @param driverId User id of the driver.
1597 * @return whether it succeeds.
1598 */
1599 private boolean startFirstPassenger(@UserIdInt int driverId) {
1600 int zoneId = getAvailablePassengerZone();
1601 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1602 Log.w(TAG_USER, "passenger occupant zone is not found");
1603 return false;
1604 }
1605 List<UserInfo> passengers = getPassengers(driverId);
1606 if (passengers.size() < 1) {
1607 Log.w(TAG_USER, "passenger is not found");
1608 return false;
1609 }
1610 // Only one passenger is supported. If there are two or more passengers, the first passenger
1611 // is chosen.
1612 int passengerId = passengers.get(0).id;
1613 if (!startPassenger(passengerId, zoneId)) {
1614 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1615 return false;
1616 }
1617 return true;
1618 }
1619
1620 private int getAvailablePassengerZone() {
1621 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1622 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1623 for (int occupantType : occupantTypes) {
1624 int zoneId = getZoneId(occupantType);
1625 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1626 return zoneId;
1627 }
1628 }
1629 return OccupantZoneInfo.INVALID_ZONE_ID;
1630 }
1631
1632 /**
1633 * Creates a new passenger user when there is no passenger user.
1634 */
1635 private void setupPassengerUser() {
1636 int currentUser = ActivityManager.getCurrentUser();
1637 int profileCount = getNumberOfManagedProfiles(currentUser);
1638 if (profileCount > 0) {
1639 Log.w(TAG_USER, "max profile of user" + currentUser
1640 + " is exceeded: current profile count is " + profileCount);
1641 return;
1642 }
1643 // TODO(b/140311342): Use resource string for the default passenger name.
1644 UserInfo passenger = createPassenger("Passenger", currentUser);
1645 if (passenger == null) {
1646 // Couldn't create user, most likely because there are too many.
1647 Log.w(TAG_USER, "cannot create a passenger user");
1648 return;
1649 }
1650 }
1651
1652 @NonNull
1653 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1654 ZoneUserBindingHelper helper = null;
1655 synchronized (mLockHelper) {
1656 if (mZoneUserBindingHelper == null) {
1657 Log.w(TAG_USER, "implementation is not delegated");
1658 return new ArrayList<OccupantZoneInfo>();
1659 }
1660 helper = mZoneUserBindingHelper;
1661 }
1662 return helper.getOccupantZones(occupantType);
1663 }
1664
1665 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1666 ZoneUserBindingHelper helper = null;
1667 synchronized (mLockHelper) {
1668 if (mZoneUserBindingHelper == null) {
1669 Log.w(TAG_USER, "implementation is not delegated");
1670 return false;
1671 }
1672 helper = mZoneUserBindingHelper;
1673 }
1674 return helper.assignUserToOccupantZone(userId, zoneId);
1675 }
1676
1677 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1678 ZoneUserBindingHelper helper = null;
1679 synchronized (mLockHelper) {
1680 if (mZoneUserBindingHelper == null) {
1681 Log.w(TAG_USER, "implementation is not delegated");
1682 return false;
1683 }
1684 helper = mZoneUserBindingHelper;
1685 }
1686 return helper.unassignUserFromOccupantZone(userId);
1687 }
1688
1689 private boolean isPassengerDisplayAvailable() {
1690 ZoneUserBindingHelper helper = null;
1691 synchronized (mLockHelper) {
1692 if (mZoneUserBindingHelper == null) {
1693 Log.w(TAG_USER, "implementation is not delegated");
1694 return false;
1695 }
1696 helper = mZoneUserBindingHelper;
1697 }
1698 return helper.isPassengerDisplayAvailable();
1699 }
1700
1701 /**
1702 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1703 * zone is returned.
1704 *
1705 * @param occupantType The type of an occupant.
1706 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1707 * if not found.
1708 */
1709 private int getZoneId(@OccupantTypeEnum int occupantType) {
1710 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1711 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1712 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001713}