blob: fc3d3a436177de379333487003c9a6f040324bb4 [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;
Felipe Lemeaba246c2020-05-11 15:02:52 -070042import android.car.userlib.UserHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070043import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070044import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070045import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070046import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070047import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080048import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070049import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070050import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
51import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070052import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
53import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080054import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070055import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070056import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080057import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070058import android.os.Handler;
59import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070060import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080061import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070062import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070063import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070064import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070065import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070066import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070067import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070068import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080069import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080070import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070071
72import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070073import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070074import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080075import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080076import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070077import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070078import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070079import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080080import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070081import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070082import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070083import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070084import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070085
86import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080087import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070088import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070089import java.util.Iterator;
90import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000091import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070092import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070093import java.util.concurrent.CountDownLatch;
94import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070095
96/**
97 * User service for cars. Manages users at boot time. Including:
98 *
99 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700100 * <li> Creates a user used as driver.
101 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700102 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700103 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700104 * <ol/>
105 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700106public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800107
felipealf7368962020-04-16 12:55:19 -0700108 private static final String TAG = TAG_USER;
109
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800110 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700111 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800112 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700113 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800114 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700115 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800116 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700117 public static final String BUNDLE_INITIAL_INFO_ACTION =
118 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800119
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700120 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700121 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700122 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700123 private final UserManager mUserManager;
124 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700125 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700126
Eric Jeongc91f9452019-08-30 15:04:21 -0700127 private final Object mLockUser = new Object();
128 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800129 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700130 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800131 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700132 // Only one passenger is supported.
133 @GuardedBy("mLockUser")
134 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700135 /**
136 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800137 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700138 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700139 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700140 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
141 /**
142 * Keep the list of background users started here. This is wholly for debugging purpose.
143 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700144 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700145 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
146
Felipe Leme58412202020-01-09 13:45:33 -0800147 private final UserHalService mHal;
148
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700149 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700150 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
151 getClass().getSimpleName());
152 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700153
Felipe Leme5528ff72020-02-10 19:05:14 -0800154 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800155 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700156 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800157 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700158 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800159
160 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800161 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700162 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800163 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700164 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800165
Mayank Garg7a114c82020-04-08 21:25:06 -0700166 /**
167 * User Id for the user switch in process, if any.
168 */
169 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700170 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700171 /**
172 * Request Id for the user switch in process, if any.
173 */
174 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700175 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700176 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
177
Eric Jeongc91f9452019-08-30 15:04:21 -0700178 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
179 new CopyOnWriteArrayList<>();
180
felipeal61ce3732020-04-03 11:01:00 -0700181 @Nullable
182 @GuardedBy("mLockUser")
183 private UserInfo mInitialUser;
184
Mayank Garg71661ea2020-04-29 01:25:03 -0700185 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700186
Mayank Garg587f1942020-05-06 01:41:34 -0700187 private IResultReceiver mUserSwitchUiReceiver;
188
Eric Jeongc91f9452019-08-30 15:04:21 -0700189 /** Interface for callbaks related to passenger activities. */
190 public interface PassengerCallback {
191 /** Called when passenger is started at a certain zone. */
192 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
193 /** Called when passenger is stopped. */
194 void onPassengerStopped(@UserIdInt int passengerId);
195 }
196
197 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
198 public interface ZoneUserBindingHelper {
199 /** Gets occupant zones corresponding to the occupant type. */
200 @NonNull
201 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
202 /** Assigns the user to the occupant zone. */
203 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
204 /** Makes the occupant zone unoccupied. */
205 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
206 /** Returns whether there is a passenger display. */
207 boolean isPassengerDisplayAvailable();
208 }
209
210 private final Object mLockHelper = new Object();
211 @GuardedBy("mLockHelper")
212 private ZoneUserBindingHelper mZoneUserBindingHelper;
213
Felipe Leme58412202020-01-09 13:45:33 -0800214 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700215 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
216 @NonNull IActivityManager am, int maxRunningUsers) {
217 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
218 new UserMetrics());
219 }
220
221 @VisibleForTesting
222 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
223 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
224 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700225 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
226 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700227 }
228 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800229 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700230 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700231 mAm = am;
232 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700233 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700234 mLastPassengerId = UserHandle.USER_NULL;
235 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700236 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700237 }
238
239 @Override
240 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700241 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
242 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700243 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700244 }
245
246 @Override
247 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
249 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700250 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700251 }
252
253 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700254 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700255 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700256 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800257 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700258 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700259 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700260 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700261 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700262 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
263 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700264 }
265 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
266 List<UserInfo> allDrivers = getAllDrivers();
267 int driversSize = allDrivers.size();
268 writer.println("NumberOfDrivers: " + driversSize);
269 for (int i = 0; i < driversSize; i++) {
270 int driverId = allDrivers.get(i).id;
271 writer.print(indent + "#" + i + ": id=" + driverId);
272 List<UserInfo> passengers = getPassengers(driverId);
273 int passengersSize = passengers.size();
274 writer.print(" NumberPassengers: " + passengersSize);
275 if (passengersSize > 0) {
276 writer.print(" [");
277 for (int j = 0; j < passengersSize; j++) {
278 writer.print(passengers.get(j).id);
279 if (j < passengersSize - 1) {
280 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700281 }
felipeal2d0483c2019-11-02 14:07:22 -0700282 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700283 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700284 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700285 writer.println();
286 }
287 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
288 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
289 writer.printf("Initial user: %s\n", mInitialUser);
290 writer.println("Relevant overlayable properties");
291 Resources res = mContext.getResources();
292 writer.printf("%sowner_name=%s\n", indent,
293 res.getString(com.android.internal.R.string.owner_name));
294 writer.printf("%sdefault_guest_name=%s\n", indent,
295 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700296 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700297 writer.printf("Request Id for the user switch in process=%d\n ",
298 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700299
300 dumpUserMetrics(writer);
301 }
302
303 /**
304 * Dumps user metrics.
305 */
306 public void dumpUserMetrics(@NonNull PrintWriter writer) {
307 mUserMetrics.dump(writer);
308 }
309
310 /**
311 * Dumps first user unlocking time.
312 */
313 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
314 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700315 }
316
317 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
318 CountDownLatch latch = new CountDownLatch(1);
319 mHandler.post(() -> {
320 handleDumpUserLifecycleListeners(writer);
321 handleDumpAppLifecycleListeners(writer, indent);
322 latch.countDown();
323 });
324 int timeout = 5;
325 try {
326 if (!latch.await(timeout, TimeUnit.SECONDS)) {
327 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
328 timeout);
329 }
330 } catch (InterruptedException e) {
331 Thread.currentThread().interrupt();
332 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
333 }
334 }
335
336 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
337 if (mUserLifecycleListeners.isEmpty()) {
338 writer.println("No user lifecycle listeners");
339 return;
340 }
341 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
342 for (UserLifecycleListener listener : mUserLifecycleListeners) {
343 writer.printf("Listener %s\n", listener);
344 }
345 }
346
347 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
348 int numberListeners = mAppLifecycleListeners.size();
349 if (numberListeners == 0) {
350 writer.println("No lifecycle listeners");
351 return;
352 }
353 writer.printf("%d lifecycle listeners\n", numberListeners);
354 for (int i = 0; i < numberListeners; i++) {
355 int uid = mAppLifecycleListeners.keyAt(i);
356 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
357 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800358 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700359 }
360
361 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800362 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
363 *
364 * @param name The name of the driver to be created.
365 * @param admin Whether the created driver will be an admin.
366 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
367 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700368 */
369 @Override
370 @Nullable
371 public UserInfo createDriver(@NonNull String name, boolean admin) {
372 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000373 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700374 if (admin) {
375 return createNewAdminUser(name);
376 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700377 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700378 }
379
380 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800381 * Creates a passenger who is a profile of the given driver.
382 *
383 * @param name The name of the passenger to be created.
384 * @param driverId User id of the driver under whom a passenger is created.
385 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
386 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700387 */
388 @Override
389 @Nullable
390 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
391 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000392 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700393 UserInfo driver = mUserManager.getUserInfo(driverId);
394 if (driver == null) {
395 Log.w(TAG_USER, "the driver is invalid");
396 return null;
397 }
398 if (driver.isGuest()) {
399 Log.w(TAG_USER, "a guest driver cannot create a passenger");
400 return null;
401 }
Bookatz42fb1a62019-10-30 11:45:01 -0700402 UserInfo user = mUserManager.createProfileForUser(name,
403 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700404 if (user == null) {
405 // Couldn't create user, most likely because there are too many.
406 Log.w(TAG_USER, "can't create a profile for user" + driverId);
407 return null;
408 }
409 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700410 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700411 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700412 return user;
413 }
414
415 /**
416 * @see CarUserManager.switchDriver
417 */
418 @Override
419 public boolean switchDriver(@UserIdInt int driverId) {
420 checkManageUsersPermission("switchDriver");
421 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
422 // System user doesn't associate with real person, can not be switched to.
423 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
424 return false;
425 }
426 int userSwitchable = mUserManager.getUserSwitchability();
427 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
428 Log.w(TAG_USER, "current process is not allowed to switch user");
429 return false;
430 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700431 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700432 // The current user is already the given user.
433 return true;
434 }
435 try {
436 return mAm.switchUser(driverId);
437 } catch (RemoteException e) {
438 // ignore
439 Log.w(TAG_USER, "error while switching user", e);
440 }
441 return false;
442 }
443
444 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800445 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
446 *
447 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700448 */
449 @Override
450 @NonNull
451 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700452 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700453 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700454 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700455 }
456
457 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800458 * Returns all passengers under the given driver.
459 *
460 * @param driverId User id of a driver.
461 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700462 */
463 @Override
464 @NonNull
465 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700466 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700467 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700468 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
469 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700470 });
471 }
472
473 /**
474 * @see CarUserManager.startPassenger
475 */
476 @Override
477 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
478 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700479 synchronized (mLockUser) {
480 try {
481 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
482 Log.w(TAG_USER, "could not start passenger");
483 return false;
484 }
485 } catch (RemoteException e) {
486 // ignore
487 Log.w(TAG_USER, "error while starting passenger", e);
488 return false;
489 }
490 if (!assignUserToOccupantZone(passengerId, zoneId)) {
491 Log.w(TAG_USER, "could not assign passenger to zone");
492 return false;
493 }
494 mLastPassengerId = passengerId;
495 }
496 for (PassengerCallback callback : mPassengerCallbacks) {
497 callback.onPassengerStarted(passengerId, zoneId);
498 }
499 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700500 }
501
502 /**
503 * @see CarUserManager.stopPassenger
504 */
505 @Override
506 public boolean stopPassenger(@UserIdInt int passengerId) {
507 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700508 return stopPassengerInternal(passengerId, true);
509 }
510
511 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
512 synchronized (mLockUser) {
513 UserInfo passenger = mUserManager.getUserInfo(passengerId);
514 if (passenger == null) {
515 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
516 return false;
517 }
518 if (mLastPassengerId != passengerId) {
519 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
520 return true;
521 }
522 if (checkCurrentDriver) {
523 int currentUser = ActivityManager.getCurrentUser();
524 if (passenger.profileGroupId != currentUser) {
525 Log.w(TAG_USER, "passenger " + passengerId
526 + " is not a profile of the current user");
527 return false;
528 }
529 }
530 // Passenger is a profile, so cannot be stopped through activity manager.
531 // Instead, activities started by the passenger are stopped and the passenger is
532 // unassigned from the zone.
533 stopAllTasks(passengerId);
534 if (!unassignUserFromOccupantZone(passengerId)) {
535 Log.w(TAG_USER, "could not unassign user from occupant zone");
536 return false;
537 }
538 mLastPassengerId = UserHandle.USER_NULL;
539 }
540 for (PassengerCallback callback : mPassengerCallbacks) {
541 callback.onPassengerStopped(passengerId);
542 }
543 return true;
544 }
545
546 private void stopAllTasks(@UserIdInt int userId) {
547 try {
548 for (StackInfo info : mAm.getAllStackInfos()) {
549 for (int i = 0; i < info.taskIds.length; i++) {
550 if (info.taskUserIds[i] == userId) {
551 int taskId = info.taskIds[i];
552 if (!mAm.removeTask(taskId)) {
553 Log.w(TAG_USER, "could not remove task " + taskId);
554 }
555 }
556 }
557 }
558 } catch (RemoteException e) {
559 Log.e(TAG_USER, "could not get stack info", e);
560 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700561 }
562
Felipe Leme5528ff72020-02-10 19:05:14 -0800563 @Override
564 public void setLifecycleListenerForUid(IResultReceiver listener) {
565 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700566 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800567 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
568
569 try {
570 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
571 } catch (RemoteException e) {
572 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
573 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700574 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800575 }
576
577 private void onListenerDeath(int uid) {
578 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700579 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800580 }
581
582 @Override
583 public void resetLifecycleListenerForUid() {
584 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700585 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800586 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700587 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800588 }
589
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800590 @Override
591 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800592 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700593 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
594 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800595 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700596 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800597 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800598 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700599 Bundle resultData = null;
600 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700601 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
602 status, resp.action, resp.userToSwitchOrCreate.userId,
603 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700604 switch (resp.action) {
605 case InitialUserInfoResponseAction.SWITCH:
606 resultData = new Bundle();
607 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
608 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
609 break;
610 case InitialUserInfoResponseAction.CREATE:
611 resultData = new Bundle();
612 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
613 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
614 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
615 break;
616 case InitialUserInfoResponseAction.DEFAULT:
617 resultData = new Bundle();
618 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
619 break;
620 default:
621 // That's ok, it will be the same as DEFAULT...
622 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800623 }
felipeal312416a2020-04-14 12:28:24 -0700624 } else {
625 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800626 }
Mayank Garg0e239142020-04-14 19:16:31 -0700627 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800628 });
629 }
630
Felipe Lemee3cab982020-03-12 11:39:29 -0700631 /**
felipeal61ce3732020-04-03 11:01:00 -0700632 * Gets the initial foreground user after the device boots or resumes from suspension.
633 *
634 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
635 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
636 * method returns {@code null}.
637 *
638 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
639 * (like switching to the last active user), and this method will return the result of such
640 * operation.
641 *
642 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
643 * {@code null}.
644 *
645 * @hide
646 */
647 @Nullable
648 public UserInfo getInitialUser() {
649 checkInteractAcrossUsersPermission("getInitialUser");
650 synchronized (mLockUser) {
651 return mInitialUser;
652 }
653 }
654
655 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
656 // some reason passing the whole UserInfo through a raw binder transaction is not working.
657 /**
658 * Sets the initial foreground user after the device boots or resumes from suspension.
659 */
660 public void setInitialUser(@UserIdInt int userId) {
661 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
662 : mUserManager.getUserInfo(userId);
663 setInitialUser(initialUser);
664 }
665
666 /**
667 * Sets the initial foreground user after the device boots or resumes from suspension.
668 */
669 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700670 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
671 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700672 synchronized (mLockUser) {
673 mInitialUser = user;
674 }
675 if (user == null) {
676 // This mean InitialUserSetter failed and could not fallback, so the initial user was
677 // not switched (and most likely is SYSTEM_USER).
678 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
679 Log.wtf(TAG_USER, "Initial user set to null");
680 }
681 }
682
683 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700684 * Calls the User HAL to get the initial user info.
685 *
686 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
687 * @param callback callback to receive the results.
688 */
689 public void getInitialUserInfo(int requestType,
690 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700691 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
692 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700693 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700694 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700695 UsersInfo usersInfo = getUsersInfo();
696 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
697 }
698
699 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700700 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
701 *
702 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700703 * When everything works well, the workflow is:
704 * <ol>
705 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
706 * type, current user id, target user id, and a callback.
707 * <li> HAL called back with SUCCESS.
708 * <li> {@link IActivityManager} is called for Android user switch.
709 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
710 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
711 * request type, current user id, and target user id. In this case, the current and target
712 * user IDs would be same.
713 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700714 *
715 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700716 * Corner cases:
717 * <ul>
718 * <li> If target user is already the current user, no user switch is performed and receiver
719 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
720 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
721 * {@code STATUS_HAL_INTERNAL_FAILURE}.
722 * <li> If HAL user switch call is successful, but android user switch call fails,
723 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
724 * target user id, but in this case the current and target user IDs would be different.
725 * <li> If another user switch request for the same target user is received while previous
726 * request is in process, receiver would receive
727 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
728 * <li> If a user switch request is received while another user switch request for different
729 * target user is in process, the previous request would be abandoned and new request will be
730 * processed. No POST_SWITCH would be sent for the previous request.
731 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700732 *
Mayank Garge19c2922020-03-30 18:05:53 -0700733 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700734 * @param timeoutMs - timeout for HAL to wait
735 * @param receiver - receiver for the results
736 */
Mayank Garge19c2922020-03-30 18:05:53 -0700737 @Override
738 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700739 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700740 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700741 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700742 Objects.requireNonNull(receiver);
743 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700744 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700745
felipealf7368962020-04-16 12:55:19 -0700746 int currentUser = ActivityManager.getCurrentUser();
747 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700748 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
749 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
750 }
felipeale5bf0322020-04-16 15:10:57 -0700751 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
752 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700753 return;
754 }
755
Mayank Garg7a114c82020-04-08 21:25:06 -0700756 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700757 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
758 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
759 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
760 }
761
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700762 // If there is another request for the same target user, return another request in
763 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
764 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
765 // user switch request in process for different target user, but that request is now
766 // ignored.
felipealf7368962020-04-16 12:55:19 -0700767 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700768 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
769 Log.d(TAG_USER,
770 "Another user switch request in process for the requested target user: "
771 + targetUserId);
772 }
773
774 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700775 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700776 return;
777 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700778 else {
779 mUserIdForUserSwitchInProcess = targetUserId;
780 mRequestIdForUserSwitchInProcess = 0;
781 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700782 }
783
Mayank Garg59f22192020-03-27 00:51:45 -0700784 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700785 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700786 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700787 halTargetUser.userId = targetUser.id;
788 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
789 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700790 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
791 Log.d(TAG, "switch response: status="
792 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
793 }
794
felipeale5bf0322020-04-16 15:10:57 -0700795 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700796
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700797 synchronized (mLockUser) {
798 if (status != HalCallback.STATUS_OK) {
799 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
800 Log.w(TAG, "invalid callback status ("
801 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
802 + resp);
803 sendResult(receiver, resultStatus);
804 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
805 return;
806 }
felipealf7368962020-04-16 12:55:19 -0700807
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700808 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
809 resp.errorMessage);
810
811 if (mUserIdForUserSwitchInProcess != targetUserId) {
812 // Another user switch request received while HAL responded. No need to process
813 // this request further
814 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
815 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
816 + "abondoned for : " + targetUserId + ". Current user in process: "
817 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700818 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700819 resultStatus =
820 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
821 sendResult(receiver, resultStatus);
822 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
823 return;
824 }
825
826 switch (resp.status) {
827 case SwitchUserStatus.SUCCESS:
828 boolean switched;
829 try {
830 switched = mAm.switchUser(targetUserId);
831 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700832 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700833 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
834 mRequestIdForUserSwitchInProcess = resp.requestId;
835 } else {
836 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
837 postSwitchHalResponse(resp.requestId, targetUserId);
838 }
839 } catch (RemoteException e) {
840 // ignore
841 Log.w(TAG_USER,
842 "error while switching user " + targetUser.toFullString(), e);
843 }
844 break;
845 case SwitchUserStatus.FAILURE:
846 // HAL failed to switch user
847 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
848 break;
849 }
850
851 if (mRequestIdForUserSwitchInProcess == 0) {
852 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
853 }
Mayank Garg59f22192020-03-27 00:51:45 -0700854 }
felipeale5bf0322020-04-16 15:10:57 -0700855 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700856 });
857 }
858
Mayank Garg587f1942020-05-06 01:41:34 -0700859 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
860 if (mUserSwitchUiReceiver == null) {
861 Log.w(TAG_USER, "No User switch UI receiver.");
862 return;
863 }
864
865 try {
866 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
867 mUserSwitchUiReceiver.send(targetUserId, null);
868 } catch (RemoteException e) {
869 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
870 }
871 }
872
felipeal5e3ede42020-04-23 18:04:07 -0700873 @Override
felipeal159a2a42020-05-08 10:32:11 -0700874 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
felipeal5e3ede42020-04-23 18:04:07 -0700875 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
876 checkManageUsersPermission("getUserIdentificationAssociation");
877
878 int uid = getCallingUid();
879 int userId = UserHandle.getUserId(uid);
880 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
881
882 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
883 request.userInfo.userId = userId;
884 request.userInfo.flags = getHalUserInfoFlags(userId);
885
886 request.numberAssociationTypes = types.length;
887 for (int i = 0; i < types.length; i++) {
888 request.associationTypes.add(types[i]);
889 }
890
891 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
892 if (halResponse == null) {
893 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
894 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -0700895 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -0700896 }
897
898 int[] values = new int[halResponse.associations.size()];
899 for (int i = 0; i < values.length; i++) {
900 values[i] = halResponse.associations.get(i).value;
901 }
902 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
903
felipeal159a2a42020-05-08 10:32:11 -0700904 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
905 }
906
907 @Override
908 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
909 AndroidFuture<UserIdentificationAssociationResponse> result) {
910 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
911 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
912 if (types.length != values.length) {
913 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
914 + Arrays.toString(values) + ") should have the same length");
915 }
916 checkManageUsersPermission("setUserIdentificationAssociation");
917
918 int uid = getCallingUid();
919 int userId = UserHandle.getUserId(uid);
920 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
921
922 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
923 request.userInfo.userId = userId;
924 request.userInfo.flags = getHalUserInfoFlags(userId);
925
926 request.numberAssociations = types.length;
927 for (int i = 0; i < types.length; i++) {
928 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
929 association.type = types[i];
930 association.value = values[i];
931 request.associations.add(association);
932 }
933
934 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
935 if (status != HalCallback.STATUS_OK) {
936 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
937 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
938 + resp);
939 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
940 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
941 result.complete(UserIdentificationAssociationResponse.forFailure());
942 return;
943 }
944 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
945 resp.errorMessage);
946 result.complete(
947 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
948 return;
949 }
950 int respSize = resp.associations.size();
951 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
952 resp.errorMessage);
953
954 int[] responseTypes = new int[respSize];
955 for (int i = 0; i < respSize; i++) {
956 responseTypes[i] = resp.associations.get(i).value;
957 }
958 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
959 .forSuccess(responseTypes, resp.errorMessage);
960 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
961 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
962 + ", converted=" + response);
963 }
964 result.complete(response);
965 });
felipeal5e3ede42020-04-23 18:04:07 -0700966 }
967
968 /**
969 * Gets the User HAL flags for the given user.
970 *
971 * @throws IllegalArgumentException if the user does not exist.
972 */
973 private int getHalUserInfoFlags(@UserIdInt int userId) {
974 UserInfo user = mUserManager.getUserInfo(userId);
975 Preconditions.checkArgument(user != null, "no user for id %d", userId);
976 return UserHalHelper.convertFlags(user);
977 }
978
Mayank Garg0e239142020-04-14 19:16:31 -0700979 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
980 @Nullable Bundle resultData) {
981 try {
982 receiver.send(resultCode, resultData);
983 } catch (RemoteException e) {
984 // ignore
985 Log.w(TAG_USER, "error while sending results", e);
986 }
987 }
988
felipeale5bf0322020-04-16 15:10:57 -0700989 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
990 @UserSwitchResult.Status int status) {
991 sendResult(receiver, status, /* errorMessage= */ null);
992 }
993
994 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
995 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
996 receiver.complete(new UserSwitchResult(status, errorMessage));
997 }
998
Mayank Garg6307fe42020-04-15 23:09:03 -0700999 /**
1000 * Calls activity manager for user switch.
1001 *
1002 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1003 *
1004 * @param requestId for the user switch request
1005 * @param targetUserId of the target user
1006 *
1007 * @hide
1008 */
1009 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1010 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1011 targetUserId);
1012 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1013
1014 try {
1015 boolean result = mAm.switchUser(targetUserId);
1016 if (result) {
1017 updateUserSwitchInProcess(requestId, targetUserId);
1018 } else {
1019 postSwitchHalResponse(requestId, targetUserId);
1020 }
1021 } catch (RemoteException e) {
1022 // ignore
1023 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1024 }
1025 }
1026
1027 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1028 synchronized (mLockUser) {
1029 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1030 // Some other user switch is in process.
1031 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1032 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1033 + " is in process. Abandoning it as a new user switch is requested"
1034 + " for the target user: " + targetUserId);
1035 }
1036 }
1037 mUserIdForUserSwitchInProcess = targetUserId;
1038 mRequestIdForUserSwitchInProcess = requestId;
1039 }
1040 }
1041
Mayank Garg7a114c82020-04-08 21:25:06 -07001042 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
1043 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
1044 UsersInfo usersInfo = getUsersInfo();
1045 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1046 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1047 halTargetUser.userId = targetUser.id;
1048 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -07001049 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1050 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001051 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
1052 }
1053
Mayank Garg59f22192020-03-27 00:51:45 -07001054 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001055 * Checks if the User HAL is supported.
1056 */
1057 public boolean isUserHalSupported() {
1058 return mHal.isSupported();
1059 }
1060
Mayank Garg587f1942020-05-06 01:41:34 -07001061 /**
1062 * Sets a callback which is invoked before user switch.
1063 *
1064 * <p>
1065 * This method should only be called by the Car System UI. The purpose of this call is to notify
1066 * Car System UI to show the user switch UI before the user switch.
1067 */
1068 @Override
1069 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
1070 // TODO(b/154958003): check UID, only carSysUI should be allowed to set it.
Yan Zhu67a383e2020-05-11 20:46:24 -07001071 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garg587f1942020-05-06 01:41:34 -07001072 mUserSwitchUiReceiver = receiver;
1073 }
1074
felipeal159a2a42020-05-08 10:32:11 -07001075 // TODO(b/150413515): use helper to generate UsersInfo
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001076 private UsersInfo getUsersInfo() {
1077 UserInfo currentUser;
1078 try {
1079 currentUser = mAm.getCurrentUser();
1080 } catch (RemoteException e) {
1081 // shouldn't happen
1082 throw new IllegalStateException("Could not get current user: ", e);
1083 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001084 return getUsersInfo(currentUser);
1085 }
1086
felipeal159a2a42020-05-08 10:32:11 -07001087 // TODO(b/150413515): use helper to generate UsersInfo
Mayank Garge5de0f92020-04-23 21:38:38 -07001088 private UsersInfo getUsersInfo(@NonNull UserInfo currentUser) {
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001089 List<UserInfo> existingUsers = mUserManager.getUsers();
1090 int size = existingUsers.size();
1091
1092 UsersInfo usersInfo = new UsersInfo();
1093 usersInfo.numberUsers = size;
1094 usersInfo.currentUser.userId = currentUser.id;
1095 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
1096
1097 for (int i = 0; i < size; i++) {
1098 UserInfo androidUser = existingUsers.get(i);
1099 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1100 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1101 halUser.userId = androidUser.id;
1102 halUser.flags = UserHalHelper.convertFlags(androidUser);
1103 usersInfo.existingUsers.add(halUser);
1104 }
1105
1106 return usersInfo;
1107 }
1108
Keun young Park13a7a822019-04-04 15:53:08 -07001109 private void updateDefaultUserRestriction() {
1110 // We want to set restrictions on system and guest users only once. These are persisted
1111 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1112 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001113 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1114 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001115 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001116 // Only apply the system user restrictions if the system user is headless.
1117 if (UserManager.isHeadlessSystemUserMode()) {
1118 setSystemUserRestrictions();
1119 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001120 Settings.Global.putInt(mContext.getContentResolver(),
1121 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001122 }
1123
Eric Jeong1545f3b2019-09-16 13:56:52 -07001124 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001125 return !mUserManager.getUserInfo(userId).isEphemeral();
1126 }
1127
Antonio Kantekc8114752020-03-05 21:37:39 -08001128 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001129 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1130 */
1131 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1132 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001133 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001134 }
1135
1136 /**
1137 * Removes previously added {@link UserLifecycleListener}.
1138 */
1139 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1140 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001141 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001142 }
1143
Eric Jeongc91f9452019-08-30 15:04:21 -07001144 /** Adds callback to listen to passenger activity events. */
1145 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001146 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001147 mPassengerCallbacks.add(callback);
1148 }
1149
1150 /** Removes previously added callback to listen passenger events. */
1151 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001152 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001153 mPassengerCallbacks.remove(callback);
1154 }
1155
1156 /** Sets the implementation of ZoneUserBindingHelper. */
1157 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1158 synchronized (mLockHelper) {
1159 mZoneUserBindingHelper = helper;
1160 }
1161 }
1162
felipeal98900c82020-04-09 09:05:02 -07001163 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001164 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001165 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001166 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001167 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001168 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1169 updateDefaultUserRestriction();
1170 tasks = new ArrayList<>(mUser0UnlockTasks);
1171 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001172 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001173 }
1174 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001175 Integer user = userId;
1176 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001177 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001178 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001179 mBackgroundUsersToRestart.remove(user);
1180 mBackgroundUsersToRestart.add(0, user);
1181 }
1182 // -1 for user 0
1183 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001184 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001185 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001186 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001187 + ", dropping least recently user from restart list:" + userToDrop);
1188 // Drop the least recently used user.
1189 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1190 }
1191 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001192 }
1193 }
1194 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001195 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001196 for (Runnable r : tasks) {
1197 r.run();
1198 }
1199 }
1200 }
1201
1202 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001203 * Starts all background users that were active in system.
1204 *
Keun young Parkfb656372019-03-12 18:37:55 -07001205 * @return list of background users started successfully.
1206 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001207 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001208 public ArrayList<Integer> startAllBackgroundUsers() {
1209 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001210 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001211 users = new ArrayList<>(mBackgroundUsersToRestart);
1212 mBackgroundUsersRestartedHere.clear();
1213 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001214 }
1215 ArrayList<Integer> startedUsers = new ArrayList<>();
1216 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001217 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001218 continue;
1219 }
1220 try {
1221 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001222 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1223 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001224 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001225 } else if (mAm.unlockUser(user, null, null, null)) {
1226 startedUsers.add(user);
1227 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001228 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001229 if (mUserManager.isUserRunning(user)) {
1230 // add to started list so that it can be stopped later.
1231 startedUsers.add(user);
1232 }
Keun young Parkfb656372019-03-12 18:37:55 -07001233 }
1234 }
1235 } catch (RemoteException e) {
1236 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001237 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001238 }
1239 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001240 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001241 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001242 ArrayList<Integer> usersToRemove = new ArrayList<>();
1243 for (Integer user : mBackgroundUsersToRestart) {
1244 if (!startedUsers.contains(user)) {
1245 usersToRemove.add(user);
1246 }
1247 }
1248 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1249 }
Keun young Parkfb656372019-03-12 18:37:55 -07001250 return startedUsers;
1251 }
1252
1253 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001254 * Stops all background users that were active in system.
1255 *
1256 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001257 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001258 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001259 if (userId == UserHandle.USER_SYSTEM) {
1260 return false;
1261 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001262 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001263 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001264 return false;
1265 }
1266 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001267 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001268 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001269 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001270 Integer user = userId;
1271 mBackgroundUsersRestartedHere.remove(user);
1272 }
1273 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1274 return false;
1275 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001276 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001277 return false;
1278 }
1279 } catch (RemoteException e) {
1280 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001281 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001282 }
1283 return true;
1284 }
1285
1286 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001287 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001288 */
felipeale8c5dce2020-04-15 11:27:06 -07001289 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1290 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1291 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001292
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001293 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001294 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001295 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001296 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1297 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001298 }
1299
felipeale8c5dce2020-04-15 11:27:06 -07001300 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001301 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001302
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001303 mHandler.post(() -> {
1304 handleNotifyServiceUserLifecycleListeners(event);
1305 handleNotifyAppUserLifecycleListeners(event);
1306 });
felipeale8c5dce2020-04-15 11:27:06 -07001307
1308 // Finally, update metrics.
1309 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1310 }
1311
1312 /**
1313 * Sets the first user unlocking metrics.
1314 */
1315 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1316 int halResponseTime) {
1317 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001318 }
1319
Mayank Garg7a114c82020-04-08 21:25:06 -07001320 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001321 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001322 || mUserIdForUserSwitchInProcess != userId
1323 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001324 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1325 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1326 }
1327 return;
1328 }
felipealf7368962020-04-16 12:55:19 -07001329 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1330 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001331 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001332 }
1333
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001334 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1335 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001336 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001337 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1338 Log.d(TAG_USER, "No app listener to be notified of " + event);
1339 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001340 return;
1341 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001342 // Must use a different TimingsTraceLog because it's another thread
1343 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1344 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1345 }
felipeal2a84d512020-04-06 18:52:15 -07001346 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001347 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1348 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1349 for (int i = 0; i < listenersSize; i++) {
1350 int uid = mAppLifecycleListeners.keyAt(i);
1351 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1352 Bundle data = new Bundle();
1353 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001354
1355 int fromUid = event.getPreviousUserId();
1356 if (fromUid != UserHandle.USER_NULL) {
1357 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1358 }
1359
felipeal2a84d512020-04-06 18:52:15 -07001360 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001361 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001362 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001363 try {
felipeal2a84d512020-04-06 18:52:15 -07001364 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001365 listener.send(userId, data);
1366 } catch (RemoteException e) {
1367 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1368 } finally {
1369 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001370 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001371 }
1372 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001373 }
1374
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001375 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001376 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1377 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001378 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001379 return;
felipeal2a84d512020-04-06 18:52:15 -07001380 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1381 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1382 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001383 }
felipeal2a84d512020-04-06 18:52:15 -07001384
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001385 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1386 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001387 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001388 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001389 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001390 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001391 listener.onEvent(event);
1392 } catch (RuntimeException e) {
1393 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001394 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001395 } finally {
1396 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001397 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001398 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001399 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001400 }
1401
Mayank Garge5de0f92020-04-23 21:38:38 -07001402 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001403 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001404 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001405 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001406
Mayank Garge5de0f92020-04-23 21:38:38 -07001407 // Switch HAL users if user switch is not requested by CarUserService
1408 notifyHalLegacySwitch(fromUserId, toUserId);
1409
Felipe Lemeaba246c2020-05-11 15:02:52 -07001410 if (!UserHelper.isHeadlessSystemUser(toUserId)) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001411 mCarUserManagerHelper.setLastActiveUser(toUserId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001412 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001413 if (mLastPassengerId != UserHandle.USER_NULL) {
1414 stopPassengerInternal(mLastPassengerId, false);
1415 }
1416 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1417 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001418 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001419 }
felipeal98900c82020-04-09 09:05:02 -07001420 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001421 }
1422
Mayank Garge5de0f92020-04-23 21:38:38 -07001423 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1424 synchronized (mLockUser) {
1425 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1426 }
1427
1428 // switch HAL user
1429 UserInfo targetUser = mUserManager.getUserInfo(toUserId);
1430 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1431 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1432 halTargetUser.userId = targetUser.id;
1433 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
1434 UserInfo currentUser = mUserManager.getUserInfo(fromUserId);
1435 UsersInfo usersInfo = getUsersInfo(currentUser);
1436 mHal.legacyUserSwitch(halTargetUser, usersInfo);
1437 }
1438
Pavel Maltsev17e81832019-04-04 14:38:41 -07001439 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001440 * 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 -08001441 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001442 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001443 * @param r Runnable to run.
1444 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001445 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001446 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001447 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001448 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001449 if (mUser0Unlocked) {
1450 runNow = true;
1451 } else {
1452 mUser0UnlockTasks.add(r);
1453 }
1454 }
1455 if (runNow) {
1456 r.run();
1457 }
1458 }
1459
Keun young Parkf3523cd2019-04-08 10:09:17 -07001460 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001461 @NonNull
1462 ArrayList<Integer> getBackgroundUsersToRestart() {
1463 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001464 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001465 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1466 }
1467 return backgroundUsersToRestart;
1468 }
1469
Ying Zheng1ab32b62018-06-26 12:47:26 -07001470 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001471 // Disable Location service for system user.
1472 LocationManager locationManager =
1473 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001474 locationManager.setLocationEnabledForUser(
1475 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001476 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001477
1478 /**
1479 * Creates a new user on the system, the created user would be granted admin role.
1480 *
1481 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001482 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001483 */
1484 @Nullable
1485 private UserInfo createNewAdminUser(String name) {
1486 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1487 // Only admins or system user can create other privileged users.
1488 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1489 return null;
1490 }
1491
1492 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1493 if (user == null) {
1494 // Couldn't create user, most likely because there are too many.
1495 Log.w(TAG_USER, "can't create admin user.");
1496 return null;
1497 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001498 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001499
1500 return user;
1501 }
1502
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001503 /**
1504 * Assigns a default icon to a user according to the user's id.
1505 *
1506 * @param userInfo User whose avatar is set to default icon.
1507 * @return Bitmap of the user icon.
1508 */
1509 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1510 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1511 Bitmap bitmap = UserIcons.convertToBitmap(
1512 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1513 mUserManager.setUserIcon(userInfo.id, bitmap);
1514 return bitmap;
1515 }
1516
Eric Jeong1545f3b2019-09-16 13:56:52 -07001517 private interface UserFilter {
1518 boolean isEligibleUser(UserInfo user);
1519 }
1520
1521 /** Returns all users who are matched by the given filter. */
1522 private List<UserInfo> getUsers(UserFilter filter) {
1523 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1524
1525 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1526 UserInfo user = iterator.next();
1527 if (!filter.isEligibleUser(user)) {
1528 iterator.remove();
1529 }
1530 }
1531 return users;
1532 }
1533
1534 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001535 * Enforces that apps which have the
1536 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1537 * can make certain calls to the CarUserManager.
1538 *
1539 * @param message used as message if SecurityException is thrown.
1540 * @throws SecurityException if the caller is not system or root.
1541 */
1542 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001543 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1544 }
1545
1546 private static void checkManageUsersOrDumpPermission(String message) {
1547 checkAtLeastOnePermission(message,
1548 android.Manifest.permission.MANAGE_USERS,
1549 android.Manifest.permission.DUMP);
1550 }
1551
Felipe Leme5528ff72020-02-10 19:05:14 -08001552 private void checkInteractAcrossUsersPermission(String message) {
1553 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1554 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1555 }
1556
felipeal2d0483c2019-11-02 14:07:22 -07001557 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001558 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001559 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1560 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001561 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001562 }
1563 }
1564
felipeal2d0483c2019-11-02 14:07:22 -07001565 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1566 for (String permission : permissions) {
1567 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1568 /* exported = */ true)
1569 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1570 return true;
1571 }
1572 }
1573 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001574 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001575
1576 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1577 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1578 // Count all users that are managed profiles of the given user.
1579 int managedProfilesCount = 0;
1580 for (UserInfo user : users) {
1581 if (user.isManagedProfile() && user.profileGroupId == userId) {
1582 managedProfilesCount++;
1583 }
1584 }
1585 return managedProfilesCount;
1586 }
1587
1588 /**
1589 * Starts the first passenger of the given driver and assigns the passenger to the front
1590 * passenger zone.
1591 *
1592 * @param driverId User id of the driver.
1593 * @return whether it succeeds.
1594 */
1595 private boolean startFirstPassenger(@UserIdInt int driverId) {
1596 int zoneId = getAvailablePassengerZone();
1597 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1598 Log.w(TAG_USER, "passenger occupant zone is not found");
1599 return false;
1600 }
1601 List<UserInfo> passengers = getPassengers(driverId);
1602 if (passengers.size() < 1) {
1603 Log.w(TAG_USER, "passenger is not found");
1604 return false;
1605 }
1606 // Only one passenger is supported. If there are two or more passengers, the first passenger
1607 // is chosen.
1608 int passengerId = passengers.get(0).id;
1609 if (!startPassenger(passengerId, zoneId)) {
1610 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1611 return false;
1612 }
1613 return true;
1614 }
1615
1616 private int getAvailablePassengerZone() {
1617 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1618 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1619 for (int occupantType : occupantTypes) {
1620 int zoneId = getZoneId(occupantType);
1621 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1622 return zoneId;
1623 }
1624 }
1625 return OccupantZoneInfo.INVALID_ZONE_ID;
1626 }
1627
1628 /**
1629 * Creates a new passenger user when there is no passenger user.
1630 */
1631 private void setupPassengerUser() {
1632 int currentUser = ActivityManager.getCurrentUser();
1633 int profileCount = getNumberOfManagedProfiles(currentUser);
1634 if (profileCount > 0) {
1635 Log.w(TAG_USER, "max profile of user" + currentUser
1636 + " is exceeded: current profile count is " + profileCount);
1637 return;
1638 }
1639 // TODO(b/140311342): Use resource string for the default passenger name.
1640 UserInfo passenger = createPassenger("Passenger", currentUser);
1641 if (passenger == null) {
1642 // Couldn't create user, most likely because there are too many.
1643 Log.w(TAG_USER, "cannot create a passenger user");
1644 return;
1645 }
1646 }
1647
1648 @NonNull
1649 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1650 ZoneUserBindingHelper helper = null;
1651 synchronized (mLockHelper) {
1652 if (mZoneUserBindingHelper == null) {
1653 Log.w(TAG_USER, "implementation is not delegated");
1654 return new ArrayList<OccupantZoneInfo>();
1655 }
1656 helper = mZoneUserBindingHelper;
1657 }
1658 return helper.getOccupantZones(occupantType);
1659 }
1660
1661 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1662 ZoneUserBindingHelper helper = null;
1663 synchronized (mLockHelper) {
1664 if (mZoneUserBindingHelper == null) {
1665 Log.w(TAG_USER, "implementation is not delegated");
1666 return false;
1667 }
1668 helper = mZoneUserBindingHelper;
1669 }
1670 return helper.assignUserToOccupantZone(userId, zoneId);
1671 }
1672
1673 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1674 ZoneUserBindingHelper helper = null;
1675 synchronized (mLockHelper) {
1676 if (mZoneUserBindingHelper == null) {
1677 Log.w(TAG_USER, "implementation is not delegated");
1678 return false;
1679 }
1680 helper = mZoneUserBindingHelper;
1681 }
1682 return helper.unassignUserFromOccupantZone(userId);
1683 }
1684
1685 private boolean isPassengerDisplayAvailable() {
1686 ZoneUserBindingHelper helper = null;
1687 synchronized (mLockHelper) {
1688 if (mZoneUserBindingHelper == null) {
1689 Log.w(TAG_USER, "implementation is not delegated");
1690 return false;
1691 }
1692 helper = mZoneUserBindingHelper;
1693 }
1694 return helper.isPassengerDisplayAvailable();
1695 }
1696
1697 /**
1698 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1699 * zone is returned.
1700 *
1701 * @param occupantType The type of an occupant.
1702 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1703 * if not found.
1704 */
1705 private int getZoneId(@OccupantTypeEnum int occupantType) {
1706 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1707 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1708 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001709}