blob: ed9a59c9e0b2a020df9940fe3436b22de4ff9d44 [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;
Eric Jeong3a793b02019-09-30 16:12:53 -070033import android.car.userlib.CarUserManagerHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070034import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070035import android.content.pm.UserInfo;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070036import android.graphics.Bitmap;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080037import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080038import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070039import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070040import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080041import android.os.Bundle;
Keun young Parkfb656372019-03-12 18:37:55 -070042import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080043import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070044import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070045import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070046import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070047import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080048import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080049import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070050
51import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070052import com.android.car.R;
Felipe Lemeabbf2da2020-02-24 18:25:29 -080053import com.android.car.hal.UserHalHelper;
Felipe Leme58412202020-01-09 13:45:33 -080054import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080055import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070056import com.android.internal.annotations.VisibleForTesting;
Felipe Leme5528ff72020-02-10 19:05:14 -080057import com.android.internal.os.IResultReceiver;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070058import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070059
60import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080061import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070062import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070063import java.util.Iterator;
64import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000065import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070066import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070067
68/**
69 * User service for cars. Manages users at boot time. Including:
70 *
71 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070072 * <li> Creates a user used as driver.
73 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070074 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070075 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076 * <ol/>
77 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070078public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080079
Felipe Lemeabbf2da2020-02-24 18:25:29 -080080 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080081 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080082 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080083 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080084 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080085 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080086 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
87 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -080088
Ying Zhengd3cb98e2018-05-11 11:42:48 -070089 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070090 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070091 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070092 private final UserManager mUserManager;
93 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -070094 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070095
Eric Jeongc91f9452019-08-30 15:04:21 -070096 private final Object mLockUser = new Object();
97 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -080098 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -070099 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800100 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700101 // Only one passenger is supported.
102 @GuardedBy("mLockUser")
103 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700104 /**
105 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800106 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700107 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700108 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700109 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
110 /**
111 * Keep the list of background users started here. This is wholly for debugging purpose.
112 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700113 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700114 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
115
Felipe Leme5528ff72020-02-10 19:05:14 -0800116 // TODO(b/144120654): mege then
Pavel Maltsev17e81832019-04-04 14:38:41 -0700117 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
118
Felipe Leme58412202020-01-09 13:45:33 -0800119 private final UserHalService mHal;
120
Felipe Leme5528ff72020-02-10 19:05:14 -0800121 /**
122 * List of lifecycle listeners by uid.
123 */
124 @GuardedBy("mLockUser")
125 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
126
127 // TODO(b/144120654): replace by CarUserManager listener
Pavel Maltsev17e81832019-04-04 14:38:41 -0700128 /** Interface for callbacks related to user activities. */
129 public interface UserCallback {
130 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700131 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700132 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700133 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700134 }
135
Eric Jeongc91f9452019-08-30 15:04:21 -0700136 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
137 new CopyOnWriteArrayList<>();
138
139 /** Interface for callbaks related to passenger activities. */
140 public interface PassengerCallback {
141 /** Called when passenger is started at a certain zone. */
142 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
143 /** Called when passenger is stopped. */
144 void onPassengerStopped(@UserIdInt int passengerId);
145 }
146
147 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
148 public interface ZoneUserBindingHelper {
149 /** Gets occupant zones corresponding to the occupant type. */
150 @NonNull
151 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
152 /** Assigns the user to the occupant zone. */
153 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
154 /** Makes the occupant zone unoccupied. */
155 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
156 /** Returns whether there is a passenger display. */
157 boolean isPassengerDisplayAvailable();
158 }
159
160 private final Object mLockHelper = new Object();
161 @GuardedBy("mLockHelper")
162 private ZoneUserBindingHelper mZoneUserBindingHelper;
163
Felipe Leme58412202020-01-09 13:45:33 -0800164 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
165 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700166 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700167 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
168 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700169 }
170 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800171 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700172 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700173 mAm = am;
174 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700175 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700176 mLastPassengerId = UserHandle.USER_NULL;
177 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700178 }
179
180 @Override
181 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700182 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
183 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700184 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700185 }
186
187 @Override
188 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700189 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
190 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700191 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700192 }
193
194 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700195 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700196 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700197 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800198 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700199 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800200 int numberListeners = mLifecycleListeners.size();
201 if (numberListeners == 0) {
202 writer.println("No lifecycle listeners");
203 } else {
204 writer.printf("%d lifecycle listeners\n", numberListeners);
205 for (int i = 0; i < numberListeners; i++) {
206 int uid = mLifecycleListeners.keyAt(i);
207 IResultReceiver listener = mLifecycleListeners.valueAt(i);
208 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
209 }
210 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700211 writer.println("User0Unlocked: " + mUser0Unlocked);
212 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
213 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
214 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700215 List<UserInfo> allDrivers = getAllDrivers();
216 int driversSize = allDrivers.size();
217 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700218 for (int i = 0; i < driversSize; i++) {
219 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800220 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700221 List<UserInfo> passengers = getPassengers(driverId);
222 int passengersSize = passengers.size();
223 writer.print(" NumberPassengers: " + passengersSize);
224 if (passengersSize > 0) {
225 writer.print(" [");
226 for (int j = 0; j < passengersSize; j++) {
227 writer.print(passengers.get(j).id);
228 if (j < passengersSize - 1) {
229 writer.print(" ");
230 }
231 }
232 writer.print("]");
233 }
234 writer.println();
235 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700236 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Keun-young Parkd462a912019-02-11 08:53:42 -0800237 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700238 }
239
240 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800241 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
242 *
243 * @param name The name of the driver to be created.
244 * @param admin Whether the created driver will be an admin.
245 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
246 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700247 */
248 @Override
249 @Nullable
250 public UserInfo createDriver(@NonNull String name, boolean admin) {
251 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000252 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700253 if (admin) {
254 return createNewAdminUser(name);
255 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700256 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700257 }
258
259 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800260 * Creates a passenger who is a profile of the given driver.
261 *
262 * @param name The name of the passenger to be created.
263 * @param driverId User id of the driver under whom a passenger is created.
264 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
265 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700266 */
267 @Override
268 @Nullable
269 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
270 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000271 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700272 UserInfo driver = mUserManager.getUserInfo(driverId);
273 if (driver == null) {
274 Log.w(TAG_USER, "the driver is invalid");
275 return null;
276 }
277 if (driver.isGuest()) {
278 Log.w(TAG_USER, "a guest driver cannot create a passenger");
279 return null;
280 }
Bookatz42fb1a62019-10-30 11:45:01 -0700281 UserInfo user = mUserManager.createProfileForUser(name,
282 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700283 if (user == null) {
284 // Couldn't create user, most likely because there are too many.
285 Log.w(TAG_USER, "can't create a profile for user" + driverId);
286 return null;
287 }
288 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700289 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700290 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700291 return user;
292 }
293
294 /**
295 * @see CarUserManager.switchDriver
296 */
297 @Override
298 public boolean switchDriver(@UserIdInt int driverId) {
299 checkManageUsersPermission("switchDriver");
300 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
301 // System user doesn't associate with real person, can not be switched to.
302 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
303 return false;
304 }
305 int userSwitchable = mUserManager.getUserSwitchability();
306 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
307 Log.w(TAG_USER, "current process is not allowed to switch user");
308 return false;
309 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700310 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700311 // The current user is already the given user.
312 return true;
313 }
314 try {
315 return mAm.switchUser(driverId);
316 } catch (RemoteException e) {
317 // ignore
318 Log.w(TAG_USER, "error while switching user", e);
319 }
320 return false;
321 }
322
323 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800324 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
325 *
326 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700327 */
328 @Override
329 @NonNull
330 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700331 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700332 return getUsers((user) -> {
333 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
334 && !user.isEphemeral();
335 });
336 }
337
338 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800339 * Returns all passengers under the given driver.
340 *
341 * @param driverId User id of a driver.
342 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700343 */
344 @Override
345 @NonNull
346 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700347 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700348 return getUsers((user) -> {
349 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
350 && user.profileGroupId == driverId;
351 });
352 }
353
354 /**
355 * @see CarUserManager.startPassenger
356 */
357 @Override
358 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
359 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700360 synchronized (mLockUser) {
361 try {
362 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
363 Log.w(TAG_USER, "could not start passenger");
364 return false;
365 }
366 } catch (RemoteException e) {
367 // ignore
368 Log.w(TAG_USER, "error while starting passenger", e);
369 return false;
370 }
371 if (!assignUserToOccupantZone(passengerId, zoneId)) {
372 Log.w(TAG_USER, "could not assign passenger to zone");
373 return false;
374 }
375 mLastPassengerId = passengerId;
376 }
377 for (PassengerCallback callback : mPassengerCallbacks) {
378 callback.onPassengerStarted(passengerId, zoneId);
379 }
380 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700381 }
382
383 /**
384 * @see CarUserManager.stopPassenger
385 */
386 @Override
387 public boolean stopPassenger(@UserIdInt int passengerId) {
388 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700389 return stopPassengerInternal(passengerId, true);
390 }
391
392 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
393 synchronized (mLockUser) {
394 UserInfo passenger = mUserManager.getUserInfo(passengerId);
395 if (passenger == null) {
396 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
397 return false;
398 }
399 if (mLastPassengerId != passengerId) {
400 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
401 return true;
402 }
403 if (checkCurrentDriver) {
404 int currentUser = ActivityManager.getCurrentUser();
405 if (passenger.profileGroupId != currentUser) {
406 Log.w(TAG_USER, "passenger " + passengerId
407 + " is not a profile of the current user");
408 return false;
409 }
410 }
411 // Passenger is a profile, so cannot be stopped through activity manager.
412 // Instead, activities started by the passenger are stopped and the passenger is
413 // unassigned from the zone.
414 stopAllTasks(passengerId);
415 if (!unassignUserFromOccupantZone(passengerId)) {
416 Log.w(TAG_USER, "could not unassign user from occupant zone");
417 return false;
418 }
419 mLastPassengerId = UserHandle.USER_NULL;
420 }
421 for (PassengerCallback callback : mPassengerCallbacks) {
422 callback.onPassengerStopped(passengerId);
423 }
424 return true;
425 }
426
427 private void stopAllTasks(@UserIdInt int userId) {
428 try {
429 for (StackInfo info : mAm.getAllStackInfos()) {
430 for (int i = 0; i < info.taskIds.length; i++) {
431 if (info.taskUserIds[i] == userId) {
432 int taskId = info.taskIds[i];
433 if (!mAm.removeTask(taskId)) {
434 Log.w(TAG_USER, "could not remove task " + taskId);
435 }
436 }
437 }
438 }
439 } catch (RemoteException e) {
440 Log.e(TAG_USER, "could not get stack info", e);
441 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700442 }
443
Felipe Leme5528ff72020-02-10 19:05:14 -0800444 @Override
445 public void setLifecycleListenerForUid(IResultReceiver listener) {
446 int uid = Binder.getCallingUid();
447 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
448
449 try {
450 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
451 } catch (RemoteException e) {
452 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
453 }
454 synchronized (mLockUser) {
455 mLifecycleListeners.append(uid, listener);
456 }
457 }
458
459 private void onListenerDeath(int uid) {
460 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
461 synchronized (mLockUser) {
462 removeLifecycleListenerLocked(uid);
463 }
464 }
465
466 @Override
467 public void resetLifecycleListenerForUid() {
468 int uid = Binder.getCallingUid();
469 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
470
471 synchronized (mLockUser) {
472 removeLifecycleListenerLocked(uid);
473 }
474 }
475
476 private void removeLifecycleListenerLocked(int uid) {
477 mLifecycleListeners.remove(uid);
478 }
479
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800480 @Override
481 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800482 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800483 Objects.requireNonNull(receiver, "receiver cannot be null");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800484 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800485 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
486 try {
487 Bundle resultData = null;
488 if (resp != null) {
489 switch (resp.action) {
490 case InitialUserInfoResponseAction.SWITCH:
491 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800492 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800493 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
494 break;
495 case InitialUserInfoResponseAction.CREATE:
496 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800497 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800498 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
499 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
500 break;
501 case InitialUserInfoResponseAction.DEFAULT:
502 // do nothing
503 break;
504 default:
505 // That's ok, it will be the same as DEFAULT...
506 Log.w(TAG_USER, "invalid response action on " + resp);
507 }
508 }
509 receiver.send(status, resultData);
510 } catch (RemoteException e) {
511 Log.w(TAG_USER, "Could not send result back to receiver", e);
512 }
513 });
514 }
515
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800516 // TODO(b/144120654): use helper to generate UsersInfo
517 private UsersInfo getUsersInfo() {
518 UserInfo currentUser;
519 try {
520 currentUser = mAm.getCurrentUser();
521 } catch (RemoteException e) {
522 // shouldn't happen
523 throw new IllegalStateException("Could not get current user: ", e);
524 }
525 List<UserInfo> existingUsers = mUserManager.getUsers();
526 int size = existingUsers.size();
527
528 UsersInfo usersInfo = new UsersInfo();
529 usersInfo.numberUsers = size;
530 usersInfo.currentUser.userId = currentUser.id;
531 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
532
533 for (int i = 0; i < size; i++) {
534 UserInfo androidUser = existingUsers.get(i);
535 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
536 new android.hardware.automotive.vehicle.V2_0.UserInfo();
537 halUser.userId = androidUser.id;
538 halUser.flags = UserHalHelper.convertFlags(androidUser);
539 usersInfo.existingUsers.add(halUser);
540 }
541
542 return usersInfo;
543 }
544
Eric Jeong1545f3b2019-09-16 13:56:52 -0700545 /** Returns whether the given user is a system user. */
546 private static boolean isSystemUser(@UserIdInt int userId) {
547 return userId == UserHandle.USER_SYSTEM;
548 }
549
Keun young Park13a7a822019-04-04 15:53:08 -0700550 private void updateDefaultUserRestriction() {
551 // We want to set restrictions on system and guest users only once. These are persisted
552 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
553 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700554 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
555 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700556 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700557 // Only apply the system user restrictions if the system user is headless.
558 if (UserManager.isHeadlessSystemUserMode()) {
559 setSystemUserRestrictions();
560 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700561 Settings.Global.putInt(mContext.getContentResolver(),
562 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700563 }
564
Eric Jeong1545f3b2019-09-16 13:56:52 -0700565 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700566 return !mUserManager.getUserInfo(userId).isEphemeral();
567 }
568
Eric Jeong1545f3b2019-09-16 13:56:52 -0700569 /** Adds callback to listen to user activity events. */
570 public void addUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000571 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700572 mUserCallbacks.add(callback);
573 }
574
Yabin Huang27712d72019-06-26 12:46:30 -0700575 /** Removes previously added callback to listen user events. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700576 public void removeUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000577 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700578 mUserCallbacks.remove(callback);
579 }
580
Eric Jeongc91f9452019-08-30 15:04:21 -0700581 /** Adds callback to listen to passenger activity events. */
582 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000583 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700584 mPassengerCallbacks.add(callback);
585 }
586
587 /** Removes previously added callback to listen passenger events. */
588 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000589 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700590 mPassengerCallbacks.remove(callback);
591 }
592
593 /** Sets the implementation of ZoneUserBindingHelper. */
594 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
595 synchronized (mLockHelper) {
596 mZoneUserBindingHelper = helper;
597 }
598 }
599
Keun-young Parkd462a912019-02-11 08:53:42 -0800600 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700601 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
602 *
603 * @param userId User id whoes lock status is changed.
604 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800605 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700606 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Mayank Garg31e73042020-01-23 00:10:38 -0800607 TimingsTraceLog t = new TimingsTraceLog(TAG_USER,
608 Trace.TRACE_TAG_SYSTEM_SERVER);
609 t.traceBegin("onUserLockChanged-" + userId
610 + (unlocked ? "-unlocked" : "-locked"));
Pavel Maltsev17e81832019-04-04 14:38:41 -0700611 for (UserCallback callback : mUserCallbacks) {
Mayank Garg31e73042020-01-23 00:10:38 -0800612 t.traceBegin("onUserLockChanged-"
613 + callback.getClass().getSimpleName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700614 callback.onUserLockChanged(userId, unlocked);
Mayank Garg31e73042020-01-23 00:10:38 -0800615 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700616 }
Mayank Garg31e73042020-01-23 00:10:38 -0800617 t.traceEnd();
618
Keun young Parkf3523cd2019-04-08 10:09:17 -0700619 if (!unlocked) { // nothing else to do when it is locked back.
620 return;
621 }
Mayank Garg31e73042020-01-23 00:10:38 -0800622
623 t.traceBegin("setUserLockStatus-UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800624 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700625 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700626 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700627 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
628 updateDefaultUserRestriction();
629 tasks = new ArrayList<>(mUser0UnlockTasks);
630 mUser0UnlockTasks.clear();
631 mUser0Unlocked = unlocked;
632 }
633 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700634 Integer user = userId;
635 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700636 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700637 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700638 mBackgroundUsersToRestart.remove(user);
639 mBackgroundUsersToRestart.add(0, user);
640 }
641 // -1 for user 0
642 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700643 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700644 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700645 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700646 + ", dropping least recently user from restart list:" + userToDrop);
647 // Drop the least recently used user.
648 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
649 }
650 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800651 }
652 }
653 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700654 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800655 for (Runnable r : tasks) {
656 r.run();
657 }
658 }
Mayank Garg31e73042020-01-23 00:10:38 -0800659 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800660 }
661
662 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700663 * Starts all background users that were active in system.
664 *
Keun young Parkfb656372019-03-12 18:37:55 -0700665 * @return list of background users started successfully.
666 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700667 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700668 public ArrayList<Integer> startAllBackgroundUsers() {
669 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700670 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700671 users = new ArrayList<>(mBackgroundUsersToRestart);
672 mBackgroundUsersRestartedHere.clear();
673 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700674 }
675 ArrayList<Integer> startedUsers = new ArrayList<>();
676 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700677 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700678 continue;
679 }
680 try {
681 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700682 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
683 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700684 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700685 } else if (mAm.unlockUser(user, null, null, null)) {
686 startedUsers.add(user);
687 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700688 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700689 if (mUserManager.isUserRunning(user)) {
690 // add to started list so that it can be stopped later.
691 startedUsers.add(user);
692 }
Keun young Parkfb656372019-03-12 18:37:55 -0700693 }
694 }
695 } catch (RemoteException e) {
696 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700697 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700698 }
699 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700700 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700701 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700702 ArrayList<Integer> usersToRemove = new ArrayList<>();
703 for (Integer user : mBackgroundUsersToRestart) {
704 if (!startedUsers.contains(user)) {
705 usersToRemove.add(user);
706 }
707 }
708 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
709 }
Keun young Parkfb656372019-03-12 18:37:55 -0700710 return startedUsers;
711 }
712
713 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700714 * Stops all background users that were active in system.
715 *
716 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700717 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700718 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700719 if (userId == UserHandle.USER_SYSTEM) {
720 return false;
721 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700722 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700723 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700724 return false;
725 }
726 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700727 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700728 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700729 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700730 Integer user = userId;
731 mBackgroundUsersRestartedHere.remove(user);
732 }
733 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
734 return false;
735 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700736 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700737 return false;
738 }
739 } catch (RemoteException e) {
740 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700741 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700742 }
743 return true;
744 }
745
746 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700747 * Called when new foreground user started to boot.
748 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700749 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700750 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700751 public void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800752 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
753 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800754 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800755
Felipe Lemef45ee502019-12-19 10:00:14 -0800756 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700757 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700758 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700759 if (mLastPassengerId != UserHandle.USER_NULL) {
760 stopPassengerInternal(mLastPassengerId, false);
761 }
762 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
763 setupPassengerUser();
764 startFirstPassenger(userId);
765 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800766
767 // TODO(b/144120654): right now just the app listeners are running in the background so the
768 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
769 // but once we refactor the car service callback into lifecycle listeners, we should use a
770 // proper thread management (like a Threadpool / executor);
771
772 int listenersSize = mLifecycleListeners.size();
773 if (listenersSize == 0) {
774 Log.i(TAG_USER, "Not notifying app listeners");
775 } else {
776 new Thread(() -> {
777 // Must use a different TimingsTraceLog because it's another thread
778 TimingsTraceLog t2 = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
779 Log.i(TAG_USER, "Notifying " + listenersSize + " listeners");
780 for (int i = 0; i < listenersSize; i++) {
781 int uid = mLifecycleListeners.keyAt(i);
782 IResultReceiver listener = mLifecycleListeners.valueAt(i);
783 t2.traceBegin("notify-listener-" + uid);
784 Bundle data = new Bundle();
785 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION,
786 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
787 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
788 // can set BUNDLE_PARAM_PREVIOUS_USER_HANDLE
789 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
790 Log.d(TAG_USER, "Notifying listener for uid " + uid);
791 }
792 try {
793 listener.send(userId, data);
794 } catch (RemoteException e) {
795 Log.e(TAG_USER, "Error calling lifecycle listener", e);
796 } finally {
797 t2.traceEnd();
798 }
799 }
800
801 }, "SwitchUser-" + userId + "-Listeners").start();
802 }
803
804 Log.i(TAG_USER, "Notifying " + mUserCallbacks.size() + " callbacks");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700805 for (UserCallback callback : mUserCallbacks) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800806 t.traceBegin("onSwitchUser-" + callback.getClass().getName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700807 callback.onSwitchUser(userId);
Mayank Garg31e73042020-01-23 00:10:38 -0800808 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700809 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800810 t.traceEnd(); // onSwitchUser
811
Pavel Maltsev17e81832019-04-04 14:38:41 -0700812 }
813
814 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700815 * 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 -0800816 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700817 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800818 * @param r Runnable to run.
819 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700820 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000821 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800822 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700823 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800824 if (mUser0Unlocked) {
825 runNow = true;
826 } else {
827 mUser0UnlockTasks.add(r);
828 }
829 }
830 if (runNow) {
831 r.run();
832 }
833 }
834
Keun young Parkf3523cd2019-04-08 10:09:17 -0700835 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700836 @NonNull
837 ArrayList<Integer> getBackgroundUsersToRestart() {
838 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700839 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700840 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
841 }
842 return backgroundUsersToRestart;
843 }
844
Ying Zheng1ab32b62018-06-26 12:47:26 -0700845 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700846 // Disable Location service for system user.
847 LocationManager locationManager =
848 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800849 locationManager.setLocationEnabledForUser(
850 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700851 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700852
853 /**
854 * Creates a new user on the system, the created user would be granted admin role.
855 *
856 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700857 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700858 */
859 @Nullable
860 private UserInfo createNewAdminUser(String name) {
861 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
862 // Only admins or system user can create other privileged users.
863 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
864 return null;
865 }
866
867 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
868 if (user == null) {
869 // Couldn't create user, most likely because there are too many.
870 Log.w(TAG_USER, "can't create admin user.");
871 return null;
872 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700873 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700874
875 return user;
876 }
877
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700878 /**
879 * Assigns a default icon to a user according to the user's id.
880 *
881 * @param userInfo User whose avatar is set to default icon.
882 * @return Bitmap of the user icon.
883 */
884 private Bitmap assignDefaultIcon(UserInfo userInfo) {
885 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
886 Bitmap bitmap = UserIcons.convertToBitmap(
887 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
888 mUserManager.setUserIcon(userInfo.id, bitmap);
889 return bitmap;
890 }
891
Eric Jeong1545f3b2019-09-16 13:56:52 -0700892 private interface UserFilter {
893 boolean isEligibleUser(UserInfo user);
894 }
895
896 /** Returns all users who are matched by the given filter. */
897 private List<UserInfo> getUsers(UserFilter filter) {
898 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
899
900 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
901 UserInfo user = iterator.next();
902 if (!filter.isEligibleUser(user)) {
903 iterator.remove();
904 }
905 }
906 return users;
907 }
908
909 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700910 * Enforces that apps which have the
911 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
912 * can make certain calls to the CarUserManager.
913 *
914 * @param message used as message if SecurityException is thrown.
915 * @throws SecurityException if the caller is not system or root.
916 */
917 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -0700918 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
919 }
920
921 private static void checkManageUsersOrDumpPermission(String message) {
922 checkAtLeastOnePermission(message,
923 android.Manifest.permission.MANAGE_USERS,
924 android.Manifest.permission.DUMP);
925 }
926
Felipe Leme5528ff72020-02-10 19:05:14 -0800927 private void checkInteractAcrossUsersPermission(String message) {
928 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
929 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
930 }
931
felipeal2d0483c2019-11-02 14:07:22 -0700932 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700933 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -0700934 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
935 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -0800936 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700937 }
938 }
939
felipeal2d0483c2019-11-02 14:07:22 -0700940 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
941 for (String permission : permissions) {
942 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
943 /* exported = */ true)
944 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
945 return true;
946 }
947 }
948 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700949 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700950
951 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
952 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
953 // Count all users that are managed profiles of the given user.
954 int managedProfilesCount = 0;
955 for (UserInfo user : users) {
956 if (user.isManagedProfile() && user.profileGroupId == userId) {
957 managedProfilesCount++;
958 }
959 }
960 return managedProfilesCount;
961 }
962
963 /**
964 * Starts the first passenger of the given driver and assigns the passenger to the front
965 * passenger zone.
966 *
967 * @param driverId User id of the driver.
968 * @return whether it succeeds.
969 */
970 private boolean startFirstPassenger(@UserIdInt int driverId) {
971 int zoneId = getAvailablePassengerZone();
972 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
973 Log.w(TAG_USER, "passenger occupant zone is not found");
974 return false;
975 }
976 List<UserInfo> passengers = getPassengers(driverId);
977 if (passengers.size() < 1) {
978 Log.w(TAG_USER, "passenger is not found");
979 return false;
980 }
981 // Only one passenger is supported. If there are two or more passengers, the first passenger
982 // is chosen.
983 int passengerId = passengers.get(0).id;
984 if (!startPassenger(passengerId, zoneId)) {
985 Log.w(TAG_USER, "cannot start passenger " + passengerId);
986 return false;
987 }
988 return true;
989 }
990
991 private int getAvailablePassengerZone() {
992 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
993 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
994 for (int occupantType : occupantTypes) {
995 int zoneId = getZoneId(occupantType);
996 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
997 return zoneId;
998 }
999 }
1000 return OccupantZoneInfo.INVALID_ZONE_ID;
1001 }
1002
1003 /**
1004 * Creates a new passenger user when there is no passenger user.
1005 */
1006 private void setupPassengerUser() {
1007 int currentUser = ActivityManager.getCurrentUser();
1008 int profileCount = getNumberOfManagedProfiles(currentUser);
1009 if (profileCount > 0) {
1010 Log.w(TAG_USER, "max profile of user" + currentUser
1011 + " is exceeded: current profile count is " + profileCount);
1012 return;
1013 }
1014 // TODO(b/140311342): Use resource string for the default passenger name.
1015 UserInfo passenger = createPassenger("Passenger", currentUser);
1016 if (passenger == null) {
1017 // Couldn't create user, most likely because there are too many.
1018 Log.w(TAG_USER, "cannot create a passenger user");
1019 return;
1020 }
1021 }
1022
1023 @NonNull
1024 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1025 ZoneUserBindingHelper helper = null;
1026 synchronized (mLockHelper) {
1027 if (mZoneUserBindingHelper == null) {
1028 Log.w(TAG_USER, "implementation is not delegated");
1029 return new ArrayList<OccupantZoneInfo>();
1030 }
1031 helper = mZoneUserBindingHelper;
1032 }
1033 return helper.getOccupantZones(occupantType);
1034 }
1035
1036 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1037 ZoneUserBindingHelper helper = null;
1038 synchronized (mLockHelper) {
1039 if (mZoneUserBindingHelper == null) {
1040 Log.w(TAG_USER, "implementation is not delegated");
1041 return false;
1042 }
1043 helper = mZoneUserBindingHelper;
1044 }
1045 return helper.assignUserToOccupantZone(userId, zoneId);
1046 }
1047
1048 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1049 ZoneUserBindingHelper helper = null;
1050 synchronized (mLockHelper) {
1051 if (mZoneUserBindingHelper == null) {
1052 Log.w(TAG_USER, "implementation is not delegated");
1053 return false;
1054 }
1055 helper = mZoneUserBindingHelper;
1056 }
1057 return helper.unassignUserFromOccupantZone(userId);
1058 }
1059
1060 private boolean isPassengerDisplayAvailable() {
1061 ZoneUserBindingHelper helper = null;
1062 synchronized (mLockHelper) {
1063 if (mZoneUserBindingHelper == null) {
1064 Log.w(TAG_USER, "implementation is not delegated");
1065 return false;
1066 }
1067 helper = mZoneUserBindingHelper;
1068 }
1069 return helper.isPassengerDisplayAvailable();
1070 }
1071
1072 /**
1073 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1074 * zone is returned.
1075 *
1076 * @param occupantType The type of an occupant.
1077 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1078 * if not found.
1079 */
1080 private int getZoneId(@OccupantTypeEnum int occupantType) {
1081 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1082 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1083 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001084}