blob: 96ab84138eeb1e7947c259199dee2210c1a5b7ff [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;
Eric Jeong3a793b02019-09-30 16:12:53 -070032import android.car.userlib.CarUserManagerHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070033import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070034import android.content.pm.UserInfo;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070035import android.graphics.Bitmap;
Ying Zheng1ab32b62018-06-26 12:47:26 -070036import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070037import android.os.Binder;
Keun young Parkfb656372019-03-12 18:37:55 -070038import android.os.RemoteException;
Ying Zhengcf20f442018-06-22 16:54:51 -070039import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070040import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070041import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070042import android.util.Log;
43
44import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070045import com.android.car.R;
Keun-young Parkd462a912019-02-11 08:53:42 -080046import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070047import com.android.internal.annotations.VisibleForTesting;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070048import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070049
50import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080051import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070052import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070053import java.util.Iterator;
54import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000055import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070056import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070057
58/**
59 * User service for cars. Manages users at boot time. Including:
60 *
61 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070062 * <li> Creates a user used as driver.
63 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070064 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070065 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070066 * <ol/>
67 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070068public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Ying Zhengd3cb98e2018-05-11 11:42:48 -070069 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070070 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070071 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070072 private final UserManager mUserManager;
73 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -070074 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070075
Eric Jeongc91f9452019-08-30 15:04:21 -070076 private final Object mLockUser = new Object();
77 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -080078 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -070079 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -080080 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -070081 // Only one passenger is supported.
82 @GuardedBy("mLockUser")
83 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -070084 /**
85 * Background users that will be restarted in garage mode. This list can include the
86 * current foreground user bit the current foreground user should not be restarted.
87 */
Eric Jeongc91f9452019-08-30 15:04:21 -070088 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -070089 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
90 /**
91 * Keep the list of background users started here. This is wholly for debugging purpose.
92 */
Eric Jeongc91f9452019-08-30 15:04:21 -070093 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -070094 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
95
Pavel Maltsev17e81832019-04-04 14:38:41 -070096 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
97
98 /** Interface for callbacks related to user activities. */
99 public interface UserCallback {
100 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700101 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700102 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700103 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700104 }
105
Eric Jeongc91f9452019-08-30 15:04:21 -0700106 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
107 new CopyOnWriteArrayList<>();
108
109 /** Interface for callbaks related to passenger activities. */
110 public interface PassengerCallback {
111 /** Called when passenger is started at a certain zone. */
112 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
113 /** Called when passenger is stopped. */
114 void onPassengerStopped(@UserIdInt int passengerId);
115 }
116
117 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
118 public interface ZoneUserBindingHelper {
119 /** Gets occupant zones corresponding to the occupant type. */
120 @NonNull
121 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
122 /** Assigns the user to the occupant zone. */
123 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
124 /** Makes the occupant zone unoccupied. */
125 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
126 /** Returns whether there is a passenger display. */
127 boolean isPassengerDisplayAvailable();
128 }
129
130 private final Object mLockHelper = new Object();
131 @GuardedBy("mLockHelper")
132 private ZoneUserBindingHelper mZoneUserBindingHelper;
133
Eric Jeong3a793b02019-09-30 16:12:53 -0700134 public CarUserService(
135 @NonNull Context context, @NonNull CarUserManagerHelper carUserManagerHelper,
136 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700137 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
138 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700139 }
140 mContext = context;
Eric Jeong3a793b02019-09-30 16:12:53 -0700141 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700142 mAm = am;
143 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700144 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700145 mLastPassengerId = UserHandle.USER_NULL;
146 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700147 }
148
149 @Override
150 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700151 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
152 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700153 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700154 }
155
156 @Override
157 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700158 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
159 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700160 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700161 }
162
163 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700164 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700165 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700166 writer.println("*CarUserService*");
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700168 writer.println("User0Unlocked: " + mUser0Unlocked);
169 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
170 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
171 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700172 List<UserInfo> allDrivers = getAllDrivers();
173 int driversSize = allDrivers.size();
174 writer.println("NumberOfDrivers: " + driversSize);
175 String prefix = " ";
176 for (int i = 0; i < driversSize; i++) {
177 int driverId = allDrivers.get(i).id;
178 writer.print(prefix + "#" + i + ": id=" + driverId);
179 List<UserInfo> passengers = getPassengers(driverId);
180 int passengersSize = passengers.size();
181 writer.print(" NumberPassengers: " + passengersSize);
182 if (passengersSize > 0) {
183 writer.print(" [");
184 for (int j = 0; j < passengersSize; j++) {
185 writer.print(passengers.get(j).id);
186 if (j < passengersSize - 1) {
187 writer.print(" ");
188 }
189 }
190 writer.print("]");
191 }
192 writer.println();
193 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700194 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Keun-young Parkd462a912019-02-11 08:53:42 -0800195 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700196 }
197
198 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800199 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
200 *
201 * @param name The name of the driver to be created.
202 * @param admin Whether the created driver will be an admin.
203 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
204 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700205 */
206 @Override
207 @Nullable
208 public UserInfo createDriver(@NonNull String name, boolean admin) {
209 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000210 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700211 if (admin) {
212 return createNewAdminUser(name);
213 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700214 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700215 }
216
217 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800218 * Creates a passenger who is a profile of the given driver.
219 *
220 * @param name The name of the passenger to be created.
221 * @param driverId User id of the driver under whom a passenger is created.
222 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
223 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700224 */
225 @Override
226 @Nullable
227 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
228 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000229 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700230 UserInfo driver = mUserManager.getUserInfo(driverId);
231 if (driver == null) {
232 Log.w(TAG_USER, "the driver is invalid");
233 return null;
234 }
235 if (driver.isGuest()) {
236 Log.w(TAG_USER, "a guest driver cannot create a passenger");
237 return null;
238 }
Bookatz42fb1a62019-10-30 11:45:01 -0700239 UserInfo user = mUserManager.createProfileForUser(name,
240 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700241 if (user == null) {
242 // Couldn't create user, most likely because there are too many.
243 Log.w(TAG_USER, "can't create a profile for user" + driverId);
244 return null;
245 }
246 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700247 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700248 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700249 return user;
250 }
251
252 /**
253 * @see CarUserManager.switchDriver
254 */
255 @Override
256 public boolean switchDriver(@UserIdInt int driverId) {
257 checkManageUsersPermission("switchDriver");
258 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
259 // System user doesn't associate with real person, can not be switched to.
260 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
261 return false;
262 }
263 int userSwitchable = mUserManager.getUserSwitchability();
264 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
265 Log.w(TAG_USER, "current process is not allowed to switch user");
266 return false;
267 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700268 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700269 // The current user is already the given user.
270 return true;
271 }
272 try {
273 return mAm.switchUser(driverId);
274 } catch (RemoteException e) {
275 // ignore
276 Log.w(TAG_USER, "error while switching user", e);
277 }
278 return false;
279 }
280
281 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800282 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
283 *
284 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700285 */
286 @Override
287 @NonNull
288 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700289 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700290 return getUsers((user) -> {
291 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
292 && !user.isEphemeral();
293 });
294 }
295
296 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800297 * Returns all passengers under the given driver.
298 *
299 * @param driverId User id of a driver.
300 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700301 */
302 @Override
303 @NonNull
304 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700305 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700306 return getUsers((user) -> {
307 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
308 && user.profileGroupId == driverId;
309 });
310 }
311
312 /**
313 * @see CarUserManager.startPassenger
314 */
315 @Override
316 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
317 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700318 synchronized (mLockUser) {
319 try {
320 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
321 Log.w(TAG_USER, "could not start passenger");
322 return false;
323 }
324 } catch (RemoteException e) {
325 // ignore
326 Log.w(TAG_USER, "error while starting passenger", e);
327 return false;
328 }
329 if (!assignUserToOccupantZone(passengerId, zoneId)) {
330 Log.w(TAG_USER, "could not assign passenger to zone");
331 return false;
332 }
333 mLastPassengerId = passengerId;
334 }
335 for (PassengerCallback callback : mPassengerCallbacks) {
336 callback.onPassengerStarted(passengerId, zoneId);
337 }
338 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700339 }
340
341 /**
342 * @see CarUserManager.stopPassenger
343 */
344 @Override
345 public boolean stopPassenger(@UserIdInt int passengerId) {
346 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700347 return stopPassengerInternal(passengerId, true);
348 }
349
350 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
351 synchronized (mLockUser) {
352 UserInfo passenger = mUserManager.getUserInfo(passengerId);
353 if (passenger == null) {
354 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
355 return false;
356 }
357 if (mLastPassengerId != passengerId) {
358 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
359 return true;
360 }
361 if (checkCurrentDriver) {
362 int currentUser = ActivityManager.getCurrentUser();
363 if (passenger.profileGroupId != currentUser) {
364 Log.w(TAG_USER, "passenger " + passengerId
365 + " is not a profile of the current user");
366 return false;
367 }
368 }
369 // Passenger is a profile, so cannot be stopped through activity manager.
370 // Instead, activities started by the passenger are stopped and the passenger is
371 // unassigned from the zone.
372 stopAllTasks(passengerId);
373 if (!unassignUserFromOccupantZone(passengerId)) {
374 Log.w(TAG_USER, "could not unassign user from occupant zone");
375 return false;
376 }
377 mLastPassengerId = UserHandle.USER_NULL;
378 }
379 for (PassengerCallback callback : mPassengerCallbacks) {
380 callback.onPassengerStopped(passengerId);
381 }
382 return true;
383 }
384
385 private void stopAllTasks(@UserIdInt int userId) {
386 try {
387 for (StackInfo info : mAm.getAllStackInfos()) {
388 for (int i = 0; i < info.taskIds.length; i++) {
389 if (info.taskUserIds[i] == userId) {
390 int taskId = info.taskIds[i];
391 if (!mAm.removeTask(taskId)) {
392 Log.w(TAG_USER, "could not remove task " + taskId);
393 }
394 }
395 }
396 }
397 } catch (RemoteException e) {
398 Log.e(TAG_USER, "could not get stack info", e);
399 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700400 }
401
402 /** Returns whether the given user is a system user. */
403 private static boolean isSystemUser(@UserIdInt int userId) {
404 return userId == UserHandle.USER_SYSTEM;
405 }
406
Keun young Park13a7a822019-04-04 15:53:08 -0700407 private void updateDefaultUserRestriction() {
408 // We want to set restrictions on system and guest users only once. These are persisted
409 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
410 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700411 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
412 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700413 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700414 // Only apply the system user restrictions if the system user is headless.
415 if (UserManager.isHeadlessSystemUserMode()) {
416 setSystemUserRestrictions();
417 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700418 Settings.Global.putInt(mContext.getContentResolver(),
419 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700420 }
421
Eric Jeong1545f3b2019-09-16 13:56:52 -0700422 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700423 return !mUserManager.getUserInfo(userId).isEphemeral();
424 }
425
Eric Jeong1545f3b2019-09-16 13:56:52 -0700426 /** Adds callback to listen to user activity events. */
427 public void addUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000428 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700429 mUserCallbacks.add(callback);
430 }
431
Yabin Huang27712d72019-06-26 12:46:30 -0700432 /** Removes previously added callback to listen user events. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700433 public void removeUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000434 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700435 mUserCallbacks.remove(callback);
436 }
437
Eric Jeongc91f9452019-08-30 15:04:21 -0700438 /** Adds callback to listen to passenger activity events. */
439 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000440 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700441 mPassengerCallbacks.add(callback);
442 }
443
444 /** Removes previously added callback to listen passenger events. */
445 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000446 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700447 mPassengerCallbacks.remove(callback);
448 }
449
450 /** Sets the implementation of ZoneUserBindingHelper. */
451 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
452 synchronized (mLockHelper) {
453 mZoneUserBindingHelper = helper;
454 }
455 }
456
Keun-young Parkd462a912019-02-11 08:53:42 -0800457 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700458 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
459 *
460 * @param userId User id whoes lock status is changed.
461 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800462 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700463 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Pavel Maltsev17e81832019-04-04 14:38:41 -0700464 for (UserCallback callback : mUserCallbacks) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700465 callback.onUserLockChanged(userId, unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700466 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700467 if (!unlocked) { // nothing else to do when it is locked back.
468 return;
469 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800470 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700471 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700472 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700473 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
474 updateDefaultUserRestriction();
475 tasks = new ArrayList<>(mUser0UnlockTasks);
476 mUser0UnlockTasks.clear();
477 mUser0Unlocked = unlocked;
478 }
479 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700480 Integer user = userId;
481 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700482 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700483 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700484 mBackgroundUsersToRestart.remove(user);
485 mBackgroundUsersToRestart.add(0, user);
486 }
487 // -1 for user 0
488 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700489 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700490 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700491 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700492 + ", dropping least recently user from restart list:" + userToDrop);
493 // Drop the least recently used user.
494 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
495 }
496 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800497 }
498 }
499 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700500 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800501 for (Runnable r : tasks) {
502 r.run();
503 }
504 }
505 }
506
507 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700508 * Starts all background users that were active in system.
509 *
Keun young Parkfb656372019-03-12 18:37:55 -0700510 * @return list of background users started successfully.
511 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700512 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700513 public ArrayList<Integer> startAllBackgroundUsers() {
514 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700515 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700516 users = new ArrayList<>(mBackgroundUsersToRestart);
517 mBackgroundUsersRestartedHere.clear();
518 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700519 }
520 ArrayList<Integer> startedUsers = new ArrayList<>();
521 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700522 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700523 continue;
524 }
525 try {
526 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700527 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
528 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700529 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700530 } else if (mAm.unlockUser(user, null, null, null)) {
531 startedUsers.add(user);
532 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700533 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700534 if (mUserManager.isUserRunning(user)) {
535 // add to started list so that it can be stopped later.
536 startedUsers.add(user);
537 }
Keun young Parkfb656372019-03-12 18:37:55 -0700538 }
539 }
540 } catch (RemoteException e) {
541 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700542 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700543 }
544 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700545 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700546 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700547 ArrayList<Integer> usersToRemove = new ArrayList<>();
548 for (Integer user : mBackgroundUsersToRestart) {
549 if (!startedUsers.contains(user)) {
550 usersToRemove.add(user);
551 }
552 }
553 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
554 }
Keun young Parkfb656372019-03-12 18:37:55 -0700555 return startedUsers;
556 }
557
558 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700559 * Stops all background users that were active in system.
560 *
561 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700562 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700563 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700564 if (userId == UserHandle.USER_SYSTEM) {
565 return false;
566 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700567 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700568 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700569 return false;
570 }
571 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700572 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700573 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700574 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700575 Integer user = userId;
576 mBackgroundUsersRestartedHere.remove(user);
577 }
578 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
579 return false;
580 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700581 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700582 return false;
583 }
584 } catch (RemoteException e) {
585 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700586 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700587 }
588 return true;
589 }
590
591 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700592 * Called when new foreground user started to boot.
593 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700594 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700595 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700596 public void onSwitchUser(@UserIdInt int userId) {
597 if (!isSystemUser(userId) && isPersistentUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700598 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700599 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700600 if (mLastPassengerId != UserHandle.USER_NULL) {
601 stopPassengerInternal(mLastPassengerId, false);
602 }
603 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
604 setupPassengerUser();
605 startFirstPassenger(userId);
606 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700607 for (UserCallback callback : mUserCallbacks) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700608 callback.onSwitchUser(userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700609 }
610 }
611
612 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700613 * 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 -0800614 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700615 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800616 * @param r Runnable to run.
617 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700618 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000619 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800620 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700621 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800622 if (mUser0Unlocked) {
623 runNow = true;
624 } else {
625 mUser0UnlockTasks.add(r);
626 }
627 }
628 if (runNow) {
629 r.run();
630 }
631 }
632
Keun young Parkf3523cd2019-04-08 10:09:17 -0700633 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700634 @NonNull
635 ArrayList<Integer> getBackgroundUsersToRestart() {
636 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700637 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700638 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
639 }
640 return backgroundUsersToRestart;
641 }
642
Ying Zheng1ab32b62018-06-26 12:47:26 -0700643 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700644 // Disable Location service for system user.
645 LocationManager locationManager =
646 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800647 locationManager.setLocationEnabledForUser(
648 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700649 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700650
651 /**
652 * Creates a new user on the system, the created user would be granted admin role.
653 *
654 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700655 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700656 */
657 @Nullable
658 private UserInfo createNewAdminUser(String name) {
659 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
660 // Only admins or system user can create other privileged users.
661 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
662 return null;
663 }
664
665 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
666 if (user == null) {
667 // Couldn't create user, most likely because there are too many.
668 Log.w(TAG_USER, "can't create admin user.");
669 return null;
670 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700671 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700672
673 return user;
674 }
675
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700676 /**
677 * Assigns a default icon to a user according to the user's id.
678 *
679 * @param userInfo User whose avatar is set to default icon.
680 * @return Bitmap of the user icon.
681 */
682 private Bitmap assignDefaultIcon(UserInfo userInfo) {
683 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
684 Bitmap bitmap = UserIcons.convertToBitmap(
685 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
686 mUserManager.setUserIcon(userInfo.id, bitmap);
687 return bitmap;
688 }
689
Eric Jeong1545f3b2019-09-16 13:56:52 -0700690 private interface UserFilter {
691 boolean isEligibleUser(UserInfo user);
692 }
693
694 /** Returns all users who are matched by the given filter. */
695 private List<UserInfo> getUsers(UserFilter filter) {
696 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
697
698 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
699 UserInfo user = iterator.next();
700 if (!filter.isEligibleUser(user)) {
701 iterator.remove();
702 }
703 }
704 return users;
705 }
706
707 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700708 * Enforces that apps which have the
709 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
710 * can make certain calls to the CarUserManager.
711 *
712 * @param message used as message if SecurityException is thrown.
713 * @throws SecurityException if the caller is not system or root.
714 */
715 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -0700716 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
717 }
718
719 private static void checkManageUsersOrDumpPermission(String message) {
720 checkAtLeastOnePermission(message,
721 android.Manifest.permission.MANAGE_USERS,
722 android.Manifest.permission.DUMP);
723 }
724
725 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700726 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -0700727 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
728 throw new SecurityException("You need one of " + Arrays.toString(permissions)
729 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700730 }
731 }
732
felipeal2d0483c2019-11-02 14:07:22 -0700733 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
734 for (String permission : permissions) {
735 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
736 /* exported = */ true)
737 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
738 return true;
739 }
740 }
741 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700742 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700743
744 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
745 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
746 // Count all users that are managed profiles of the given user.
747 int managedProfilesCount = 0;
748 for (UserInfo user : users) {
749 if (user.isManagedProfile() && user.profileGroupId == userId) {
750 managedProfilesCount++;
751 }
752 }
753 return managedProfilesCount;
754 }
755
756 /**
757 * Starts the first passenger of the given driver and assigns the passenger to the front
758 * passenger zone.
759 *
760 * @param driverId User id of the driver.
761 * @return whether it succeeds.
762 */
763 private boolean startFirstPassenger(@UserIdInt int driverId) {
764 int zoneId = getAvailablePassengerZone();
765 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
766 Log.w(TAG_USER, "passenger occupant zone is not found");
767 return false;
768 }
769 List<UserInfo> passengers = getPassengers(driverId);
770 if (passengers.size() < 1) {
771 Log.w(TAG_USER, "passenger is not found");
772 return false;
773 }
774 // Only one passenger is supported. If there are two or more passengers, the first passenger
775 // is chosen.
776 int passengerId = passengers.get(0).id;
777 if (!startPassenger(passengerId, zoneId)) {
778 Log.w(TAG_USER, "cannot start passenger " + passengerId);
779 return false;
780 }
781 return true;
782 }
783
784 private int getAvailablePassengerZone() {
785 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
786 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
787 for (int occupantType : occupantTypes) {
788 int zoneId = getZoneId(occupantType);
789 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
790 return zoneId;
791 }
792 }
793 return OccupantZoneInfo.INVALID_ZONE_ID;
794 }
795
796 /**
797 * Creates a new passenger user when there is no passenger user.
798 */
799 private void setupPassengerUser() {
800 int currentUser = ActivityManager.getCurrentUser();
801 int profileCount = getNumberOfManagedProfiles(currentUser);
802 if (profileCount > 0) {
803 Log.w(TAG_USER, "max profile of user" + currentUser
804 + " is exceeded: current profile count is " + profileCount);
805 return;
806 }
807 // TODO(b/140311342): Use resource string for the default passenger name.
808 UserInfo passenger = createPassenger("Passenger", currentUser);
809 if (passenger == null) {
810 // Couldn't create user, most likely because there are too many.
811 Log.w(TAG_USER, "cannot create a passenger user");
812 return;
813 }
814 }
815
816 @NonNull
817 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
818 ZoneUserBindingHelper helper = null;
819 synchronized (mLockHelper) {
820 if (mZoneUserBindingHelper == null) {
821 Log.w(TAG_USER, "implementation is not delegated");
822 return new ArrayList<OccupantZoneInfo>();
823 }
824 helper = mZoneUserBindingHelper;
825 }
826 return helper.getOccupantZones(occupantType);
827 }
828
829 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
830 ZoneUserBindingHelper helper = null;
831 synchronized (mLockHelper) {
832 if (mZoneUserBindingHelper == null) {
833 Log.w(TAG_USER, "implementation is not delegated");
834 return false;
835 }
836 helper = mZoneUserBindingHelper;
837 }
838 return helper.assignUserToOccupantZone(userId, zoneId);
839 }
840
841 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
842 ZoneUserBindingHelper helper = null;
843 synchronized (mLockHelper) {
844 if (mZoneUserBindingHelper == null) {
845 Log.w(TAG_USER, "implementation is not delegated");
846 return false;
847 }
848 helper = mZoneUserBindingHelper;
849 }
850 return helper.unassignUserFromOccupantZone(userId);
851 }
852
853 private boolean isPassengerDisplayAvailable() {
854 ZoneUserBindingHelper helper = null;
855 synchronized (mLockHelper) {
856 if (mZoneUserBindingHelper == null) {
857 Log.w(TAG_USER, "implementation is not delegated");
858 return false;
859 }
860 helper = mZoneUserBindingHelper;
861 }
862 return helper.isPassengerDisplayAvailable();
863 }
864
865 /**
866 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
867 * zone is returned.
868 *
869 * @param occupantType The type of an occupant.
870 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
871 * if not found.
872 */
873 private int getZoneId(@OccupantTypeEnum int occupantType) {
874 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
875 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
876 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700877}