blob: e2f21b5f3733dd5ba4836323e34cc8b96a6f3a24 [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;
Ying Zheng1ab32b62018-06-26 12:47:26 -070037import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070038import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080039import android.os.Bundle;
Keun young Parkfb656372019-03-12 18:37:55 -070040import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080041import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070042import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070043import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070044import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070045import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080046import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080047import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070048
49import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070050import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080051import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080052import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070053import com.android.internal.annotations.VisibleForTesting;
Felipe Leme5528ff72020-02-10 19:05:14 -080054import com.android.internal.os.IResultReceiver;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070055import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070056
57import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080058import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070059import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070060import java.util.Iterator;
61import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000062import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070063import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070064
65/**
66 * User service for cars. Manages users at boot time. Including:
67 *
68 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070069 * <li> Creates a user used as driver.
70 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070071 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070072 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070073 * <ol/>
74 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070075public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080076
77
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070079 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070080 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070081 private final UserManager mUserManager;
82 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -070083 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070084
Eric Jeongc91f9452019-08-30 15:04:21 -070085 private final Object mLockUser = new Object();
86 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -080087 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -070088 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -080089 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -070090 // Only one passenger is supported.
91 @GuardedBy("mLockUser")
92 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -070093 /**
94 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -080095 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -070096 */
Eric Jeongc91f9452019-08-30 15:04:21 -070097 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -070098 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
99 /**
100 * Keep the list of background users started here. This is wholly for debugging purpose.
101 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700102 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700103 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
104
Felipe Leme5528ff72020-02-10 19:05:14 -0800105 // TODO(b/144120654): mege then
Pavel Maltsev17e81832019-04-04 14:38:41 -0700106 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
107
Felipe Leme58412202020-01-09 13:45:33 -0800108 private final UserHalService mHal;
109
Felipe Leme5528ff72020-02-10 19:05:14 -0800110 /**
111 * List of lifecycle listeners by uid.
112 */
113 @GuardedBy("mLockUser")
114 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
115
116 // TODO(b/144120654): replace by CarUserManager listener
Pavel Maltsev17e81832019-04-04 14:38:41 -0700117 /** Interface for callbacks related to user activities. */
118 public interface UserCallback {
119 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700120 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700121 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700122 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700123 }
124
Eric Jeongc91f9452019-08-30 15:04:21 -0700125 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
126 new CopyOnWriteArrayList<>();
127
128 /** Interface for callbaks related to passenger activities. */
129 public interface PassengerCallback {
130 /** Called when passenger is started at a certain zone. */
131 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
132 /** Called when passenger is stopped. */
133 void onPassengerStopped(@UserIdInt int passengerId);
134 }
135
136 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
137 public interface ZoneUserBindingHelper {
138 /** Gets occupant zones corresponding to the occupant type. */
139 @NonNull
140 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
141 /** Assigns the user to the occupant zone. */
142 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
143 /** Makes the occupant zone unoccupied. */
144 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
145 /** Returns whether there is a passenger display. */
146 boolean isPassengerDisplayAvailable();
147 }
148
149 private final Object mLockHelper = new Object();
150 @GuardedBy("mLockHelper")
151 private ZoneUserBindingHelper mZoneUserBindingHelper;
152
Felipe Leme58412202020-01-09 13:45:33 -0800153 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
154 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700155 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700156 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
157 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700158 }
159 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800160 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700161 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700162 mAm = am;
163 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700164 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700165 mLastPassengerId = UserHandle.USER_NULL;
166 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700167 }
168
169 @Override
170 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700171 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
172 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700173 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700174 }
175
176 @Override
177 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700178 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
179 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700180 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700181 }
182
183 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700184 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700185 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700186 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800187 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700188 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800189 int numberListeners = mLifecycleListeners.size();
190 if (numberListeners == 0) {
191 writer.println("No lifecycle listeners");
192 } else {
193 writer.printf("%d lifecycle listeners\n", numberListeners);
194 for (int i = 0; i < numberListeners; i++) {
195 int uid = mLifecycleListeners.keyAt(i);
196 IResultReceiver listener = mLifecycleListeners.valueAt(i);
197 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
198 }
199 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700200 writer.println("User0Unlocked: " + mUser0Unlocked);
201 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
202 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
203 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700204 List<UserInfo> allDrivers = getAllDrivers();
205 int driversSize = allDrivers.size();
206 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700207 for (int i = 0; i < driversSize; i++) {
208 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800209 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700210 List<UserInfo> passengers = getPassengers(driverId);
211 int passengersSize = passengers.size();
212 writer.print(" NumberPassengers: " + passengersSize);
213 if (passengersSize > 0) {
214 writer.print(" [");
215 for (int j = 0; j < passengersSize; j++) {
216 writer.print(passengers.get(j).id);
217 if (j < passengersSize - 1) {
218 writer.print(" ");
219 }
220 }
221 writer.print("]");
222 }
223 writer.println();
224 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700225 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Keun-young Parkd462a912019-02-11 08:53:42 -0800226 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700227 }
228
229 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800230 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
231 *
232 * @param name The name of the driver to be created.
233 * @param admin Whether the created driver will be an admin.
234 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
235 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700236 */
237 @Override
238 @Nullable
239 public UserInfo createDriver(@NonNull String name, boolean admin) {
240 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000241 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700242 if (admin) {
243 return createNewAdminUser(name);
244 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700245 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700246 }
247
248 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800249 * Creates a passenger who is a profile of the given driver.
250 *
251 * @param name The name of the passenger to be created.
252 * @param driverId User id of the driver under whom a passenger is created.
253 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
254 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700255 */
256 @Override
257 @Nullable
258 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
259 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000260 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700261 UserInfo driver = mUserManager.getUserInfo(driverId);
262 if (driver == null) {
263 Log.w(TAG_USER, "the driver is invalid");
264 return null;
265 }
266 if (driver.isGuest()) {
267 Log.w(TAG_USER, "a guest driver cannot create a passenger");
268 return null;
269 }
Bookatz42fb1a62019-10-30 11:45:01 -0700270 UserInfo user = mUserManager.createProfileForUser(name,
271 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700272 if (user == null) {
273 // Couldn't create user, most likely because there are too many.
274 Log.w(TAG_USER, "can't create a profile for user" + driverId);
275 return null;
276 }
277 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700278 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700279 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700280 return user;
281 }
282
283 /**
284 * @see CarUserManager.switchDriver
285 */
286 @Override
287 public boolean switchDriver(@UserIdInt int driverId) {
288 checkManageUsersPermission("switchDriver");
289 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
290 // System user doesn't associate with real person, can not be switched to.
291 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
292 return false;
293 }
294 int userSwitchable = mUserManager.getUserSwitchability();
295 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
296 Log.w(TAG_USER, "current process is not allowed to switch user");
297 return false;
298 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700299 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700300 // The current user is already the given user.
301 return true;
302 }
303 try {
304 return mAm.switchUser(driverId);
305 } catch (RemoteException e) {
306 // ignore
307 Log.w(TAG_USER, "error while switching user", e);
308 }
309 return false;
310 }
311
312 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800313 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
314 *
315 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700316 */
317 @Override
318 @NonNull
319 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700320 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700321 return getUsers((user) -> {
322 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
323 && !user.isEphemeral();
324 });
325 }
326
327 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800328 * Returns all passengers under the given driver.
329 *
330 * @param driverId User id of a driver.
331 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700332 */
333 @Override
334 @NonNull
335 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700336 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700337 return getUsers((user) -> {
338 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
339 && user.profileGroupId == driverId;
340 });
341 }
342
343 /**
344 * @see CarUserManager.startPassenger
345 */
346 @Override
347 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
348 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700349 synchronized (mLockUser) {
350 try {
351 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
352 Log.w(TAG_USER, "could not start passenger");
353 return false;
354 }
355 } catch (RemoteException e) {
356 // ignore
357 Log.w(TAG_USER, "error while starting passenger", e);
358 return false;
359 }
360 if (!assignUserToOccupantZone(passengerId, zoneId)) {
361 Log.w(TAG_USER, "could not assign passenger to zone");
362 return false;
363 }
364 mLastPassengerId = passengerId;
365 }
366 for (PassengerCallback callback : mPassengerCallbacks) {
367 callback.onPassengerStarted(passengerId, zoneId);
368 }
369 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700370 }
371
372 /**
373 * @see CarUserManager.stopPassenger
374 */
375 @Override
376 public boolean stopPassenger(@UserIdInt int passengerId) {
377 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700378 return stopPassengerInternal(passengerId, true);
379 }
380
381 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
382 synchronized (mLockUser) {
383 UserInfo passenger = mUserManager.getUserInfo(passengerId);
384 if (passenger == null) {
385 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
386 return false;
387 }
388 if (mLastPassengerId != passengerId) {
389 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
390 return true;
391 }
392 if (checkCurrentDriver) {
393 int currentUser = ActivityManager.getCurrentUser();
394 if (passenger.profileGroupId != currentUser) {
395 Log.w(TAG_USER, "passenger " + passengerId
396 + " is not a profile of the current user");
397 return false;
398 }
399 }
400 // Passenger is a profile, so cannot be stopped through activity manager.
401 // Instead, activities started by the passenger are stopped and the passenger is
402 // unassigned from the zone.
403 stopAllTasks(passengerId);
404 if (!unassignUserFromOccupantZone(passengerId)) {
405 Log.w(TAG_USER, "could not unassign user from occupant zone");
406 return false;
407 }
408 mLastPassengerId = UserHandle.USER_NULL;
409 }
410 for (PassengerCallback callback : mPassengerCallbacks) {
411 callback.onPassengerStopped(passengerId);
412 }
413 return true;
414 }
415
416 private void stopAllTasks(@UserIdInt int userId) {
417 try {
418 for (StackInfo info : mAm.getAllStackInfos()) {
419 for (int i = 0; i < info.taskIds.length; i++) {
420 if (info.taskUserIds[i] == userId) {
421 int taskId = info.taskIds[i];
422 if (!mAm.removeTask(taskId)) {
423 Log.w(TAG_USER, "could not remove task " + taskId);
424 }
425 }
426 }
427 }
428 } catch (RemoteException e) {
429 Log.e(TAG_USER, "could not get stack info", e);
430 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700431 }
432
Felipe Leme5528ff72020-02-10 19:05:14 -0800433 @Override
434 public void setLifecycleListenerForUid(IResultReceiver listener) {
435 int uid = Binder.getCallingUid();
436 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
437
438 try {
439 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
440 } catch (RemoteException e) {
441 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
442 }
443 synchronized (mLockUser) {
444 mLifecycleListeners.append(uid, listener);
445 }
446 }
447
448 private void onListenerDeath(int uid) {
449 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
450 synchronized (mLockUser) {
451 removeLifecycleListenerLocked(uid);
452 }
453 }
454
455 @Override
456 public void resetLifecycleListenerForUid() {
457 int uid = Binder.getCallingUid();
458 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
459
460 synchronized (mLockUser) {
461 removeLifecycleListenerLocked(uid);
462 }
463 }
464
465 private void removeLifecycleListenerLocked(int uid) {
466 mLifecycleListeners.remove(uid);
467 }
468
Eric Jeong1545f3b2019-09-16 13:56:52 -0700469 /** Returns whether the given user is a system user. */
470 private static boolean isSystemUser(@UserIdInt int userId) {
471 return userId == UserHandle.USER_SYSTEM;
472 }
473
Keun young Park13a7a822019-04-04 15:53:08 -0700474 private void updateDefaultUserRestriction() {
475 // We want to set restrictions on system and guest users only once. These are persisted
476 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
477 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700478 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
479 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700480 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700481 // Only apply the system user restrictions if the system user is headless.
482 if (UserManager.isHeadlessSystemUserMode()) {
483 setSystemUserRestrictions();
484 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700485 Settings.Global.putInt(mContext.getContentResolver(),
486 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700487 }
488
Eric Jeong1545f3b2019-09-16 13:56:52 -0700489 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700490 return !mUserManager.getUserInfo(userId).isEphemeral();
491 }
492
Eric Jeong1545f3b2019-09-16 13:56:52 -0700493 /** Adds callback to listen to user activity events. */
494 public void addUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000495 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700496 mUserCallbacks.add(callback);
497 }
498
Yabin Huang27712d72019-06-26 12:46:30 -0700499 /** Removes previously added callback to listen user events. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700500 public void removeUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000501 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700502 mUserCallbacks.remove(callback);
503 }
504
Eric Jeongc91f9452019-08-30 15:04:21 -0700505 /** Adds callback to listen to passenger activity events. */
506 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000507 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700508 mPassengerCallbacks.add(callback);
509 }
510
511 /** Removes previously added callback to listen passenger events. */
512 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000513 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700514 mPassengerCallbacks.remove(callback);
515 }
516
517 /** Sets the implementation of ZoneUserBindingHelper. */
518 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
519 synchronized (mLockHelper) {
520 mZoneUserBindingHelper = helper;
521 }
522 }
523
Keun-young Parkd462a912019-02-11 08:53:42 -0800524 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700525 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
526 *
527 * @param userId User id whoes lock status is changed.
528 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800529 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700530 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Mayank Garg31e73042020-01-23 00:10:38 -0800531 TimingsTraceLog t = new TimingsTraceLog(TAG_USER,
532 Trace.TRACE_TAG_SYSTEM_SERVER);
533 t.traceBegin("onUserLockChanged-" + userId
534 + (unlocked ? "-unlocked" : "-locked"));
Pavel Maltsev17e81832019-04-04 14:38:41 -0700535 for (UserCallback callback : mUserCallbacks) {
Mayank Garg31e73042020-01-23 00:10:38 -0800536 t.traceBegin("onUserLockChanged-"
537 + callback.getClass().getSimpleName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700538 callback.onUserLockChanged(userId, unlocked);
Mayank Garg31e73042020-01-23 00:10:38 -0800539 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700540 }
Mayank Garg31e73042020-01-23 00:10:38 -0800541 t.traceEnd();
542
Keun young Parkf3523cd2019-04-08 10:09:17 -0700543 if (!unlocked) { // nothing else to do when it is locked back.
544 return;
545 }
Mayank Garg31e73042020-01-23 00:10:38 -0800546
547 t.traceBegin("setUserLockStatus-UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800548 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700549 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700550 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700551 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
552 updateDefaultUserRestriction();
553 tasks = new ArrayList<>(mUser0UnlockTasks);
554 mUser0UnlockTasks.clear();
555 mUser0Unlocked = unlocked;
556 }
557 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700558 Integer user = userId;
559 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700560 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700561 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700562 mBackgroundUsersToRestart.remove(user);
563 mBackgroundUsersToRestart.add(0, user);
564 }
565 // -1 for user 0
566 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700567 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700568 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700569 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700570 + ", dropping least recently user from restart list:" + userToDrop);
571 // Drop the least recently used user.
572 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
573 }
574 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800575 }
576 }
577 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700578 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800579 for (Runnable r : tasks) {
580 r.run();
581 }
582 }
Mayank Garg31e73042020-01-23 00:10:38 -0800583 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800584 }
585
586 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700587 * Starts all background users that were active in system.
588 *
Keun young Parkfb656372019-03-12 18:37:55 -0700589 * @return list of background users started successfully.
590 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700591 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700592 public ArrayList<Integer> startAllBackgroundUsers() {
593 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700594 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700595 users = new ArrayList<>(mBackgroundUsersToRestart);
596 mBackgroundUsersRestartedHere.clear();
597 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700598 }
599 ArrayList<Integer> startedUsers = new ArrayList<>();
600 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700601 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700602 continue;
603 }
604 try {
605 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700606 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
607 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700608 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700609 } else if (mAm.unlockUser(user, null, null, null)) {
610 startedUsers.add(user);
611 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700612 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700613 if (mUserManager.isUserRunning(user)) {
614 // add to started list so that it can be stopped later.
615 startedUsers.add(user);
616 }
Keun young Parkfb656372019-03-12 18:37:55 -0700617 }
618 }
619 } catch (RemoteException e) {
620 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700621 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700622 }
623 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700624 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700625 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700626 ArrayList<Integer> usersToRemove = new ArrayList<>();
627 for (Integer user : mBackgroundUsersToRestart) {
628 if (!startedUsers.contains(user)) {
629 usersToRemove.add(user);
630 }
631 }
632 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
633 }
Keun young Parkfb656372019-03-12 18:37:55 -0700634 return startedUsers;
635 }
636
637 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700638 * Stops all background users that were active in system.
639 *
640 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700641 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700642 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700643 if (userId == UserHandle.USER_SYSTEM) {
644 return false;
645 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700646 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700647 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700648 return false;
649 }
650 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700651 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700652 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700653 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700654 Integer user = userId;
655 mBackgroundUsersRestartedHere.remove(user);
656 }
657 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
658 return false;
659 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700660 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700661 return false;
662 }
663 } catch (RemoteException e) {
664 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700665 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700666 }
667 return true;
668 }
669
670 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700671 * Called when new foreground user started to boot.
672 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700673 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700674 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700675 public void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800676 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
677 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800678 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800679
Felipe Lemef45ee502019-12-19 10:00:14 -0800680 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700681 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700682 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700683 if (mLastPassengerId != UserHandle.USER_NULL) {
684 stopPassengerInternal(mLastPassengerId, false);
685 }
686 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
687 setupPassengerUser();
688 startFirstPassenger(userId);
689 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800690
691 // TODO(b/144120654): right now just the app listeners are running in the background so the
692 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
693 // but once we refactor the car service callback into lifecycle listeners, we should use a
694 // proper thread management (like a Threadpool / executor);
695
696 int listenersSize = mLifecycleListeners.size();
697 if (listenersSize == 0) {
698 Log.i(TAG_USER, "Not notifying app listeners");
699 } else {
700 new Thread(() -> {
701 // Must use a different TimingsTraceLog because it's another thread
702 TimingsTraceLog t2 = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
703 Log.i(TAG_USER, "Notifying " + listenersSize + " listeners");
704 for (int i = 0; i < listenersSize; i++) {
705 int uid = mLifecycleListeners.keyAt(i);
706 IResultReceiver listener = mLifecycleListeners.valueAt(i);
707 t2.traceBegin("notify-listener-" + uid);
708 Bundle data = new Bundle();
709 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION,
710 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
711 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
712 // can set BUNDLE_PARAM_PREVIOUS_USER_HANDLE
713 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
714 Log.d(TAG_USER, "Notifying listener for uid " + uid);
715 }
716 try {
717 listener.send(userId, data);
718 } catch (RemoteException e) {
719 Log.e(TAG_USER, "Error calling lifecycle listener", e);
720 } finally {
721 t2.traceEnd();
722 }
723 }
724
725 }, "SwitchUser-" + userId + "-Listeners").start();
726 }
727
728 Log.i(TAG_USER, "Notifying " + mUserCallbacks.size() + " callbacks");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700729 for (UserCallback callback : mUserCallbacks) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800730 t.traceBegin("onSwitchUser-" + callback.getClass().getName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700731 callback.onSwitchUser(userId);
Mayank Garg31e73042020-01-23 00:10:38 -0800732 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700733 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800734 t.traceEnd(); // onSwitchUser
735
Pavel Maltsev17e81832019-04-04 14:38:41 -0700736 }
737
738 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700739 * 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 -0800740 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700741 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800742 * @param r Runnable to run.
743 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700744 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000745 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800746 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700747 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800748 if (mUser0Unlocked) {
749 runNow = true;
750 } else {
751 mUser0UnlockTasks.add(r);
752 }
753 }
754 if (runNow) {
755 r.run();
756 }
757 }
758
Keun young Parkf3523cd2019-04-08 10:09:17 -0700759 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700760 @NonNull
761 ArrayList<Integer> getBackgroundUsersToRestart() {
762 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700763 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700764 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
765 }
766 return backgroundUsersToRestart;
767 }
768
Ying Zheng1ab32b62018-06-26 12:47:26 -0700769 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700770 // Disable Location service for system user.
771 LocationManager locationManager =
772 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800773 locationManager.setLocationEnabledForUser(
774 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700775 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700776
777 /**
778 * Creates a new user on the system, the created user would be granted admin role.
779 *
780 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700781 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700782 */
783 @Nullable
784 private UserInfo createNewAdminUser(String name) {
785 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
786 // Only admins or system user can create other privileged users.
787 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
788 return null;
789 }
790
791 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
792 if (user == null) {
793 // Couldn't create user, most likely because there are too many.
794 Log.w(TAG_USER, "can't create admin user.");
795 return null;
796 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700797 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700798
799 return user;
800 }
801
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700802 /**
803 * Assigns a default icon to a user according to the user's id.
804 *
805 * @param userInfo User whose avatar is set to default icon.
806 * @return Bitmap of the user icon.
807 */
808 private Bitmap assignDefaultIcon(UserInfo userInfo) {
809 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
810 Bitmap bitmap = UserIcons.convertToBitmap(
811 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
812 mUserManager.setUserIcon(userInfo.id, bitmap);
813 return bitmap;
814 }
815
Eric Jeong1545f3b2019-09-16 13:56:52 -0700816 private interface UserFilter {
817 boolean isEligibleUser(UserInfo user);
818 }
819
820 /** Returns all users who are matched by the given filter. */
821 private List<UserInfo> getUsers(UserFilter filter) {
822 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
823
824 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
825 UserInfo user = iterator.next();
826 if (!filter.isEligibleUser(user)) {
827 iterator.remove();
828 }
829 }
830 return users;
831 }
832
833 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700834 * Enforces that apps which have the
835 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
836 * can make certain calls to the CarUserManager.
837 *
838 * @param message used as message if SecurityException is thrown.
839 * @throws SecurityException if the caller is not system or root.
840 */
841 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -0700842 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
843 }
844
845 private static void checkManageUsersOrDumpPermission(String message) {
846 checkAtLeastOnePermission(message,
847 android.Manifest.permission.MANAGE_USERS,
848 android.Manifest.permission.DUMP);
849 }
850
Felipe Leme5528ff72020-02-10 19:05:14 -0800851 private void checkInteractAcrossUsersPermission(String message) {
852 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
853 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
854 }
855
felipeal2d0483c2019-11-02 14:07:22 -0700856 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700857 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -0700858 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
859 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -0800860 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700861 }
862 }
863
felipeal2d0483c2019-11-02 14:07:22 -0700864 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
865 for (String permission : permissions) {
866 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
867 /* exported = */ true)
868 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
869 return true;
870 }
871 }
872 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700873 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700874
875 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
876 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
877 // Count all users that are managed profiles of the given user.
878 int managedProfilesCount = 0;
879 for (UserInfo user : users) {
880 if (user.isManagedProfile() && user.profileGroupId == userId) {
881 managedProfilesCount++;
882 }
883 }
884 return managedProfilesCount;
885 }
886
887 /**
888 * Starts the first passenger of the given driver and assigns the passenger to the front
889 * passenger zone.
890 *
891 * @param driverId User id of the driver.
892 * @return whether it succeeds.
893 */
894 private boolean startFirstPassenger(@UserIdInt int driverId) {
895 int zoneId = getAvailablePassengerZone();
896 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
897 Log.w(TAG_USER, "passenger occupant zone is not found");
898 return false;
899 }
900 List<UserInfo> passengers = getPassengers(driverId);
901 if (passengers.size() < 1) {
902 Log.w(TAG_USER, "passenger is not found");
903 return false;
904 }
905 // Only one passenger is supported. If there are two or more passengers, the first passenger
906 // is chosen.
907 int passengerId = passengers.get(0).id;
908 if (!startPassenger(passengerId, zoneId)) {
909 Log.w(TAG_USER, "cannot start passenger " + passengerId);
910 return false;
911 }
912 return true;
913 }
914
915 private int getAvailablePassengerZone() {
916 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
917 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
918 for (int occupantType : occupantTypes) {
919 int zoneId = getZoneId(occupantType);
920 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
921 return zoneId;
922 }
923 }
924 return OccupantZoneInfo.INVALID_ZONE_ID;
925 }
926
927 /**
928 * Creates a new passenger user when there is no passenger user.
929 */
930 private void setupPassengerUser() {
931 int currentUser = ActivityManager.getCurrentUser();
932 int profileCount = getNumberOfManagedProfiles(currentUser);
933 if (profileCount > 0) {
934 Log.w(TAG_USER, "max profile of user" + currentUser
935 + " is exceeded: current profile count is " + profileCount);
936 return;
937 }
938 // TODO(b/140311342): Use resource string for the default passenger name.
939 UserInfo passenger = createPassenger("Passenger", currentUser);
940 if (passenger == null) {
941 // Couldn't create user, most likely because there are too many.
942 Log.w(TAG_USER, "cannot create a passenger user");
943 return;
944 }
945 }
946
947 @NonNull
948 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
949 ZoneUserBindingHelper helper = null;
950 synchronized (mLockHelper) {
951 if (mZoneUserBindingHelper == null) {
952 Log.w(TAG_USER, "implementation is not delegated");
953 return new ArrayList<OccupantZoneInfo>();
954 }
955 helper = mZoneUserBindingHelper;
956 }
957 return helper.getOccupantZones(occupantType);
958 }
959
960 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
961 ZoneUserBindingHelper helper = null;
962 synchronized (mLockHelper) {
963 if (mZoneUserBindingHelper == null) {
964 Log.w(TAG_USER, "implementation is not delegated");
965 return false;
966 }
967 helper = mZoneUserBindingHelper;
968 }
969 return helper.assignUserToOccupantZone(userId, zoneId);
970 }
971
972 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
973 ZoneUserBindingHelper helper = null;
974 synchronized (mLockHelper) {
975 if (mZoneUserBindingHelper == null) {
976 Log.w(TAG_USER, "implementation is not delegated");
977 return false;
978 }
979 helper = mZoneUserBindingHelper;
980 }
981 return helper.unassignUserFromOccupantZone(userId);
982 }
983
984 private boolean isPassengerDisplayAvailable() {
985 ZoneUserBindingHelper helper = null;
986 synchronized (mLockHelper) {
987 if (mZoneUserBindingHelper == null) {
988 Log.w(TAG_USER, "implementation is not delegated");
989 return false;
990 }
991 helper = mZoneUserBindingHelper;
992 }
993 return helper.isPassengerDisplayAvailable();
994 }
995
996 /**
997 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
998 * zone is returned.
999 *
1000 * @param occupantType The type of an occupant.
1001 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1002 * if not found.
1003 */
1004 private int getZoneId(@OccupantTypeEnum int occupantType) {
1005 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1006 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1007 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001008}