blob: 164ecb844327f330dc550c379d6364fa5aada3de [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;
34import android.car.user.CarUserManager.UserLifecycleListener;
Eric Jeong3a793b02019-09-30 16:12:53 -070035import android.car.userlib.CarUserManagerHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070036import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070037import android.content.pm.UserInfo;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070038import android.graphics.Bitmap;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080039import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080040import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070041import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070042import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080043import android.os.Bundle;
Keun young Parkfb656372019-03-12 18:37:55 -070044import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080045import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070046import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070047import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070048import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070049import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080050import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080051import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070052
53import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070054import com.android.car.R;
Felipe Lemeabbf2da2020-02-24 18:25:29 -080055import com.android.car.hal.UserHalHelper;
Felipe Leme58412202020-01-09 13:45:33 -080056import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080057import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070058import com.android.internal.annotations.VisibleForTesting;
Felipe Leme5528ff72020-02-10 19:05:14 -080059import com.android.internal.os.IResultReceiver;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070060import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070061
62import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080063import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070064import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070065import java.util.Iterator;
66import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000067import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070068import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070069
70/**
71 * User service for cars. Manages users at boot time. Including:
72 *
73 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070074 * <li> Creates a user used as driver.
75 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070077 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078 * <ol/>
79 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070080public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080081
Felipe Lemeabbf2da2020-02-24 18:25:29 -080082 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080083 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080084 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080085 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080086 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080087 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080088 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
89 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -080090
Ying Zhengd3cb98e2018-05-11 11:42:48 -070091 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070092 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070093 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070094 private final UserManager mUserManager;
95 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -070096 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097
Eric Jeongc91f9452019-08-30 15:04:21 -070098 private final Object mLockUser = new Object();
99 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800100 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700101 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800102 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700103 // Only one passenger is supported.
104 @GuardedBy("mLockUser")
105 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700106 /**
107 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800108 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700109 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700110 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700111 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
112 /**
113 * Keep the list of background users started here. This is wholly for debugging purpose.
114 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700115 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700116 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
117
Antonio Kantekc8114752020-03-05 21:37:39 -0800118 // TODO(b/144120654): merge then
Pavel Maltsev17e81832019-04-04 14:38:41 -0700119 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
120
Felipe Leme58412202020-01-09 13:45:33 -0800121 private final UserHalService mHal;
122
Felipe Leme5528ff72020-02-10 19:05:14 -0800123 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800124 * List of listeners to be notified on new user activities events.
125 */
126 private final CopyOnWriteArrayList<UserLifecycleListener>
127 mUserLifecycleListeners = new CopyOnWriteArrayList<>();
128
129 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800130 * List of lifecycle listeners by uid.
131 */
132 @GuardedBy("mLockUser")
133 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
134
Antonio Kantekc8114752020-03-05 21:37:39 -0800135 /**
136 * Interface for callbacks related to user activities.
137 *
138 * @deprecated {@link UserCallback} will be fully replaced by
139 * {@link UserLifecycleListener} as part of b/145689885
140 */
141 @Deprecated
Pavel Maltsev17e81832019-04-04 14:38:41 -0700142 public interface UserCallback {
143 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700144 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700145 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700146 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700147 }
148
Eric Jeongc91f9452019-08-30 15:04:21 -0700149 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
150 new CopyOnWriteArrayList<>();
151
152 /** Interface for callbaks related to passenger activities. */
153 public interface PassengerCallback {
154 /** Called when passenger is started at a certain zone. */
155 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
156 /** Called when passenger is stopped. */
157 void onPassengerStopped(@UserIdInt int passengerId);
158 }
159
160 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
161 public interface ZoneUserBindingHelper {
162 /** Gets occupant zones corresponding to the occupant type. */
163 @NonNull
164 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
165 /** Assigns the user to the occupant zone. */
166 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
167 /** Makes the occupant zone unoccupied. */
168 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
169 /** Returns whether there is a passenger display. */
170 boolean isPassengerDisplayAvailable();
171 }
172
173 private final Object mLockHelper = new Object();
174 @GuardedBy("mLockHelper")
175 private ZoneUserBindingHelper mZoneUserBindingHelper;
176
Felipe Leme58412202020-01-09 13:45:33 -0800177 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
178 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700179 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700180 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
181 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700182 }
183 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800184 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700185 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700186 mAm = am;
187 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700188 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700189 mLastPassengerId = UserHandle.USER_NULL;
190 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700191 }
192
193 @Override
194 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700195 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
196 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700197 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700198 }
199
200 @Override
201 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700202 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
203 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700204 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700205 }
206
207 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700208 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700209 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700210 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800211 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700212 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800213 int numberListeners = mLifecycleListeners.size();
214 if (numberListeners == 0) {
215 writer.println("No lifecycle listeners");
216 } else {
217 writer.printf("%d lifecycle listeners\n", numberListeners);
218 for (int i = 0; i < numberListeners; i++) {
219 int uid = mLifecycleListeners.keyAt(i);
220 IResultReceiver listener = mLifecycleListeners.valueAt(i);
221 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
222 }
223 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700224 writer.println("User0Unlocked: " + mUser0Unlocked);
225 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
226 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
227 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700228 List<UserInfo> allDrivers = getAllDrivers();
229 int driversSize = allDrivers.size();
230 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700231 for (int i = 0; i < driversSize; i++) {
232 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800233 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700234 List<UserInfo> passengers = getPassengers(driverId);
235 int passengersSize = passengers.size();
236 writer.print(" NumberPassengers: " + passengersSize);
237 if (passengersSize > 0) {
238 writer.print(" [");
239 for (int j = 0; j < passengersSize; j++) {
240 writer.print(passengers.get(j).id);
241 if (j < passengersSize - 1) {
242 writer.print(" ");
243 }
244 }
245 writer.print("]");
246 }
247 writer.println();
248 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700249 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Keun-young Parkd462a912019-02-11 08:53:42 -0800250 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700251 }
252
253 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800254 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
255 *
256 * @param name The name of the driver to be created.
257 * @param admin Whether the created driver will be an admin.
258 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
259 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700260 */
261 @Override
262 @Nullable
263 public UserInfo createDriver(@NonNull String name, boolean admin) {
264 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000265 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700266 if (admin) {
267 return createNewAdminUser(name);
268 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700269 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700270 }
271
272 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800273 * Creates a passenger who is a profile of the given driver.
274 *
275 * @param name The name of the passenger to be created.
276 * @param driverId User id of the driver under whom a passenger is created.
277 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
278 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700279 */
280 @Override
281 @Nullable
282 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
283 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000284 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700285 UserInfo driver = mUserManager.getUserInfo(driverId);
286 if (driver == null) {
287 Log.w(TAG_USER, "the driver is invalid");
288 return null;
289 }
290 if (driver.isGuest()) {
291 Log.w(TAG_USER, "a guest driver cannot create a passenger");
292 return null;
293 }
Bookatz42fb1a62019-10-30 11:45:01 -0700294 UserInfo user = mUserManager.createProfileForUser(name,
295 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700296 if (user == null) {
297 // Couldn't create user, most likely because there are too many.
298 Log.w(TAG_USER, "can't create a profile for user" + driverId);
299 return null;
300 }
301 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700302 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700303 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700304 return user;
305 }
306
307 /**
308 * @see CarUserManager.switchDriver
309 */
310 @Override
311 public boolean switchDriver(@UserIdInt int driverId) {
312 checkManageUsersPermission("switchDriver");
313 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
314 // System user doesn't associate with real person, can not be switched to.
315 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
316 return false;
317 }
318 int userSwitchable = mUserManager.getUserSwitchability();
319 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
320 Log.w(TAG_USER, "current process is not allowed to switch user");
321 return false;
322 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700323 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700324 // The current user is already the given user.
325 return true;
326 }
327 try {
328 return mAm.switchUser(driverId);
329 } catch (RemoteException e) {
330 // ignore
331 Log.w(TAG_USER, "error while switching user", e);
332 }
333 return false;
334 }
335
336 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800337 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
338 *
339 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700340 */
341 @Override
342 @NonNull
343 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700344 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700345 return getUsers((user) -> {
346 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
347 && !user.isEphemeral();
348 });
349 }
350
351 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800352 * Returns all passengers under the given driver.
353 *
354 * @param driverId User id of a driver.
355 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700356 */
357 @Override
358 @NonNull
359 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700360 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700361 return getUsers((user) -> {
362 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
363 && user.profileGroupId == driverId;
364 });
365 }
366
367 /**
368 * @see CarUserManager.startPassenger
369 */
370 @Override
371 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
372 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700373 synchronized (mLockUser) {
374 try {
375 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
376 Log.w(TAG_USER, "could not start passenger");
377 return false;
378 }
379 } catch (RemoteException e) {
380 // ignore
381 Log.w(TAG_USER, "error while starting passenger", e);
382 return false;
383 }
384 if (!assignUserToOccupantZone(passengerId, zoneId)) {
385 Log.w(TAG_USER, "could not assign passenger to zone");
386 return false;
387 }
388 mLastPassengerId = passengerId;
389 }
390 for (PassengerCallback callback : mPassengerCallbacks) {
391 callback.onPassengerStarted(passengerId, zoneId);
392 }
393 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700394 }
395
396 /**
397 * @see CarUserManager.stopPassenger
398 */
399 @Override
400 public boolean stopPassenger(@UserIdInt int passengerId) {
401 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700402 return stopPassengerInternal(passengerId, true);
403 }
404
405 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
406 synchronized (mLockUser) {
407 UserInfo passenger = mUserManager.getUserInfo(passengerId);
408 if (passenger == null) {
409 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
410 return false;
411 }
412 if (mLastPassengerId != passengerId) {
413 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
414 return true;
415 }
416 if (checkCurrentDriver) {
417 int currentUser = ActivityManager.getCurrentUser();
418 if (passenger.profileGroupId != currentUser) {
419 Log.w(TAG_USER, "passenger " + passengerId
420 + " is not a profile of the current user");
421 return false;
422 }
423 }
424 // Passenger is a profile, so cannot be stopped through activity manager.
425 // Instead, activities started by the passenger are stopped and the passenger is
426 // unassigned from the zone.
427 stopAllTasks(passengerId);
428 if (!unassignUserFromOccupantZone(passengerId)) {
429 Log.w(TAG_USER, "could not unassign user from occupant zone");
430 return false;
431 }
432 mLastPassengerId = UserHandle.USER_NULL;
433 }
434 for (PassengerCallback callback : mPassengerCallbacks) {
435 callback.onPassengerStopped(passengerId);
436 }
437 return true;
438 }
439
440 private void stopAllTasks(@UserIdInt int userId) {
441 try {
442 for (StackInfo info : mAm.getAllStackInfos()) {
443 for (int i = 0; i < info.taskIds.length; i++) {
444 if (info.taskUserIds[i] == userId) {
445 int taskId = info.taskIds[i];
446 if (!mAm.removeTask(taskId)) {
447 Log.w(TAG_USER, "could not remove task " + taskId);
448 }
449 }
450 }
451 }
452 } catch (RemoteException e) {
453 Log.e(TAG_USER, "could not get stack info", e);
454 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700455 }
456
Felipe Leme5528ff72020-02-10 19:05:14 -0800457 @Override
458 public void setLifecycleListenerForUid(IResultReceiver listener) {
459 int uid = Binder.getCallingUid();
460 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
461
462 try {
463 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
464 } catch (RemoteException e) {
465 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
466 }
467 synchronized (mLockUser) {
468 mLifecycleListeners.append(uid, listener);
469 }
470 }
471
472 private void onListenerDeath(int uid) {
473 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
474 synchronized (mLockUser) {
475 removeLifecycleListenerLocked(uid);
476 }
477 }
478
479 @Override
480 public void resetLifecycleListenerForUid() {
481 int uid = Binder.getCallingUid();
482 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
483
484 synchronized (mLockUser) {
485 removeLifecycleListenerLocked(uid);
486 }
487 }
488
489 private void removeLifecycleListenerLocked(int uid) {
490 mLifecycleListeners.remove(uid);
491 }
492
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800493 @Override
494 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800495 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800496 Objects.requireNonNull(receiver, "receiver cannot be null");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800497 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800498 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
499 try {
500 Bundle resultData = null;
501 if (resp != null) {
502 switch (resp.action) {
503 case InitialUserInfoResponseAction.SWITCH:
504 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800505 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800506 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
507 break;
508 case InitialUserInfoResponseAction.CREATE:
509 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800510 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800511 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
512 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
513 break;
514 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800515 resultData = new Bundle();
516 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800517 break;
518 default:
519 // That's ok, it will be the same as DEFAULT...
520 Log.w(TAG_USER, "invalid response action on " + resp);
521 }
522 }
523 receiver.send(status, resultData);
524 } catch (RemoteException e) {
525 Log.w(TAG_USER, "Could not send result back to receiver", e);
526 }
527 });
528 }
529
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800530 // TODO(b/144120654): use helper to generate UsersInfo
531 private UsersInfo getUsersInfo() {
532 UserInfo currentUser;
533 try {
534 currentUser = mAm.getCurrentUser();
535 } catch (RemoteException e) {
536 // shouldn't happen
537 throw new IllegalStateException("Could not get current user: ", e);
538 }
539 List<UserInfo> existingUsers = mUserManager.getUsers();
540 int size = existingUsers.size();
541
542 UsersInfo usersInfo = new UsersInfo();
543 usersInfo.numberUsers = size;
544 usersInfo.currentUser.userId = currentUser.id;
545 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
546
547 for (int i = 0; i < size; i++) {
548 UserInfo androidUser = existingUsers.get(i);
549 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
550 new android.hardware.automotive.vehicle.V2_0.UserInfo();
551 halUser.userId = androidUser.id;
552 halUser.flags = UserHalHelper.convertFlags(androidUser);
553 usersInfo.existingUsers.add(halUser);
554 }
555
556 return usersInfo;
557 }
558
Eric Jeong1545f3b2019-09-16 13:56:52 -0700559 /** Returns whether the given user is a system user. */
560 private static boolean isSystemUser(@UserIdInt int userId) {
561 return userId == UserHandle.USER_SYSTEM;
562 }
563
Keun young Park13a7a822019-04-04 15:53:08 -0700564 private void updateDefaultUserRestriction() {
565 // We want to set restrictions on system and guest users only once. These are persisted
566 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
567 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700568 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
569 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700570 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700571 // Only apply the system user restrictions if the system user is headless.
572 if (UserManager.isHeadlessSystemUserMode()) {
573 setSystemUserRestrictions();
574 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700575 Settings.Global.putInt(mContext.getContentResolver(),
576 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700577 }
578
Eric Jeong1545f3b2019-09-16 13:56:52 -0700579 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700580 return !mUserManager.getUserInfo(userId).isEphemeral();
581 }
582
Antonio Kantekc8114752020-03-05 21:37:39 -0800583 /**
584 * Adds a new callback to listen to user activity events.
585 *
586 * @deprecated users should rely on {@link UserLifecycleListener} and invoke
587 * {@link #addUserLifecycleListener} instead
588 */
589 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700590 public void addUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000591 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700592 mUserCallbacks.add(callback);
593 }
594
Antonio Kantekc8114752020-03-05 21:37:39 -0800595 /**
596 * Removes previously added user callback.
597 *
598 * @deprecated users should rely on {@link UserLifecycleListener} and invoke
599 * {@link CarUserService#remove]UserLifecycleListener} instead
600 */
601 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700602 public void removeUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000603 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700604 mUserCallbacks.remove(callback);
605 }
606
Antonio Kantekc8114752020-03-05 21:37:39 -0800607 /**
608 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
609 */
610 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
611 Objects.requireNonNull(listener, "listener cannot be null");
612 mUserLifecycleListeners.add(listener);
613 }
614
615 /**
616 * Removes previously added {@link UserLifecycleListener}.
617 */
618 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
619 Objects.requireNonNull(listener, "listener cannot be null");
620 mUserLifecycleListeners.remove(listener);
621 }
622
Eric Jeongc91f9452019-08-30 15:04:21 -0700623 /** Adds callback to listen to passenger activity events. */
624 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000625 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700626 mPassengerCallbacks.add(callback);
627 }
628
629 /** Removes previously added callback to listen passenger events. */
630 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000631 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700632 mPassengerCallbacks.remove(callback);
633 }
634
635 /** Sets the implementation of ZoneUserBindingHelper. */
636 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
637 synchronized (mLockHelper) {
638 mZoneUserBindingHelper = helper;
639 }
640 }
641
Keun-young Parkd462a912019-02-11 08:53:42 -0800642 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700643 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
644 *
645 * @param userId User id whoes lock status is changed.
646 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800647 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700648 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Mayank Garg31e73042020-01-23 00:10:38 -0800649 TimingsTraceLog t = new TimingsTraceLog(TAG_USER,
650 Trace.TRACE_TAG_SYSTEM_SERVER);
651 t.traceBegin("onUserLockChanged-" + userId
652 + (unlocked ? "-unlocked" : "-locked"));
Pavel Maltsev17e81832019-04-04 14:38:41 -0700653 for (UserCallback callback : mUserCallbacks) {
Mayank Garg31e73042020-01-23 00:10:38 -0800654 t.traceBegin("onUserLockChanged-"
655 + callback.getClass().getSimpleName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700656 callback.onUserLockChanged(userId, unlocked);
Mayank Garg31e73042020-01-23 00:10:38 -0800657 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700658 }
Mayank Garg31e73042020-01-23 00:10:38 -0800659 t.traceEnd();
660
Keun young Parkf3523cd2019-04-08 10:09:17 -0700661 if (!unlocked) { // nothing else to do when it is locked back.
662 return;
663 }
Mayank Garg31e73042020-01-23 00:10:38 -0800664
665 t.traceBegin("setUserLockStatus-UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800666 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700667 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700668 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700669 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
670 updateDefaultUserRestriction();
671 tasks = new ArrayList<>(mUser0UnlockTasks);
672 mUser0UnlockTasks.clear();
673 mUser0Unlocked = unlocked;
674 }
675 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700676 Integer user = userId;
677 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700678 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700679 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700680 mBackgroundUsersToRestart.remove(user);
681 mBackgroundUsersToRestart.add(0, user);
682 }
683 // -1 for user 0
684 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700685 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700686 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700687 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700688 + ", dropping least recently user from restart list:" + userToDrop);
689 // Drop the least recently used user.
690 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
691 }
692 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800693 }
694 }
695 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700696 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800697 for (Runnable r : tasks) {
698 r.run();
699 }
700 }
Mayank Garg31e73042020-01-23 00:10:38 -0800701 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800702 }
703
704 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700705 * Starts all background users that were active in system.
706 *
Keun young Parkfb656372019-03-12 18:37:55 -0700707 * @return list of background users started successfully.
708 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700709 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700710 public ArrayList<Integer> startAllBackgroundUsers() {
711 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700712 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700713 users = new ArrayList<>(mBackgroundUsersToRestart);
714 mBackgroundUsersRestartedHere.clear();
715 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700716 }
717 ArrayList<Integer> startedUsers = new ArrayList<>();
718 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700719 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700720 continue;
721 }
722 try {
723 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700724 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
725 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700726 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700727 } else if (mAm.unlockUser(user, null, null, null)) {
728 startedUsers.add(user);
729 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700730 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700731 if (mUserManager.isUserRunning(user)) {
732 // add to started list so that it can be stopped later.
733 startedUsers.add(user);
734 }
Keun young Parkfb656372019-03-12 18:37:55 -0700735 }
736 }
737 } catch (RemoteException e) {
738 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700739 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700740 }
741 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700742 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700743 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700744 ArrayList<Integer> usersToRemove = new ArrayList<>();
745 for (Integer user : mBackgroundUsersToRestart) {
746 if (!startedUsers.contains(user)) {
747 usersToRemove.add(user);
748 }
749 }
750 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
751 }
Keun young Parkfb656372019-03-12 18:37:55 -0700752 return startedUsers;
753 }
754
755 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700756 * Stops all background users that were active in system.
757 *
758 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700759 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700760 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700761 if (userId == UserHandle.USER_SYSTEM) {
762 return false;
763 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700764 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700765 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700766 return false;
767 }
768 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700769 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700770 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700771 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700772 Integer user = userId;
773 mBackgroundUsersRestartedHere.remove(user);
774 }
775 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
776 return false;
777 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700778 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700779 return false;
780 }
781 } catch (RemoteException e) {
782 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700783 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700784 }
785 return true;
786 }
787
788 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700789 * Called when new foreground user started to boot.
790 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700791 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700792 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700793 public void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800794 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
795 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800796 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800797
Felipe Lemef45ee502019-12-19 10:00:14 -0800798 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700799 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700800 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700801 if (mLastPassengerId != UserHandle.USER_NULL) {
802 stopPassengerInternal(mLastPassengerId, false);
803 }
804 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
805 setupPassengerUser();
806 startFirstPassenger(userId);
807 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800808
809 // TODO(b/144120654): right now just the app listeners are running in the background so the
810 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
811 // but once we refactor the car service callback into lifecycle listeners, we should use a
812 // proper thread management (like a Threadpool / executor);
813
814 int listenersSize = mLifecycleListeners.size();
815 if (listenersSize == 0) {
816 Log.i(TAG_USER, "Not notifying app listeners");
817 } else {
818 new Thread(() -> {
819 // Must use a different TimingsTraceLog because it's another thread
820 TimingsTraceLog t2 = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
821 Log.i(TAG_USER, "Notifying " + listenersSize + " listeners");
822 for (int i = 0; i < listenersSize; i++) {
823 int uid = mLifecycleListeners.keyAt(i);
824 IResultReceiver listener = mLifecycleListeners.valueAt(i);
825 t2.traceBegin("notify-listener-" + uid);
826 Bundle data = new Bundle();
827 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION,
828 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
829 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
830 // can set BUNDLE_PARAM_PREVIOUS_USER_HANDLE
831 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
832 Log.d(TAG_USER, "Notifying listener for uid " + uid);
833 }
834 try {
835 listener.send(userId, data);
836 } catch (RemoteException e) {
837 Log.e(TAG_USER, "Error calling lifecycle listener", e);
838 } finally {
839 t2.traceEnd();
840 }
841 }
842
843 }, "SwitchUser-" + userId + "-Listeners").start();
844 }
845
Antonio Kantekc8114752020-03-05 21:37:39 -0800846 notifyUserLifecycleListeners(t, userId);
847 notifyCallbacks(t, userId);
848 }
849
850 private void notifyUserLifecycleListeners(TimingsTraceLog t,
851 @UserIdInt int userId) {
852 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
853 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size()
854 + " user lifecycle listeners");
855 }
856 // TODO(b/145689885): passing null for `from` parameter until it gets properly replaced
857 // the expected Binder call.
858 UserLifecycleEvent event = new UserLifecycleEvent(
859 /* eventType= */ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
860 /* from= */ null, /* to= */ new UserHandle(userId));
861 for (UserLifecycleListener listener : mUserLifecycleListeners) {
862 t.traceBegin("onEvent-" + listener.getClass().getName());
863 try {
864 listener.onEvent(event);
865 } catch (RuntimeException e) {
866 Log.e(TAG_USER,
867 "Exception raised when invoking onEvent for " + listener, e);
868 }
869 t.traceEnd();
870 }
871 }
872
873 private void notifyCallbacks(TimingsTraceLog t, @UserIdInt int userId) {
874 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
875 Log.d(TAG_USER, "Notifying " + mUserCallbacks.size() + " callbacks");
876 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700877 for (UserCallback callback : mUserCallbacks) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800878 t.traceBegin("onSwitchUser-" + callback.getClass().getName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700879 callback.onSwitchUser(userId);
Mayank Garg31e73042020-01-23 00:10:38 -0800880 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700881 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800882 t.traceEnd(); // onSwitchUser
Pavel Maltsev17e81832019-04-04 14:38:41 -0700883 }
884
885 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700886 * 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 -0800887 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700888 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800889 * @param r Runnable to run.
890 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700891 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000892 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800893 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700894 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800895 if (mUser0Unlocked) {
896 runNow = true;
897 } else {
898 mUser0UnlockTasks.add(r);
899 }
900 }
901 if (runNow) {
902 r.run();
903 }
904 }
905
Keun young Parkf3523cd2019-04-08 10:09:17 -0700906 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700907 @NonNull
908 ArrayList<Integer> getBackgroundUsersToRestart() {
909 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700910 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700911 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
912 }
913 return backgroundUsersToRestart;
914 }
915
Ying Zheng1ab32b62018-06-26 12:47:26 -0700916 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700917 // Disable Location service for system user.
918 LocationManager locationManager =
919 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800920 locationManager.setLocationEnabledForUser(
921 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700922 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700923
924 /**
925 * Creates a new user on the system, the created user would be granted admin role.
926 *
927 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700928 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700929 */
930 @Nullable
931 private UserInfo createNewAdminUser(String name) {
932 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
933 // Only admins or system user can create other privileged users.
934 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
935 return null;
936 }
937
938 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
939 if (user == null) {
940 // Couldn't create user, most likely because there are too many.
941 Log.w(TAG_USER, "can't create admin user.");
942 return null;
943 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700944 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700945
946 return user;
947 }
948
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700949 /**
950 * Assigns a default icon to a user according to the user's id.
951 *
952 * @param userInfo User whose avatar is set to default icon.
953 * @return Bitmap of the user icon.
954 */
955 private Bitmap assignDefaultIcon(UserInfo userInfo) {
956 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
957 Bitmap bitmap = UserIcons.convertToBitmap(
958 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
959 mUserManager.setUserIcon(userInfo.id, bitmap);
960 return bitmap;
961 }
962
Eric Jeong1545f3b2019-09-16 13:56:52 -0700963 private interface UserFilter {
964 boolean isEligibleUser(UserInfo user);
965 }
966
967 /** Returns all users who are matched by the given filter. */
968 private List<UserInfo> getUsers(UserFilter filter) {
969 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
970
971 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
972 UserInfo user = iterator.next();
973 if (!filter.isEligibleUser(user)) {
974 iterator.remove();
975 }
976 }
977 return users;
978 }
979
980 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700981 * Enforces that apps which have the
982 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
983 * can make certain calls to the CarUserManager.
984 *
985 * @param message used as message if SecurityException is thrown.
986 * @throws SecurityException if the caller is not system or root.
987 */
988 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -0700989 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
990 }
991
992 private static void checkManageUsersOrDumpPermission(String message) {
993 checkAtLeastOnePermission(message,
994 android.Manifest.permission.MANAGE_USERS,
995 android.Manifest.permission.DUMP);
996 }
997
Felipe Leme5528ff72020-02-10 19:05:14 -0800998 private void checkInteractAcrossUsersPermission(String message) {
999 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1000 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1001 }
1002
felipeal2d0483c2019-11-02 14:07:22 -07001003 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001004 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001005 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1006 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001007 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001008 }
1009 }
1010
felipeal2d0483c2019-11-02 14:07:22 -07001011 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1012 for (String permission : permissions) {
1013 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1014 /* exported = */ true)
1015 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1016 return true;
1017 }
1018 }
1019 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001020 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001021
1022 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1023 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1024 // Count all users that are managed profiles of the given user.
1025 int managedProfilesCount = 0;
1026 for (UserInfo user : users) {
1027 if (user.isManagedProfile() && user.profileGroupId == userId) {
1028 managedProfilesCount++;
1029 }
1030 }
1031 return managedProfilesCount;
1032 }
1033
1034 /**
1035 * Starts the first passenger of the given driver and assigns the passenger to the front
1036 * passenger zone.
1037 *
1038 * @param driverId User id of the driver.
1039 * @return whether it succeeds.
1040 */
1041 private boolean startFirstPassenger(@UserIdInt int driverId) {
1042 int zoneId = getAvailablePassengerZone();
1043 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1044 Log.w(TAG_USER, "passenger occupant zone is not found");
1045 return false;
1046 }
1047 List<UserInfo> passengers = getPassengers(driverId);
1048 if (passengers.size() < 1) {
1049 Log.w(TAG_USER, "passenger is not found");
1050 return false;
1051 }
1052 // Only one passenger is supported. If there are two or more passengers, the first passenger
1053 // is chosen.
1054 int passengerId = passengers.get(0).id;
1055 if (!startPassenger(passengerId, zoneId)) {
1056 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1057 return false;
1058 }
1059 return true;
1060 }
1061
1062 private int getAvailablePassengerZone() {
1063 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1064 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1065 for (int occupantType : occupantTypes) {
1066 int zoneId = getZoneId(occupantType);
1067 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1068 return zoneId;
1069 }
1070 }
1071 return OccupantZoneInfo.INVALID_ZONE_ID;
1072 }
1073
1074 /**
1075 * Creates a new passenger user when there is no passenger user.
1076 */
1077 private void setupPassengerUser() {
1078 int currentUser = ActivityManager.getCurrentUser();
1079 int profileCount = getNumberOfManagedProfiles(currentUser);
1080 if (profileCount > 0) {
1081 Log.w(TAG_USER, "max profile of user" + currentUser
1082 + " is exceeded: current profile count is " + profileCount);
1083 return;
1084 }
1085 // TODO(b/140311342): Use resource string for the default passenger name.
1086 UserInfo passenger = createPassenger("Passenger", currentUser);
1087 if (passenger == null) {
1088 // Couldn't create user, most likely because there are too many.
1089 Log.w(TAG_USER, "cannot create a passenger user");
1090 return;
1091 }
1092 }
1093
1094 @NonNull
1095 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1096 ZoneUserBindingHelper helper = null;
1097 synchronized (mLockHelper) {
1098 if (mZoneUserBindingHelper == null) {
1099 Log.w(TAG_USER, "implementation is not delegated");
1100 return new ArrayList<OccupantZoneInfo>();
1101 }
1102 helper = mZoneUserBindingHelper;
1103 }
1104 return helper.getOccupantZones(occupantType);
1105 }
1106
1107 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1108 ZoneUserBindingHelper helper = null;
1109 synchronized (mLockHelper) {
1110 if (mZoneUserBindingHelper == null) {
1111 Log.w(TAG_USER, "implementation is not delegated");
1112 return false;
1113 }
1114 helper = mZoneUserBindingHelper;
1115 }
1116 return helper.assignUserToOccupantZone(userId, zoneId);
1117 }
1118
1119 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1120 ZoneUserBindingHelper helper = null;
1121 synchronized (mLockHelper) {
1122 if (mZoneUserBindingHelper == null) {
1123 Log.w(TAG_USER, "implementation is not delegated");
1124 return false;
1125 }
1126 helper = mZoneUserBindingHelper;
1127 }
1128 return helper.unassignUserFromOccupantZone(userId);
1129 }
1130
1131 private boolean isPassengerDisplayAvailable() {
1132 ZoneUserBindingHelper helper = null;
1133 synchronized (mLockHelper) {
1134 if (mZoneUserBindingHelper == null) {
1135 Log.w(TAG_USER, "implementation is not delegated");
1136 return false;
1137 }
1138 helper = mZoneUserBindingHelper;
1139 }
1140 return helper.isPassengerDisplayAvailable();
1141 }
1142
1143 /**
1144 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1145 * zone is returned.
1146 *
1147 * @param occupantType The type of an occupant.
1148 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1149 * if not found.
1150 */
1151 private int getZoneId(@OccupantTypeEnum int occupantType) {
1152 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1153 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1154 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001155}