blob: 2f4337074684408328b82bbcf309ebfd48ec59cb [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;
felipeal5e3ede42020-04-23 18:04:07 -070036import android.car.user.GetUserIdentificationAssociationResponse;
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;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080051import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070052import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070053import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080054import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070055import android.os.Handler;
56import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070057import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080058import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070059import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070060import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070061import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070062import android.sysprop.CarProperties;
felipeal312416a2020-04-14 12:28:24 -070063import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070064import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080065import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080066import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070067
68import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070069import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070070import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080071import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080072import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070073import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070074import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070075import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080076import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070077import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070078import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070079import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070080import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081
82import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080083import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070084import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070085import java.util.Iterator;
86import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000087import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070088import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070089import java.util.concurrent.CountDownLatch;
90import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070091
92/**
93 * User service for cars. Manages users at boot time. Including:
94 *
95 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070096 * <li> Creates a user used as driver.
97 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070098 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070099 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700100 * <ol/>
101 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700102public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800103
felipealf7368962020-04-16 12:55:19 -0700104 private static final String TAG = TAG_USER;
105
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800106 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700107 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800108 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700109 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800110 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700111 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800112 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700113 public static final String BUNDLE_INITIAL_INFO_ACTION =
114 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800115
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700116 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700117 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700118 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700119 private final UserManager mUserManager;
120 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700121 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700122
Eric Jeongc91f9452019-08-30 15:04:21 -0700123 private final Object mLockUser = new Object();
124 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800125 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700126 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800127 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700128 // Only one passenger is supported.
129 @GuardedBy("mLockUser")
130 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700131 /**
132 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800133 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700134 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700135 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700136 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
137 /**
138 * Keep the list of background users started here. This is wholly for debugging purpose.
139 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700140 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700141 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
142
Felipe Leme58412202020-01-09 13:45:33 -0800143 private final UserHalService mHal;
144
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700145 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700146 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
147 getClass().getSimpleName());
148 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700149
Felipe Leme5528ff72020-02-10 19:05:14 -0800150 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800151 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700152 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800153 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700154 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800155
156 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800157 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700158 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800159 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700160 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800161
Mayank Garg7a114c82020-04-08 21:25:06 -0700162 /**
163 * User Id for the user switch in process, if any.
164 */
165 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700166 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700167 /**
168 * Request Id for the user switch in process, if any.
169 */
170 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700171 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700172 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
173
Eric Jeongc91f9452019-08-30 15:04:21 -0700174 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
175 new CopyOnWriteArrayList<>();
176
felipeal61ce3732020-04-03 11:01:00 -0700177 @Nullable
178 @GuardedBy("mLockUser")
179 private UserInfo mInitialUser;
180
Mayank Garg71661ea2020-04-29 01:25:03 -0700181 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700182
Eric Jeongc91f9452019-08-30 15:04:21 -0700183 /** Interface for callbaks related to passenger activities. */
184 public interface PassengerCallback {
185 /** Called when passenger is started at a certain zone. */
186 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
187 /** Called when passenger is stopped. */
188 void onPassengerStopped(@UserIdInt int passengerId);
189 }
190
191 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
192 public interface ZoneUserBindingHelper {
193 /** Gets occupant zones corresponding to the occupant type. */
194 @NonNull
195 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
196 /** Assigns the user to the occupant zone. */
197 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
198 /** Makes the occupant zone unoccupied. */
199 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
200 /** Returns whether there is a passenger display. */
201 boolean isPassengerDisplayAvailable();
202 }
203
204 private final Object mLockHelper = new Object();
205 @GuardedBy("mLockHelper")
206 private ZoneUserBindingHelper mZoneUserBindingHelper;
207
Felipe Leme58412202020-01-09 13:45:33 -0800208 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700209 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
210 @NonNull IActivityManager am, int maxRunningUsers) {
211 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
212 new UserMetrics());
213 }
214
215 @VisibleForTesting
216 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
217 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
218 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700219 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
220 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700221 }
222 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800223 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700224 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700225 mAm = am;
226 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700227 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700228 mLastPassengerId = UserHandle.USER_NULL;
229 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700230 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700231 }
232
233 @Override
234 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700235 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
236 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700237 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700238 }
239
240 @Override
241 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700242 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
243 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700244 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700245 }
246
247 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700249 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700250 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800251 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700252 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700253 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700254 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700255 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
256 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700257 }
258 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
259 List<UserInfo> allDrivers = getAllDrivers();
260 int driversSize = allDrivers.size();
261 writer.println("NumberOfDrivers: " + driversSize);
262 for (int i = 0; i < driversSize; i++) {
263 int driverId = allDrivers.get(i).id;
264 writer.print(indent + "#" + i + ": id=" + driverId);
265 List<UserInfo> passengers = getPassengers(driverId);
266 int passengersSize = passengers.size();
267 writer.print(" NumberPassengers: " + passengersSize);
268 if (passengersSize > 0) {
269 writer.print(" [");
270 for (int j = 0; j < passengersSize; j++) {
271 writer.print(passengers.get(j).id);
272 if (j < passengersSize - 1) {
273 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700274 }
felipeal2d0483c2019-11-02 14:07:22 -0700275 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700276 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700277 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700278 writer.println();
279 }
280 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
281 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
282 writer.printf("Initial user: %s\n", mInitialUser);
283 writer.println("Relevant overlayable properties");
284 Resources res = mContext.getResources();
285 writer.printf("%sowner_name=%s\n", indent,
286 res.getString(com.android.internal.R.string.owner_name));
287 writer.printf("%sdefault_guest_name=%s\n", indent,
288 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700289 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700290 writer.printf("Request Id for the user switch in process=%d\n ",
291 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700292
293 dumpUserMetrics(writer);
294 }
295
296 /**
297 * Dumps user metrics.
298 */
299 public void dumpUserMetrics(@NonNull PrintWriter writer) {
300 mUserMetrics.dump(writer);
301 }
302
303 /**
304 * Dumps first user unlocking time.
305 */
306 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
307 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700308 }
309
310 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
311 CountDownLatch latch = new CountDownLatch(1);
312 mHandler.post(() -> {
313 handleDumpUserLifecycleListeners(writer);
314 handleDumpAppLifecycleListeners(writer, indent);
315 latch.countDown();
316 });
317 int timeout = 5;
318 try {
319 if (!latch.await(timeout, TimeUnit.SECONDS)) {
320 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
321 timeout);
322 }
323 } catch (InterruptedException e) {
324 Thread.currentThread().interrupt();
325 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
326 }
327 }
328
329 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
330 if (mUserLifecycleListeners.isEmpty()) {
331 writer.println("No user lifecycle listeners");
332 return;
333 }
334 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
335 for (UserLifecycleListener listener : mUserLifecycleListeners) {
336 writer.printf("Listener %s\n", listener);
337 }
338 }
339
340 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
341 int numberListeners = mAppLifecycleListeners.size();
342 if (numberListeners == 0) {
343 writer.println("No lifecycle listeners");
344 return;
345 }
346 writer.printf("%d lifecycle listeners\n", numberListeners);
347 for (int i = 0; i < numberListeners; i++) {
348 int uid = mAppLifecycleListeners.keyAt(i);
349 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
350 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800351 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700352 }
353
354 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800355 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
356 *
357 * @param name The name of the driver to be created.
358 * @param admin Whether the created driver will be an admin.
359 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
360 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700361 */
362 @Override
363 @Nullable
364 public UserInfo createDriver(@NonNull String name, boolean admin) {
365 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000366 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700367 if (admin) {
368 return createNewAdminUser(name);
369 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700370 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700371 }
372
373 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800374 * Creates a passenger who is a profile of the given driver.
375 *
376 * @param name The name of the passenger to be created.
377 * @param driverId User id of the driver under whom a passenger is created.
378 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
379 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700380 */
381 @Override
382 @Nullable
383 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
384 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000385 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700386 UserInfo driver = mUserManager.getUserInfo(driverId);
387 if (driver == null) {
388 Log.w(TAG_USER, "the driver is invalid");
389 return null;
390 }
391 if (driver.isGuest()) {
392 Log.w(TAG_USER, "a guest driver cannot create a passenger");
393 return null;
394 }
Bookatz42fb1a62019-10-30 11:45:01 -0700395 UserInfo user = mUserManager.createProfileForUser(name,
396 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700397 if (user == null) {
398 // Couldn't create user, most likely because there are too many.
399 Log.w(TAG_USER, "can't create a profile for user" + driverId);
400 return null;
401 }
402 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700403 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700404 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700405 return user;
406 }
407
408 /**
409 * @see CarUserManager.switchDriver
410 */
411 @Override
412 public boolean switchDriver(@UserIdInt int driverId) {
413 checkManageUsersPermission("switchDriver");
414 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
415 // System user doesn't associate with real person, can not be switched to.
416 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
417 return false;
418 }
419 int userSwitchable = mUserManager.getUserSwitchability();
420 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
421 Log.w(TAG_USER, "current process is not allowed to switch user");
422 return false;
423 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700424 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700425 // The current user is already the given user.
426 return true;
427 }
428 try {
429 return mAm.switchUser(driverId);
430 } catch (RemoteException e) {
431 // ignore
432 Log.w(TAG_USER, "error while switching user", e);
433 }
434 return false;
435 }
436
437 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800438 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
439 *
440 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 */
442 @Override
443 @NonNull
444 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700445 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700446 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
447 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700448 }
449
450 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800451 * Returns all passengers under the given driver.
452 *
453 * @param driverId User id of a driver.
454 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700455 */
456 @Override
457 @NonNull
458 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700459 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700460 return getUsers((user) -> {
461 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
462 && user.profileGroupId == driverId;
463 });
464 }
465
466 /**
467 * @see CarUserManager.startPassenger
468 */
469 @Override
470 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
471 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700472 synchronized (mLockUser) {
473 try {
474 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
475 Log.w(TAG_USER, "could not start passenger");
476 return false;
477 }
478 } catch (RemoteException e) {
479 // ignore
480 Log.w(TAG_USER, "error while starting passenger", e);
481 return false;
482 }
483 if (!assignUserToOccupantZone(passengerId, zoneId)) {
484 Log.w(TAG_USER, "could not assign passenger to zone");
485 return false;
486 }
487 mLastPassengerId = passengerId;
488 }
489 for (PassengerCallback callback : mPassengerCallbacks) {
490 callback.onPassengerStarted(passengerId, zoneId);
491 }
492 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700493 }
494
495 /**
496 * @see CarUserManager.stopPassenger
497 */
498 @Override
499 public boolean stopPassenger(@UserIdInt int passengerId) {
500 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700501 return stopPassengerInternal(passengerId, true);
502 }
503
504 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
505 synchronized (mLockUser) {
506 UserInfo passenger = mUserManager.getUserInfo(passengerId);
507 if (passenger == null) {
508 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
509 return false;
510 }
511 if (mLastPassengerId != passengerId) {
512 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
513 return true;
514 }
515 if (checkCurrentDriver) {
516 int currentUser = ActivityManager.getCurrentUser();
517 if (passenger.profileGroupId != currentUser) {
518 Log.w(TAG_USER, "passenger " + passengerId
519 + " is not a profile of the current user");
520 return false;
521 }
522 }
523 // Passenger is a profile, so cannot be stopped through activity manager.
524 // Instead, activities started by the passenger are stopped and the passenger is
525 // unassigned from the zone.
526 stopAllTasks(passengerId);
527 if (!unassignUserFromOccupantZone(passengerId)) {
528 Log.w(TAG_USER, "could not unassign user from occupant zone");
529 return false;
530 }
531 mLastPassengerId = UserHandle.USER_NULL;
532 }
533 for (PassengerCallback callback : mPassengerCallbacks) {
534 callback.onPassengerStopped(passengerId);
535 }
536 return true;
537 }
538
539 private void stopAllTasks(@UserIdInt int userId) {
540 try {
541 for (StackInfo info : mAm.getAllStackInfos()) {
542 for (int i = 0; i < info.taskIds.length; i++) {
543 if (info.taskUserIds[i] == userId) {
544 int taskId = info.taskIds[i];
545 if (!mAm.removeTask(taskId)) {
546 Log.w(TAG_USER, "could not remove task " + taskId);
547 }
548 }
549 }
550 }
551 } catch (RemoteException e) {
552 Log.e(TAG_USER, "could not get stack info", e);
553 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700554 }
555
Felipe Leme5528ff72020-02-10 19:05:14 -0800556 @Override
557 public void setLifecycleListenerForUid(IResultReceiver listener) {
558 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700559 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800560 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
561
562 try {
563 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
564 } catch (RemoteException e) {
565 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
566 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700567 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800568 }
569
570 private void onListenerDeath(int uid) {
571 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700572 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800573 }
574
575 @Override
576 public void resetLifecycleListenerForUid() {
577 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700578 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800579 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700580 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800581 }
582
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800583 @Override
584 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800585 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700586 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
587 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800588 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700589 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800590 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800591 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700592 Bundle resultData = null;
593 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700594 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
595 status, resp.action, resp.userToSwitchOrCreate.userId,
596 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700597 switch (resp.action) {
598 case InitialUserInfoResponseAction.SWITCH:
599 resultData = new Bundle();
600 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
601 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
602 break;
603 case InitialUserInfoResponseAction.CREATE:
604 resultData = new Bundle();
605 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
606 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
607 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
608 break;
609 case InitialUserInfoResponseAction.DEFAULT:
610 resultData = new Bundle();
611 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
612 break;
613 default:
614 // That's ok, it will be the same as DEFAULT...
615 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800616 }
felipeal312416a2020-04-14 12:28:24 -0700617 } else {
618 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800619 }
Mayank Garg0e239142020-04-14 19:16:31 -0700620 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800621 });
622 }
623
Felipe Lemee3cab982020-03-12 11:39:29 -0700624 /**
felipeal61ce3732020-04-03 11:01:00 -0700625 * Gets the initial foreground user after the device boots or resumes from suspension.
626 *
627 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
628 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
629 * method returns {@code null}.
630 *
631 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
632 * (like switching to the last active user), and this method will return the result of such
633 * operation.
634 *
635 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
636 * {@code null}.
637 *
638 * @hide
639 */
640 @Nullable
641 public UserInfo getInitialUser() {
642 checkInteractAcrossUsersPermission("getInitialUser");
643 synchronized (mLockUser) {
644 return mInitialUser;
645 }
646 }
647
648 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
649 // some reason passing the whole UserInfo through a raw binder transaction is not working.
650 /**
651 * Sets the initial foreground user after the device boots or resumes from suspension.
652 */
653 public void setInitialUser(@UserIdInt int userId) {
654 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
655 : mUserManager.getUserInfo(userId);
656 setInitialUser(initialUser);
657 }
658
659 /**
660 * Sets the initial foreground user after the device boots or resumes from suspension.
661 */
662 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700663 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
664 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700665 synchronized (mLockUser) {
666 mInitialUser = user;
667 }
668 if (user == null) {
669 // This mean InitialUserSetter failed and could not fallback, so the initial user was
670 // not switched (and most likely is SYSTEM_USER).
671 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
672 Log.wtf(TAG_USER, "Initial user set to null");
673 }
674 }
675
676 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700677 * Calls the User HAL to get the initial user info.
678 *
679 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
680 * @param callback callback to receive the results.
681 */
682 public void getInitialUserInfo(int requestType,
683 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700684 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
685 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700686 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700687 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700688 UsersInfo usersInfo = getUsersInfo();
689 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
690 }
691
692 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700693 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
694 *
695 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700696 * When everything works well, the workflow is:
697 * <ol>
698 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
699 * type, current user id, target user id, and a callback.
700 * <li> HAL called back with SUCCESS.
701 * <li> {@link IActivityManager} is called for Android user switch.
702 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
703 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
704 * request type, current user id, and target user id. In this case, the current and target
705 * user IDs would be same.
706 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700707 *
708 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700709 * Corner cases:
710 * <ul>
711 * <li> If target user is already the current user, no user switch is performed and receiver
712 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
713 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
714 * {@code STATUS_HAL_INTERNAL_FAILURE}.
715 * <li> If HAL user switch call is successful, but android user switch call fails,
716 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
717 * target user id, but in this case the current and target user IDs would be different.
718 * <li> If another user switch request for the same target user is received while previous
719 * request is in process, receiver would receive
720 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
721 * <li> If a user switch request is received while another user switch request for different
722 * target user is in process, the previous request would be abandoned and new request will be
723 * processed. No POST_SWITCH would be sent for the previous request.
724 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700725 *
Mayank Garge19c2922020-03-30 18:05:53 -0700726 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700727 * @param timeoutMs - timeout for HAL to wait
728 * @param receiver - receiver for the results
729 */
Mayank Garge19c2922020-03-30 18:05:53 -0700730 @Override
731 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700732 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700733 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700734 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700735 Objects.requireNonNull(receiver);
736 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700737 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700738
felipealf7368962020-04-16 12:55:19 -0700739 int currentUser = ActivityManager.getCurrentUser();
740 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700741 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
742 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
743 }
felipeale5bf0322020-04-16 15:10:57 -0700744 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
745 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700746 return;
747 }
748
Mayank Garg7a114c82020-04-08 21:25:06 -0700749 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700750 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
751 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
752 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
753 }
754
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700755 // If there is another request for the same target user, return another request in
756 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
757 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
758 // user switch request in process for different target user, but that request is now
759 // ignored.
felipealf7368962020-04-16 12:55:19 -0700760 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700761 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
762 Log.d(TAG_USER,
763 "Another user switch request in process for the requested target user: "
764 + targetUserId);
765 }
766
767 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700768 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700769 return;
770 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700771 else {
772 mUserIdForUserSwitchInProcess = targetUserId;
773 mRequestIdForUserSwitchInProcess = 0;
774 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700775 }
776
Mayank Garg59f22192020-03-27 00:51:45 -0700777 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700778 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700779 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700780 halTargetUser.userId = targetUser.id;
781 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
782 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700783 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
784 Log.d(TAG, "switch response: status="
785 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
786 }
787
felipeale5bf0322020-04-16 15:10:57 -0700788 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700789
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700790 synchronized (mLockUser) {
791 if (status != HalCallback.STATUS_OK) {
792 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
793 Log.w(TAG, "invalid callback status ("
794 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
795 + resp);
796 sendResult(receiver, resultStatus);
797 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
798 return;
799 }
felipealf7368962020-04-16 12:55:19 -0700800
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700801 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
802 resp.errorMessage);
803
804 if (mUserIdForUserSwitchInProcess != targetUserId) {
805 // Another user switch request received while HAL responded. No need to process
806 // this request further
807 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
808 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
809 + "abondoned for : " + targetUserId + ". Current user in process: "
810 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700811 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700812 resultStatus =
813 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
814 sendResult(receiver, resultStatus);
815 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
816 return;
817 }
818
819 switch (resp.status) {
820 case SwitchUserStatus.SUCCESS:
821 boolean switched;
822 try {
823 switched = mAm.switchUser(targetUserId);
824 if (switched) {
825 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
826 mRequestIdForUserSwitchInProcess = resp.requestId;
827 } else {
828 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
829 postSwitchHalResponse(resp.requestId, targetUserId);
830 }
831 } catch (RemoteException e) {
832 // ignore
833 Log.w(TAG_USER,
834 "error while switching user " + targetUser.toFullString(), e);
835 }
836 break;
837 case SwitchUserStatus.FAILURE:
838 // HAL failed to switch user
839 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
840 break;
841 }
842
843 if (mRequestIdForUserSwitchInProcess == 0) {
844 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
845 }
Mayank Garg59f22192020-03-27 00:51:45 -0700846 }
felipeale5bf0322020-04-16 15:10:57 -0700847 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700848 });
849 }
850
felipeal5e3ede42020-04-23 18:04:07 -0700851 @Override
852 public GetUserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
853 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
854 checkManageUsersPermission("getUserIdentificationAssociation");
855
856 int uid = getCallingUid();
857 int userId = UserHandle.getUserId(uid);
858 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
859
860 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
861 request.userInfo.userId = userId;
862 request.userInfo.flags = getHalUserInfoFlags(userId);
863
864 request.numberAssociationTypes = types.length;
865 for (int i = 0; i < types.length; i++) {
866 request.associationTypes.add(types[i]);
867 }
868
869 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
870 if (halResponse == null) {
871 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
872 + Arrays.toString(types));
873 return null;
874 }
875
876 int[] values = new int[halResponse.associations.size()];
877 for (int i = 0; i < values.length; i++) {
878 values[i] = halResponse.associations.get(i).value;
879 }
880 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
881
882 return new GetUserIdentificationAssociationResponse(halResponse.errorMessage, values);
883 }
884
885 /**
886 * Gets the User HAL flags for the given user.
887 *
888 * @throws IllegalArgumentException if the user does not exist.
889 */
890 private int getHalUserInfoFlags(@UserIdInt int userId) {
891 UserInfo user = mUserManager.getUserInfo(userId);
892 Preconditions.checkArgument(user != null, "no user for id %d", userId);
893 return UserHalHelper.convertFlags(user);
894 }
895
Mayank Garg0e239142020-04-14 19:16:31 -0700896 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
897 @Nullable Bundle resultData) {
898 try {
899 receiver.send(resultCode, resultData);
900 } catch (RemoteException e) {
901 // ignore
902 Log.w(TAG_USER, "error while sending results", e);
903 }
904 }
905
felipeale5bf0322020-04-16 15:10:57 -0700906 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
907 @UserSwitchResult.Status int status) {
908 sendResult(receiver, status, /* errorMessage= */ null);
909 }
910
911 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
912 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
913 receiver.complete(new UserSwitchResult(status, errorMessage));
914 }
915
Mayank Garg7a114c82020-04-08 21:25:06 -0700916 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
917 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
918 UsersInfo usersInfo = getUsersInfo();
919 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
920 new android.hardware.automotive.vehicle.V2_0.UserInfo();
921 halTargetUser.userId = targetUser.id;
922 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700923 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
924 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700925 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
926 }
927
Mayank Garg59f22192020-03-27 00:51:45 -0700928 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700929 * Checks if the User HAL is supported.
930 */
931 public boolean isUserHalSupported() {
932 return mHal.isSupported();
933 }
934
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800935 // TODO(b/144120654): use helper to generate UsersInfo
936 private UsersInfo getUsersInfo() {
937 UserInfo currentUser;
938 try {
939 currentUser = mAm.getCurrentUser();
940 } catch (RemoteException e) {
941 // shouldn't happen
942 throw new IllegalStateException("Could not get current user: ", e);
943 }
944 List<UserInfo> existingUsers = mUserManager.getUsers();
945 int size = existingUsers.size();
946
947 UsersInfo usersInfo = new UsersInfo();
948 usersInfo.numberUsers = size;
949 usersInfo.currentUser.userId = currentUser.id;
950 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
951
952 for (int i = 0; i < size; i++) {
953 UserInfo androidUser = existingUsers.get(i);
954 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
955 new android.hardware.automotive.vehicle.V2_0.UserInfo();
956 halUser.userId = androidUser.id;
957 halUser.flags = UserHalHelper.convertFlags(androidUser);
958 usersInfo.existingUsers.add(halUser);
959 }
960
961 return usersInfo;
962 }
963
Eric Jeong1545f3b2019-09-16 13:56:52 -0700964 /** Returns whether the given user is a system user. */
965 private static boolean isSystemUser(@UserIdInt int userId) {
966 return userId == UserHandle.USER_SYSTEM;
967 }
968
Keun young Park13a7a822019-04-04 15:53:08 -0700969 private void updateDefaultUserRestriction() {
970 // We want to set restrictions on system and guest users only once. These are persisted
971 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
972 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700973 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
974 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700975 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700976 // Only apply the system user restrictions if the system user is headless.
977 if (UserManager.isHeadlessSystemUserMode()) {
978 setSystemUserRestrictions();
979 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700980 Settings.Global.putInt(mContext.getContentResolver(),
981 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700982 }
983
Eric Jeong1545f3b2019-09-16 13:56:52 -0700984 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700985 return !mUserManager.getUserInfo(userId).isEphemeral();
986 }
987
Antonio Kantekc8114752020-03-05 21:37:39 -0800988 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800989 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
990 */
991 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
992 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700993 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800994 }
995
996 /**
997 * Removes previously added {@link UserLifecycleListener}.
998 */
999 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1000 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001001 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001002 }
1003
Eric Jeongc91f9452019-08-30 15:04:21 -07001004 /** Adds callback to listen to passenger activity events. */
1005 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001006 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001007 mPassengerCallbacks.add(callback);
1008 }
1009
1010 /** Removes previously added callback to listen passenger events. */
1011 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001012 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001013 mPassengerCallbacks.remove(callback);
1014 }
1015
1016 /** Sets the implementation of ZoneUserBindingHelper. */
1017 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1018 synchronized (mLockHelper) {
1019 mZoneUserBindingHelper = helper;
1020 }
1021 }
1022
felipeal98900c82020-04-09 09:05:02 -07001023 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001024 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001025 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001026 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001027 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001028 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1029 updateDefaultUserRestriction();
1030 tasks = new ArrayList<>(mUser0UnlockTasks);
1031 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001032 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001033 }
1034 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001035 Integer user = userId;
1036 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001037 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001038 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001039 mBackgroundUsersToRestart.remove(user);
1040 mBackgroundUsersToRestart.add(0, user);
1041 }
1042 // -1 for user 0
1043 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001044 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001045 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001046 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001047 + ", dropping least recently user from restart list:" + userToDrop);
1048 // Drop the least recently used user.
1049 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1050 }
1051 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001052 }
1053 }
1054 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001055 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001056 for (Runnable r : tasks) {
1057 r.run();
1058 }
1059 }
1060 }
1061
1062 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001063 * Starts all background users that were active in system.
1064 *
Keun young Parkfb656372019-03-12 18:37:55 -07001065 * @return list of background users started successfully.
1066 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001067 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001068 public ArrayList<Integer> startAllBackgroundUsers() {
1069 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001070 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001071 users = new ArrayList<>(mBackgroundUsersToRestart);
1072 mBackgroundUsersRestartedHere.clear();
1073 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001074 }
1075 ArrayList<Integer> startedUsers = new ArrayList<>();
1076 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001077 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001078 continue;
1079 }
1080 try {
1081 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001082 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1083 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001084 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001085 } else if (mAm.unlockUser(user, null, null, null)) {
1086 startedUsers.add(user);
1087 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001088 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001089 if (mUserManager.isUserRunning(user)) {
1090 // add to started list so that it can be stopped later.
1091 startedUsers.add(user);
1092 }
Keun young Parkfb656372019-03-12 18:37:55 -07001093 }
1094 }
1095 } catch (RemoteException e) {
1096 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001097 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001098 }
1099 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001100 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001101 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001102 ArrayList<Integer> usersToRemove = new ArrayList<>();
1103 for (Integer user : mBackgroundUsersToRestart) {
1104 if (!startedUsers.contains(user)) {
1105 usersToRemove.add(user);
1106 }
1107 }
1108 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1109 }
Keun young Parkfb656372019-03-12 18:37:55 -07001110 return startedUsers;
1111 }
1112
1113 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001114 * Stops all background users that were active in system.
1115 *
1116 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001117 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001118 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001119 if (userId == UserHandle.USER_SYSTEM) {
1120 return false;
1121 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001122 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001123 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001124 return false;
1125 }
1126 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001127 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001128 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001129 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001130 Integer user = userId;
1131 mBackgroundUsersRestartedHere.remove(user);
1132 }
1133 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1134 return false;
1135 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001136 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001137 return false;
1138 }
1139 } catch (RemoteException e) {
1140 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001141 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001142 }
1143 return true;
1144 }
1145
1146 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001147 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001148 */
felipeale8c5dce2020-04-15 11:27:06 -07001149 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1150 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1151 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001152
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001153 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001154 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1155 onUserSwitching(userId);
1156 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1157 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001158 }
1159
felipeale8c5dce2020-04-15 11:27:06 -07001160 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001161 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001162
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001163 mHandler.post(() -> {
1164 handleNotifyServiceUserLifecycleListeners(event);
1165 handleNotifyAppUserLifecycleListeners(event);
1166 });
felipeale8c5dce2020-04-15 11:27:06 -07001167
1168 // Finally, update metrics.
1169 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1170 }
1171
1172 /**
1173 * Sets the first user unlocking metrics.
1174 */
1175 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1176 int halResponseTime) {
1177 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001178 }
1179
Mayank Garg7a114c82020-04-08 21:25:06 -07001180 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001181 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001182 || mUserIdForUserSwitchInProcess != userId
1183 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001184 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1185 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1186 }
1187 return;
1188 }
felipealf7368962020-04-16 12:55:19 -07001189 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1190 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001191 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001192 }
1193
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001194 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1195 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001196 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001197 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1198 Log.d(TAG_USER, "No app listener to be notified of " + event);
1199 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001200 return;
1201 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001202 // Must use a different TimingsTraceLog because it's another thread
1203 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1204 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1205 }
felipeal2a84d512020-04-06 18:52:15 -07001206 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001207 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1208 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1209 for (int i = 0; i < listenersSize; i++) {
1210 int uid = mAppLifecycleListeners.keyAt(i);
1211 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1212 Bundle data = new Bundle();
1213 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001214
1215 int fromUid = event.getPreviousUserId();
1216 if (fromUid != UserHandle.USER_NULL) {
1217 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1218 }
1219
felipeal2a84d512020-04-06 18:52:15 -07001220 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001221 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001222 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001223 try {
felipeal2a84d512020-04-06 18:52:15 -07001224 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001225 listener.send(userId, data);
1226 } catch (RemoteException e) {
1227 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1228 } finally {
1229 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001230 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001231 }
1232 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001233 }
1234
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001235 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001236 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1237 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001238 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001239 return;
felipeal2a84d512020-04-06 18:52:15 -07001240 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1241 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1242 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001243 }
felipeal2a84d512020-04-06 18:52:15 -07001244
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001245 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1246 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001247 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001248 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001249 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001250 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001251 listener.onEvent(event);
1252 } catch (RuntimeException e) {
1253 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001254 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001255 } finally {
1256 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001257 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001258 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001259 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001260 }
1261
felipeal98900c82020-04-09 09:05:02 -07001262 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001263 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1264 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001265 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001266
Felipe Lemef45ee502019-12-19 10:00:14 -08001267 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001268 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001269 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001270 if (mLastPassengerId != UserHandle.USER_NULL) {
1271 stopPassengerInternal(mLastPassengerId, false);
1272 }
1273 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1274 setupPassengerUser();
1275 startFirstPassenger(userId);
1276 }
felipeal98900c82020-04-09 09:05:02 -07001277 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001278 }
1279
1280 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001281 * 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 -08001282 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001283 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001284 * @param r Runnable to run.
1285 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001286 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001287 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001288 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001289 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001290 if (mUser0Unlocked) {
1291 runNow = true;
1292 } else {
1293 mUser0UnlockTasks.add(r);
1294 }
1295 }
1296 if (runNow) {
1297 r.run();
1298 }
1299 }
1300
Keun young Parkf3523cd2019-04-08 10:09:17 -07001301 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001302 @NonNull
1303 ArrayList<Integer> getBackgroundUsersToRestart() {
1304 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001305 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001306 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1307 }
1308 return backgroundUsersToRestart;
1309 }
1310
Ying Zheng1ab32b62018-06-26 12:47:26 -07001311 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001312 // Disable Location service for system user.
1313 LocationManager locationManager =
1314 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001315 locationManager.setLocationEnabledForUser(
1316 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001317 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001318
1319 /**
1320 * Creates a new user on the system, the created user would be granted admin role.
1321 *
1322 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001323 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001324 */
1325 @Nullable
1326 private UserInfo createNewAdminUser(String name) {
1327 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1328 // Only admins or system user can create other privileged users.
1329 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1330 return null;
1331 }
1332
1333 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1334 if (user == null) {
1335 // Couldn't create user, most likely because there are too many.
1336 Log.w(TAG_USER, "can't create admin user.");
1337 return null;
1338 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001339 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001340
1341 return user;
1342 }
1343
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001344 /**
1345 * Assigns a default icon to a user according to the user's id.
1346 *
1347 * @param userInfo User whose avatar is set to default icon.
1348 * @return Bitmap of the user icon.
1349 */
1350 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1351 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1352 Bitmap bitmap = UserIcons.convertToBitmap(
1353 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1354 mUserManager.setUserIcon(userInfo.id, bitmap);
1355 return bitmap;
1356 }
1357
Eric Jeong1545f3b2019-09-16 13:56:52 -07001358 private interface UserFilter {
1359 boolean isEligibleUser(UserInfo user);
1360 }
1361
1362 /** Returns all users who are matched by the given filter. */
1363 private List<UserInfo> getUsers(UserFilter filter) {
1364 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1365
1366 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1367 UserInfo user = iterator.next();
1368 if (!filter.isEligibleUser(user)) {
1369 iterator.remove();
1370 }
1371 }
1372 return users;
1373 }
1374
1375 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001376 * Enforces that apps which have the
1377 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1378 * can make certain calls to the CarUserManager.
1379 *
1380 * @param message used as message if SecurityException is thrown.
1381 * @throws SecurityException if the caller is not system or root.
1382 */
1383 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001384 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1385 }
1386
1387 private static void checkManageUsersOrDumpPermission(String message) {
1388 checkAtLeastOnePermission(message,
1389 android.Manifest.permission.MANAGE_USERS,
1390 android.Manifest.permission.DUMP);
1391 }
1392
Felipe Leme5528ff72020-02-10 19:05:14 -08001393 private void checkInteractAcrossUsersPermission(String message) {
1394 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1395 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1396 }
1397
felipeal2d0483c2019-11-02 14:07:22 -07001398 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001399 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001400 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1401 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001402 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001403 }
1404 }
1405
felipeal2d0483c2019-11-02 14:07:22 -07001406 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1407 for (String permission : permissions) {
1408 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1409 /* exported = */ true)
1410 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1411 return true;
1412 }
1413 }
1414 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001415 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001416
1417 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1418 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1419 // Count all users that are managed profiles of the given user.
1420 int managedProfilesCount = 0;
1421 for (UserInfo user : users) {
1422 if (user.isManagedProfile() && user.profileGroupId == userId) {
1423 managedProfilesCount++;
1424 }
1425 }
1426 return managedProfilesCount;
1427 }
1428
1429 /**
1430 * Starts the first passenger of the given driver and assigns the passenger to the front
1431 * passenger zone.
1432 *
1433 * @param driverId User id of the driver.
1434 * @return whether it succeeds.
1435 */
1436 private boolean startFirstPassenger(@UserIdInt int driverId) {
1437 int zoneId = getAvailablePassengerZone();
1438 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1439 Log.w(TAG_USER, "passenger occupant zone is not found");
1440 return false;
1441 }
1442 List<UserInfo> passengers = getPassengers(driverId);
1443 if (passengers.size() < 1) {
1444 Log.w(TAG_USER, "passenger is not found");
1445 return false;
1446 }
1447 // Only one passenger is supported. If there are two or more passengers, the first passenger
1448 // is chosen.
1449 int passengerId = passengers.get(0).id;
1450 if (!startPassenger(passengerId, zoneId)) {
1451 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1452 return false;
1453 }
1454 return true;
1455 }
1456
1457 private int getAvailablePassengerZone() {
1458 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1459 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1460 for (int occupantType : occupantTypes) {
1461 int zoneId = getZoneId(occupantType);
1462 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1463 return zoneId;
1464 }
1465 }
1466 return OccupantZoneInfo.INVALID_ZONE_ID;
1467 }
1468
1469 /**
1470 * Creates a new passenger user when there is no passenger user.
1471 */
1472 private void setupPassengerUser() {
1473 int currentUser = ActivityManager.getCurrentUser();
1474 int profileCount = getNumberOfManagedProfiles(currentUser);
1475 if (profileCount > 0) {
1476 Log.w(TAG_USER, "max profile of user" + currentUser
1477 + " is exceeded: current profile count is " + profileCount);
1478 return;
1479 }
1480 // TODO(b/140311342): Use resource string for the default passenger name.
1481 UserInfo passenger = createPassenger("Passenger", currentUser);
1482 if (passenger == null) {
1483 // Couldn't create user, most likely because there are too many.
1484 Log.w(TAG_USER, "cannot create a passenger user");
1485 return;
1486 }
1487 }
1488
1489 @NonNull
1490 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1491 ZoneUserBindingHelper helper = null;
1492 synchronized (mLockHelper) {
1493 if (mZoneUserBindingHelper == null) {
1494 Log.w(TAG_USER, "implementation is not delegated");
1495 return new ArrayList<OccupantZoneInfo>();
1496 }
1497 helper = mZoneUserBindingHelper;
1498 }
1499 return helper.getOccupantZones(occupantType);
1500 }
1501
1502 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1503 ZoneUserBindingHelper helper = null;
1504 synchronized (mLockHelper) {
1505 if (mZoneUserBindingHelper == null) {
1506 Log.w(TAG_USER, "implementation is not delegated");
1507 return false;
1508 }
1509 helper = mZoneUserBindingHelper;
1510 }
1511 return helper.assignUserToOccupantZone(userId, zoneId);
1512 }
1513
1514 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1515 ZoneUserBindingHelper helper = null;
1516 synchronized (mLockHelper) {
1517 if (mZoneUserBindingHelper == null) {
1518 Log.w(TAG_USER, "implementation is not delegated");
1519 return false;
1520 }
1521 helper = mZoneUserBindingHelper;
1522 }
1523 return helper.unassignUserFromOccupantZone(userId);
1524 }
1525
1526 private boolean isPassengerDisplayAvailable() {
1527 ZoneUserBindingHelper helper = null;
1528 synchronized (mLockHelper) {
1529 if (mZoneUserBindingHelper == null) {
1530 Log.w(TAG_USER, "implementation is not delegated");
1531 return false;
1532 }
1533 helper = mZoneUserBindingHelper;
1534 }
1535 return helper.isPassengerDisplayAvailable();
1536 }
1537
1538 /**
1539 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1540 * zone is returned.
1541 *
1542 * @param occupantType The type of an occupant.
1543 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1544 * if not found.
1545 */
1546 private int getZoneId(@OccupantTypeEnum int occupantType) {
1547 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1548 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1549 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001550}