blob: 64e9ec4e257019b9c9e8182cc57aaee72c330089 [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.user;
18
Eric Jeong1545f3b2019-09-16 13:56:52 -070019import static com.android.car.CarLog.TAG_USER;
20
21import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070022import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070024import android.app.ActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070025import android.app.ActivityManager.StackInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070026import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070027import android.car.CarOccupantZoneManager;
28import android.car.CarOccupantZoneManager.OccupantTypeEnum;
29import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070030import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070031import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080032import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080033import android.car.user.CarUserManager.UserLifecycleEvent;
34import android.car.user.CarUserManager.UserLifecycleListener;
Eric Jeong3a793b02019-09-30 16:12:53 -070035import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070036import android.car.userlib.HalCallback;
37import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070038import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070039import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070040import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070041import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070042import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080043import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070044import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080045import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070046import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070047import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080048import android.os.Bundle;
Keun young Parkfb656372019-03-12 18:37:55 -070049import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080050import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070051import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070052import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070053import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070054import android.sysprop.CarProperties;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070055import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080056import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080057import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070058
59import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070060import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080061import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080062import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070063import com.android.internal.annotations.VisibleForTesting;
Felipe Leme5528ff72020-02-10 19:05:14 -080064import com.android.internal.os.IResultReceiver;
Mayank Garge19c2922020-03-30 18:05:53 -070065import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070066import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070067
68import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080069import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070070import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070071import java.util.Iterator;
72import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000073import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070074import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070075
76/**
77 * User service for cars. Manages users at boot time. Including:
78 *
79 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070080 * <li> Creates a user used as driver.
81 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070082 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070083 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070084 * <ol/>
85 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070086public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080087
Felipe Lemeabbf2da2020-02-24 18:25:29 -080088 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080089 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080090 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080091 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080092 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080093 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080094 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
95 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -080096
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070098 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070099 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700100 private final UserManager mUserManager;
101 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700102 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700103
Eric Jeongc91f9452019-08-30 15:04:21 -0700104 private final Object mLockUser = new Object();
105 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800106 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700107 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800108 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700109 // Only one passenger is supported.
110 @GuardedBy("mLockUser")
111 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700112 /**
113 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800114 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700115 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700116 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700117 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
118 /**
119 * Keep the list of background users started here. This is wholly for debugging purpose.
120 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700121 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700122 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
123
Felipe Leme58412202020-01-09 13:45:33 -0800124 private final UserHalService mHal;
125
Felipe Leme5528ff72020-02-10 19:05:14 -0800126 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800127 * List of listeners to be notified on new user activities events.
128 */
129 private final CopyOnWriteArrayList<UserLifecycleListener>
130 mUserLifecycleListeners = new CopyOnWriteArrayList<>();
131
132 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800133 * List of lifecycle listeners by uid.
134 */
135 @GuardedBy("mLockUser")
136 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
137
Felipe Lemee3cab982020-03-12 11:39:29 -0700138 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
139
Eric Jeongc91f9452019-08-30 15:04:21 -0700140 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
141 new CopyOnWriteArrayList<>();
142
felipeal61ce3732020-04-03 11:01:00 -0700143 @Nullable
144 @GuardedBy("mLockUser")
145 private UserInfo mInitialUser;
146
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 /** Interface for callbaks related to passenger activities. */
148 public interface PassengerCallback {
149 /** Called when passenger is started at a certain zone. */
150 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
151 /** Called when passenger is stopped. */
152 void onPassengerStopped(@UserIdInt int passengerId);
153 }
154
155 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
156 public interface ZoneUserBindingHelper {
157 /** Gets occupant zones corresponding to the occupant type. */
158 @NonNull
159 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
160 /** Assigns the user to the occupant zone. */
161 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
162 /** Makes the occupant zone unoccupied. */
163 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
164 /** Returns whether there is a passenger display. */
165 boolean isPassengerDisplayAvailable();
166 }
167
168 private final Object mLockHelper = new Object();
169 @GuardedBy("mLockHelper")
170 private ZoneUserBindingHelper mZoneUserBindingHelper;
171
Felipe Leme58412202020-01-09 13:45:33 -0800172 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
173 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700174 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700175 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
176 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700177 }
178 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800179 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700180 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700181 mAm = am;
182 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700183 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700184 mLastPassengerId = UserHandle.USER_NULL;
185 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700186 }
187
188 @Override
189 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700190 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
191 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700192 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700193 }
194
195 @Override
196 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700197 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
198 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700199 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700200 }
201
202 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700203 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700204 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700205 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800206 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700207 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800208 int numberListeners = mLifecycleListeners.size();
209 if (numberListeners == 0) {
210 writer.println("No lifecycle listeners");
211 } else {
212 writer.printf("%d lifecycle listeners\n", numberListeners);
213 for (int i = 0; i < numberListeners; i++) {
214 int uid = mLifecycleListeners.keyAt(i);
215 IResultReceiver listener = mLifecycleListeners.valueAt(i);
216 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
217 }
218 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700219 writer.println("User0Unlocked: " + mUser0Unlocked);
220 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
221 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
222 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700223 List<UserInfo> allDrivers = getAllDrivers();
224 int driversSize = allDrivers.size();
225 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700226 for (int i = 0; i < driversSize; i++) {
227 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800228 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700229 List<UserInfo> passengers = getPassengers(driverId);
230 int passengersSize = passengers.size();
231 writer.print(" NumberPassengers: " + passengersSize);
232 if (passengersSize > 0) {
233 writer.print(" [");
234 for (int j = 0; j < passengersSize; j++) {
235 writer.print(passengers.get(j).id);
236 if (j < passengersSize - 1) {
237 writer.print(" ");
238 }
239 }
240 writer.print("]");
241 }
242 writer.println();
243 }
felipeal61ce3732020-04-03 11:01:00 -0700244 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
245 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
246 writer.printf("Initial user: %s\n", mInitialUser);
247 writer.println("Relevant overlayable properties");
Felipe Leme315a53b2020-03-12 10:51:04 -0700248 Resources res = mContext.getResources();
249 writer.printf("%sowner_name=%s\n", indent,
250 res.getString(com.android.internal.R.string.owner_name));
251 writer.printf("%sdefault_guest_name=%s\n", indent,
252 res.getString(R.string.default_guest_name));
Keun-young Parkd462a912019-02-11 08:53:42 -0800253 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700254 }
255
256 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800257 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
258 *
259 * @param name The name of the driver to be created.
260 * @param admin Whether the created driver will be an admin.
261 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
262 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700263 */
264 @Override
265 @Nullable
266 public UserInfo createDriver(@NonNull String name, boolean admin) {
267 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000268 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700269 if (admin) {
270 return createNewAdminUser(name);
271 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700272 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700273 }
274
275 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800276 * Creates a passenger who is a profile of the given driver.
277 *
278 * @param name The name of the passenger to be created.
279 * @param driverId User id of the driver under whom a passenger is created.
280 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
281 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700282 */
283 @Override
284 @Nullable
285 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
286 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000287 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700288 UserInfo driver = mUserManager.getUserInfo(driverId);
289 if (driver == null) {
290 Log.w(TAG_USER, "the driver is invalid");
291 return null;
292 }
293 if (driver.isGuest()) {
294 Log.w(TAG_USER, "a guest driver cannot create a passenger");
295 return null;
296 }
Bookatz42fb1a62019-10-30 11:45:01 -0700297 UserInfo user = mUserManager.createProfileForUser(name,
298 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700299 if (user == null) {
300 // Couldn't create user, most likely because there are too many.
301 Log.w(TAG_USER, "can't create a profile for user" + driverId);
302 return null;
303 }
304 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700305 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700306 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700307 return user;
308 }
309
310 /**
311 * @see CarUserManager.switchDriver
312 */
313 @Override
314 public boolean switchDriver(@UserIdInt int driverId) {
315 checkManageUsersPermission("switchDriver");
316 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
317 // System user doesn't associate with real person, can not be switched to.
318 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
319 return false;
320 }
321 int userSwitchable = mUserManager.getUserSwitchability();
322 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
323 Log.w(TAG_USER, "current process is not allowed to switch user");
324 return false;
325 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700326 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700327 // The current user is already the given user.
328 return true;
329 }
330 try {
331 return mAm.switchUser(driverId);
332 } catch (RemoteException e) {
333 // ignore
334 Log.w(TAG_USER, "error while switching user", e);
335 }
336 return false;
337 }
338
339 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800340 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
341 *
342 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700343 */
344 @Override
345 @NonNull
346 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700347 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700348 return getUsers((user) -> {
349 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
350 && !user.isEphemeral();
351 });
352 }
353
354 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800355 * Returns all passengers under the given driver.
356 *
357 * @param driverId User id of a driver.
358 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700359 */
360 @Override
361 @NonNull
362 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700363 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700364 return getUsers((user) -> {
365 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
366 && user.profileGroupId == driverId;
367 });
368 }
369
370 /**
371 * @see CarUserManager.startPassenger
372 */
373 @Override
374 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
375 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700376 synchronized (mLockUser) {
377 try {
378 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
379 Log.w(TAG_USER, "could not start passenger");
380 return false;
381 }
382 } catch (RemoteException e) {
383 // ignore
384 Log.w(TAG_USER, "error while starting passenger", e);
385 return false;
386 }
387 if (!assignUserToOccupantZone(passengerId, zoneId)) {
388 Log.w(TAG_USER, "could not assign passenger to zone");
389 return false;
390 }
391 mLastPassengerId = passengerId;
392 }
393 for (PassengerCallback callback : mPassengerCallbacks) {
394 callback.onPassengerStarted(passengerId, zoneId);
395 }
396 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700397 }
398
399 /**
400 * @see CarUserManager.stopPassenger
401 */
402 @Override
403 public boolean stopPassenger(@UserIdInt int passengerId) {
404 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700405 return stopPassengerInternal(passengerId, true);
406 }
407
408 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
409 synchronized (mLockUser) {
410 UserInfo passenger = mUserManager.getUserInfo(passengerId);
411 if (passenger == null) {
412 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
413 return false;
414 }
415 if (mLastPassengerId != passengerId) {
416 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
417 return true;
418 }
419 if (checkCurrentDriver) {
420 int currentUser = ActivityManager.getCurrentUser();
421 if (passenger.profileGroupId != currentUser) {
422 Log.w(TAG_USER, "passenger " + passengerId
423 + " is not a profile of the current user");
424 return false;
425 }
426 }
427 // Passenger is a profile, so cannot be stopped through activity manager.
428 // Instead, activities started by the passenger are stopped and the passenger is
429 // unassigned from the zone.
430 stopAllTasks(passengerId);
431 if (!unassignUserFromOccupantZone(passengerId)) {
432 Log.w(TAG_USER, "could not unassign user from occupant zone");
433 return false;
434 }
435 mLastPassengerId = UserHandle.USER_NULL;
436 }
437 for (PassengerCallback callback : mPassengerCallbacks) {
438 callback.onPassengerStopped(passengerId);
439 }
440 return true;
441 }
442
443 private void stopAllTasks(@UserIdInt int userId) {
444 try {
445 for (StackInfo info : mAm.getAllStackInfos()) {
446 for (int i = 0; i < info.taskIds.length; i++) {
447 if (info.taskUserIds[i] == userId) {
448 int taskId = info.taskIds[i];
449 if (!mAm.removeTask(taskId)) {
450 Log.w(TAG_USER, "could not remove task " + taskId);
451 }
452 }
453 }
454 }
455 } catch (RemoteException e) {
456 Log.e(TAG_USER, "could not get stack info", e);
457 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700458 }
459
Felipe Leme5528ff72020-02-10 19:05:14 -0800460 @Override
461 public void setLifecycleListenerForUid(IResultReceiver listener) {
462 int uid = Binder.getCallingUid();
463 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
464
465 try {
466 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
467 } catch (RemoteException e) {
468 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
469 }
470 synchronized (mLockUser) {
471 mLifecycleListeners.append(uid, listener);
472 }
473 }
474
475 private void onListenerDeath(int uid) {
476 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
477 synchronized (mLockUser) {
478 removeLifecycleListenerLocked(uid);
479 }
480 }
481
482 @Override
483 public void resetLifecycleListenerForUid() {
484 int uid = Binder.getCallingUid();
485 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
486
487 synchronized (mLockUser) {
488 removeLifecycleListenerLocked(uid);
489 }
490 }
491
492 private void removeLifecycleListenerLocked(int uid) {
493 mLifecycleListeners.remove(uid);
494 }
495
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800496 @Override
497 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800498 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800499 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700500 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800501 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800502 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
503 try {
504 Bundle resultData = null;
505 if (resp != null) {
506 switch (resp.action) {
507 case InitialUserInfoResponseAction.SWITCH:
508 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800509 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800510 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
511 break;
512 case InitialUserInfoResponseAction.CREATE:
513 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800514 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800515 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
516 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
517 break;
518 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800519 resultData = new Bundle();
520 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800521 break;
522 default:
523 // That's ok, it will be the same as DEFAULT...
524 Log.w(TAG_USER, "invalid response action on " + resp);
525 }
526 }
527 receiver.send(status, resultData);
528 } catch (RemoteException e) {
529 Log.w(TAG_USER, "Could not send result back to receiver", e);
530 }
531 });
532 }
533
Felipe Lemee3cab982020-03-12 11:39:29 -0700534 /**
felipeal61ce3732020-04-03 11:01:00 -0700535 * Gets the initial foreground user after the device boots or resumes from suspension.
536 *
537 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
538 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
539 * method returns {@code null}.
540 *
541 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
542 * (like switching to the last active user), and this method will return the result of such
543 * operation.
544 *
545 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
546 * {@code null}.
547 *
548 * @hide
549 */
550 @Nullable
551 public UserInfo getInitialUser() {
552 checkInteractAcrossUsersPermission("getInitialUser");
553 synchronized (mLockUser) {
554 return mInitialUser;
555 }
556 }
557
558 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
559 // some reason passing the whole UserInfo through a raw binder transaction is not working.
560 /**
561 * Sets the initial foreground user after the device boots or resumes from suspension.
562 */
563 public void setInitialUser(@UserIdInt int userId) {
564 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
565 : mUserManager.getUserInfo(userId);
566 setInitialUser(initialUser);
567 }
568
569 /**
570 * Sets the initial foreground user after the device boots or resumes from suspension.
571 */
572 public void setInitialUser(@Nullable UserInfo user) {
573 Log.i(TAG_USER, "setInitialUser: " + user);
574 synchronized (mLockUser) {
575 mInitialUser = user;
576 }
577 if (user == null) {
578 // This mean InitialUserSetter failed and could not fallback, so the initial user was
579 // not switched (and most likely is SYSTEM_USER).
580 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
581 Log.wtf(TAG_USER, "Initial user set to null");
582 }
583 }
584
585 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700586 * Calls the User HAL to get the initial user info.
587 *
588 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
589 * @param callback callback to receive the results.
590 */
591 public void getInitialUserInfo(int requestType,
592 HalCallback<InitialUserInfoResponse> callback) {
593 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700594 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700595 UsersInfo usersInfo = getUsersInfo();
596 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
597 }
598
599 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700600 * Calls the User HAL to switch user.
601 *
Mayank Garge19c2922020-03-30 18:05:53 -0700602 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700603 * @param timeoutMs - timeout for HAL to wait
604 * @param receiver - receiver for the results
605 */
Mayank Garge19c2922020-03-30 18:05:53 -0700606 @Override
607 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
Mayank Garg59f22192020-03-27 00:51:45 -0700608 @NonNull IResultReceiver receiver) {
609 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700610 Objects.requireNonNull(receiver);
611 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
612 Preconditions.checkArgument(targetUser != null, "Invalid target user Id");
Mayank Garg59f22192020-03-27 00:51:45 -0700613 UsersInfo usersInfo = getUsersInfo();
614 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
615 new android.hardware.automotive.vehicle.V2_0.UserInfo();
616 halUser.userId = targetUser.id;
617 halUser.flags = UserHalHelper.convertFlags(targetUser);
618 mHal.switchUser(halUser, timeoutMs, usersInfo, (status, resp) -> {
619 Bundle resultData = null;
620 resultData = new Bundle();
Mayank Garge19c2922020-03-30 18:05:53 -0700621 int resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_INTERNAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700622 if (resp != null) {
Mayank Garge19c2922020-03-30 18:05:53 -0700623 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
624 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
625 if (resp.errorMessage != null) {
626 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
627 resp.errorMessage);
628 }
Mayank Garg59f22192020-03-27 00:51:45 -0700629 switch (resp.status) {
630 case SwitchUserStatus.SUCCESS:
631 boolean result;
632 try {
Mayank Garge19c2922020-03-30 18:05:53 -0700633 result = mAm.switchUser(targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700634 // TODO(b/150409110): post user switch OK/FAIL to Hal using
635 // ANDROID_POST_SWITCH
636 if (result) {
Mayank Garge19c2922020-03-30 18:05:53 -0700637 resultStatus = CarUserManager.USER_SWITCH_STATUS_SUCCESSFUL;
Mayank Garg59f22192020-03-27 00:51:45 -0700638 } else {
Mayank Garge19c2922020-03-30 18:05:53 -0700639 resultStatus = CarUserManager.USER_SWITCH_STATUS_ANDROID_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700640 }
641 } catch (RemoteException e) {
642 // ignore
643 Log.w(TAG_USER,
644 "error while switching user " + targetUser.toFullString(), e);
645 }
646 break;
647 case SwitchUserStatus.FAILURE:
648 // HAL failed to switch user
Mayank Garge19c2922020-03-30 18:05:53 -0700649 resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700650 break;
651 }
Mayank Garg59f22192020-03-27 00:51:45 -0700652 }
Mayank Garge19c2922020-03-30 18:05:53 -0700653 try {
654 receiver.send(resultStatus, resultData);
655 } catch (RemoteException e) {
656 // ignore
657 Log.w(TAG_USER, "error while sending results", e);
658 }
659
Mayank Garg59f22192020-03-27 00:51:45 -0700660 });
661 }
662
663 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700664 * Checks if the User HAL is supported.
665 */
666 public boolean isUserHalSupported() {
667 return mHal.isSupported();
668 }
669
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800670 // TODO(b/144120654): use helper to generate UsersInfo
671 private UsersInfo getUsersInfo() {
672 UserInfo currentUser;
673 try {
674 currentUser = mAm.getCurrentUser();
675 } catch (RemoteException e) {
676 // shouldn't happen
677 throw new IllegalStateException("Could not get current user: ", e);
678 }
679 List<UserInfo> existingUsers = mUserManager.getUsers();
680 int size = existingUsers.size();
681
682 UsersInfo usersInfo = new UsersInfo();
683 usersInfo.numberUsers = size;
684 usersInfo.currentUser.userId = currentUser.id;
685 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
686
687 for (int i = 0; i < size; i++) {
688 UserInfo androidUser = existingUsers.get(i);
689 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
690 new android.hardware.automotive.vehicle.V2_0.UserInfo();
691 halUser.userId = androidUser.id;
692 halUser.flags = UserHalHelper.convertFlags(androidUser);
693 usersInfo.existingUsers.add(halUser);
694 }
695
696 return usersInfo;
697 }
698
Eric Jeong1545f3b2019-09-16 13:56:52 -0700699 /** Returns whether the given user is a system user. */
700 private static boolean isSystemUser(@UserIdInt int userId) {
701 return userId == UserHandle.USER_SYSTEM;
702 }
703
Keun young Park13a7a822019-04-04 15:53:08 -0700704 private void updateDefaultUserRestriction() {
705 // We want to set restrictions on system and guest users only once. These are persisted
706 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
707 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700708 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
709 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700710 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700711 // Only apply the system user restrictions if the system user is headless.
712 if (UserManager.isHeadlessSystemUserMode()) {
713 setSystemUserRestrictions();
714 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700715 Settings.Global.putInt(mContext.getContentResolver(),
716 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700717 }
718
Eric Jeong1545f3b2019-09-16 13:56:52 -0700719 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700720 return !mUserManager.getUserInfo(userId).isEphemeral();
721 }
722
Antonio Kantekc8114752020-03-05 21:37:39 -0800723 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800724 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
725 */
726 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
727 Objects.requireNonNull(listener, "listener cannot be null");
728 mUserLifecycleListeners.add(listener);
729 }
730
731 /**
732 * Removes previously added {@link UserLifecycleListener}.
733 */
734 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
735 Objects.requireNonNull(listener, "listener cannot be null");
736 mUserLifecycleListeners.remove(listener);
737 }
738
Eric Jeongc91f9452019-08-30 15:04:21 -0700739 /** Adds callback to listen to passenger activity events. */
740 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000741 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700742 mPassengerCallbacks.add(callback);
743 }
744
745 /** Removes previously added callback to listen passenger events. */
746 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000747 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700748 mPassengerCallbacks.remove(callback);
749 }
750
751 /** Sets the implementation of ZoneUserBindingHelper. */
752 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
753 synchronized (mLockHelper) {
754 mZoneUserBindingHelper = helper;
755 }
756 }
757
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700758 private void unlockUser(@UserIdInt int userId) {
759 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
760 notifyUserLifecycleListeners(
felipeal042a73c2020-03-30 09:24:05 -0700761 new UserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, userId));
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700762 t.traceBegin("UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800763 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700764 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700765 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700766 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
767 updateDefaultUserRestriction();
768 tasks = new ArrayList<>(mUser0UnlockTasks);
769 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700770 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700771 }
772 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700773 Integer user = userId;
774 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700775 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700776 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700777 mBackgroundUsersToRestart.remove(user);
778 mBackgroundUsersToRestart.add(0, user);
779 }
780 // -1 for user 0
781 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700782 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700783 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700784 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700785 + ", dropping least recently user from restart list:" + userToDrop);
786 // Drop the least recently used user.
787 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
788 }
789 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800790 }
791 }
792 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700793 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800794 for (Runnable r : tasks) {
795 r.run();
796 }
797 }
Mayank Garg31e73042020-01-23 00:10:38 -0800798 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800799 }
800
801 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700802 * Starts all background users that were active in system.
803 *
Keun young Parkfb656372019-03-12 18:37:55 -0700804 * @return list of background users started successfully.
805 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700806 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700807 public ArrayList<Integer> startAllBackgroundUsers() {
808 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700809 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700810 users = new ArrayList<>(mBackgroundUsersToRestart);
811 mBackgroundUsersRestartedHere.clear();
812 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700813 }
814 ArrayList<Integer> startedUsers = new ArrayList<>();
815 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700816 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700817 continue;
818 }
819 try {
820 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700821 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
822 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700823 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700824 } else if (mAm.unlockUser(user, null, null, null)) {
825 startedUsers.add(user);
826 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700827 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700828 if (mUserManager.isUserRunning(user)) {
829 // add to started list so that it can be stopped later.
830 startedUsers.add(user);
831 }
Keun young Parkfb656372019-03-12 18:37:55 -0700832 }
833 }
834 } catch (RemoteException e) {
835 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700836 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700837 }
838 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700839 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700840 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700841 ArrayList<Integer> usersToRemove = new ArrayList<>();
842 for (Integer user : mBackgroundUsersToRestart) {
843 if (!startedUsers.contains(user)) {
844 usersToRemove.add(user);
845 }
846 }
847 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
848 }
Keun young Parkfb656372019-03-12 18:37:55 -0700849 return startedUsers;
850 }
851
852 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700853 * Stops all background users that were active in system.
854 *
855 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700856 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700857 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700858 if (userId == UserHandle.USER_SYSTEM) {
859 return false;
860 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700861 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700862 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700863 return false;
864 }
865 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700866 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700867 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700868 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700869 Integer user = userId;
870 mBackgroundUsersRestartedHere.remove(user);
871 }
872 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
873 return false;
874 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700875 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700876 return false;
877 }
878 } catch (RemoteException e) {
879 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700880 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700881 }
882 return true;
883 }
884
885 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700886 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700887 */
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700888 public void onUserLifecycleEvent(UserLifecycleEvent event) {
889 int userId = event.getUserId();
890 if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
891 onSwitchUser(userId);
892 } else if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) {
893 unlockUser(userId);
894 }
895
896 // TODO(b/144120654): right now just the app listeners are running in the background so the
897 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
898 // but once we refactor the car service callback into lifecycle listeners, we should use a
899 // proper thread management (like a Threadpool / executor);
900
901 // Notify all user listeners
902 notifyUserLifecycleListeners(event);
903
904 // Notify all app listeners
905 notifyAppLifecycleListeners(event);
906 }
907
908 private void notifyAppLifecycleListeners(UserLifecycleEvent event) {
909 int listenersSize = mLifecycleListeners.size();
910 if (listenersSize == 0) {
911 Log.i(TAG_USER, "No app listener to be notified");
912 return;
913 }
914 new Thread(() -> {
915 // Must use a different TimingsTraceLog because it's another thread
916 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
917 Log.i(TAG_USER, "Notifying " + listenersSize + " app listeners");
918 int userId = event.getUserId();
919 for (int i = 0; i < listenersSize; i++) {
920 int uid = mLifecycleListeners.keyAt(i);
921 IResultReceiver listener = mLifecycleListeners.valueAt(i);
922 t.traceBegin("notify-" + event.getEventType() + "-app-listener-" + uid);
923 Bundle data = new Bundle();
924 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
925 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
926 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
927 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
928 Log.d(TAG_USER, "Notifying listener for uid " + uid);
929 }
930 try {
931 listener.send(userId, data);
932 } catch (RemoteException e) {
933 Log.e(TAG_USER, "Error calling lifecycle listener", e);
934 } finally {
935 t.traceEnd();
936 }
937 }
938 }, "SwitchUser-" + event.getUserId() + "-Listeners").start();
939 }
940
941 private void notifyUserLifecycleListeners(UserLifecycleEvent event) {
942 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
943 if (mUserLifecycleListeners.isEmpty()) {
944 Log.i(TAG_USER, "Not notifying internal UserLifecycleListeners");
945 return;
946 }
947 t.traceBegin("notifyInternalUserLifecycleListeners");
948 for (UserLifecycleListener listener : mUserLifecycleListeners) {
949 t.traceBegin("notify-" + event.getEventType() + "-listener-" + listener);
950 try {
951 listener.onEvent(event);
952 } catch (RuntimeException e) {
953 Log.e(TAG_USER,
954 "Exception raised when invoking onEvent for " + listener, e);
955 }
956 t.traceEnd();
957 }
958 t.traceEnd();
959 }
960
961 private void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800962 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
963 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800964 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800965
Felipe Lemef45ee502019-12-19 10:00:14 -0800966 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700967 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700968 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700969 if (mLastPassengerId != UserHandle.USER_NULL) {
970 stopPassengerInternal(mLastPassengerId, false);
971 }
972 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
973 setupPassengerUser();
974 startFirstPassenger(userId);
975 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700976 }
977
978 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700979 * 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 -0800980 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700981 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800982 * @param r Runnable to run.
983 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700984 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000985 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800986 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700987 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800988 if (mUser0Unlocked) {
989 runNow = true;
990 } else {
991 mUser0UnlockTasks.add(r);
992 }
993 }
994 if (runNow) {
995 r.run();
996 }
997 }
998
Keun young Parkf3523cd2019-04-08 10:09:17 -0700999 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001000 @NonNull
1001 ArrayList<Integer> getBackgroundUsersToRestart() {
1002 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001003 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001004 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1005 }
1006 return backgroundUsersToRestart;
1007 }
1008
Ying Zheng1ab32b62018-06-26 12:47:26 -07001009 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001010 // Disable Location service for system user.
1011 LocationManager locationManager =
1012 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001013 locationManager.setLocationEnabledForUser(
1014 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001015 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001016
1017 /**
1018 * Creates a new user on the system, the created user would be granted admin role.
1019 *
1020 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001021 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001022 */
1023 @Nullable
1024 private UserInfo createNewAdminUser(String name) {
1025 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1026 // Only admins or system user can create other privileged users.
1027 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1028 return null;
1029 }
1030
1031 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1032 if (user == null) {
1033 // Couldn't create user, most likely because there are too many.
1034 Log.w(TAG_USER, "can't create admin user.");
1035 return null;
1036 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001037 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001038
1039 return user;
1040 }
1041
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001042 /**
1043 * Assigns a default icon to a user according to the user's id.
1044 *
1045 * @param userInfo User whose avatar is set to default icon.
1046 * @return Bitmap of the user icon.
1047 */
1048 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1049 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1050 Bitmap bitmap = UserIcons.convertToBitmap(
1051 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1052 mUserManager.setUserIcon(userInfo.id, bitmap);
1053 return bitmap;
1054 }
1055
Eric Jeong1545f3b2019-09-16 13:56:52 -07001056 private interface UserFilter {
1057 boolean isEligibleUser(UserInfo user);
1058 }
1059
1060 /** Returns all users who are matched by the given filter. */
1061 private List<UserInfo> getUsers(UserFilter filter) {
1062 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1063
1064 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1065 UserInfo user = iterator.next();
1066 if (!filter.isEligibleUser(user)) {
1067 iterator.remove();
1068 }
1069 }
1070 return users;
1071 }
1072
1073 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001074 * Enforces that apps which have the
1075 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1076 * can make certain calls to the CarUserManager.
1077 *
1078 * @param message used as message if SecurityException is thrown.
1079 * @throws SecurityException if the caller is not system or root.
1080 */
1081 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001082 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1083 }
1084
1085 private static void checkManageUsersOrDumpPermission(String message) {
1086 checkAtLeastOnePermission(message,
1087 android.Manifest.permission.MANAGE_USERS,
1088 android.Manifest.permission.DUMP);
1089 }
1090
Felipe Leme5528ff72020-02-10 19:05:14 -08001091 private void checkInteractAcrossUsersPermission(String message) {
1092 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1093 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1094 }
1095
felipeal2d0483c2019-11-02 14:07:22 -07001096 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001097 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001098 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1099 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001100 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001101 }
1102 }
1103
felipeal2d0483c2019-11-02 14:07:22 -07001104 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1105 for (String permission : permissions) {
1106 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1107 /* exported = */ true)
1108 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1109 return true;
1110 }
1111 }
1112 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001113 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001114
1115 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1116 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1117 // Count all users that are managed profiles of the given user.
1118 int managedProfilesCount = 0;
1119 for (UserInfo user : users) {
1120 if (user.isManagedProfile() && user.profileGroupId == userId) {
1121 managedProfilesCount++;
1122 }
1123 }
1124 return managedProfilesCount;
1125 }
1126
1127 /**
1128 * Starts the first passenger of the given driver and assigns the passenger to the front
1129 * passenger zone.
1130 *
1131 * @param driverId User id of the driver.
1132 * @return whether it succeeds.
1133 */
1134 private boolean startFirstPassenger(@UserIdInt int driverId) {
1135 int zoneId = getAvailablePassengerZone();
1136 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1137 Log.w(TAG_USER, "passenger occupant zone is not found");
1138 return false;
1139 }
1140 List<UserInfo> passengers = getPassengers(driverId);
1141 if (passengers.size() < 1) {
1142 Log.w(TAG_USER, "passenger is not found");
1143 return false;
1144 }
1145 // Only one passenger is supported. If there are two or more passengers, the first passenger
1146 // is chosen.
1147 int passengerId = passengers.get(0).id;
1148 if (!startPassenger(passengerId, zoneId)) {
1149 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1150 return false;
1151 }
1152 return true;
1153 }
1154
1155 private int getAvailablePassengerZone() {
1156 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1157 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1158 for (int occupantType : occupantTypes) {
1159 int zoneId = getZoneId(occupantType);
1160 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1161 return zoneId;
1162 }
1163 }
1164 return OccupantZoneInfo.INVALID_ZONE_ID;
1165 }
1166
1167 /**
1168 * Creates a new passenger user when there is no passenger user.
1169 */
1170 private void setupPassengerUser() {
1171 int currentUser = ActivityManager.getCurrentUser();
1172 int profileCount = getNumberOfManagedProfiles(currentUser);
1173 if (profileCount > 0) {
1174 Log.w(TAG_USER, "max profile of user" + currentUser
1175 + " is exceeded: current profile count is " + profileCount);
1176 return;
1177 }
1178 // TODO(b/140311342): Use resource string for the default passenger name.
1179 UserInfo passenger = createPassenger("Passenger", currentUser);
1180 if (passenger == null) {
1181 // Couldn't create user, most likely because there are too many.
1182 Log.w(TAG_USER, "cannot create a passenger user");
1183 return;
1184 }
1185 }
1186
1187 @NonNull
1188 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1189 ZoneUserBindingHelper helper = null;
1190 synchronized (mLockHelper) {
1191 if (mZoneUserBindingHelper == null) {
1192 Log.w(TAG_USER, "implementation is not delegated");
1193 return new ArrayList<OccupantZoneInfo>();
1194 }
1195 helper = mZoneUserBindingHelper;
1196 }
1197 return helper.getOccupantZones(occupantType);
1198 }
1199
1200 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1201 ZoneUserBindingHelper helper = null;
1202 synchronized (mLockHelper) {
1203 if (mZoneUserBindingHelper == null) {
1204 Log.w(TAG_USER, "implementation is not delegated");
1205 return false;
1206 }
1207 helper = mZoneUserBindingHelper;
1208 }
1209 return helper.assignUserToOccupantZone(userId, zoneId);
1210 }
1211
1212 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1213 ZoneUserBindingHelper helper = null;
1214 synchronized (mLockHelper) {
1215 if (mZoneUserBindingHelper == null) {
1216 Log.w(TAG_USER, "implementation is not delegated");
1217 return false;
1218 }
1219 helper = mZoneUserBindingHelper;
1220 }
1221 return helper.unassignUserFromOccupantZone(userId);
1222 }
1223
1224 private boolean isPassengerDisplayAvailable() {
1225 ZoneUserBindingHelper helper = null;
1226 synchronized (mLockHelper) {
1227 if (mZoneUserBindingHelper == null) {
1228 Log.w(TAG_USER, "implementation is not delegated");
1229 return false;
1230 }
1231 helper = mZoneUserBindingHelper;
1232 }
1233 return helper.isPassengerDisplayAvailable();
1234 }
1235
1236 /**
1237 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1238 * zone is returned.
1239 *
1240 * @param occupantType The type of an occupant.
1241 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1242 * if not found.
1243 */
1244 private int getZoneId(@OccupantTypeEnum int occupantType) {
1245 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1246 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1247 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001248}