blob: 196bd89b290ba1da2edfafcfe99999a64a778024 [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;
felipeal2a84d512020-04-06 18:52:15 -070065import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070066import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070067import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070068
69import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080070import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070071import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070072import java.util.Iterator;
73import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000074import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070075import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076
77/**
78 * User service for cars. Manages users at boot time. Including:
79 *
80 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070081 * <li> Creates a user used as driver.
82 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070083 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070084 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070085 * <ol/>
86 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070087public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080088
Felipe Lemeabbf2da2020-02-24 18:25:29 -080089 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080090 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080091 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080092 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080093 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080094 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080095 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
96 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -080097
Ying Zhengd3cb98e2018-05-11 11:42:48 -070098 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070099 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700100 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700101 private final UserManager mUserManager;
102 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700103 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700104
Eric Jeongc91f9452019-08-30 15:04:21 -0700105 private final Object mLockUser = new Object();
106 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800107 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700108 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800109 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700110 // Only one passenger is supported.
111 @GuardedBy("mLockUser")
112 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700113 /**
114 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800115 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700116 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700117 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700118 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
119 /**
120 * Keep the list of background users started here. This is wholly for debugging purpose.
121 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700122 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700123 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
124
Felipe Leme58412202020-01-09 13:45:33 -0800125 private final UserHalService mHal;
126
Felipe Leme5528ff72020-02-10 19:05:14 -0800127 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800128 * List of listeners to be notified on new user activities events.
129 */
130 private final CopyOnWriteArrayList<UserLifecycleListener>
131 mUserLifecycleListeners = new CopyOnWriteArrayList<>();
132
133 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800134 * List of lifecycle listeners by uid.
135 */
136 @GuardedBy("mLockUser")
137 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
138
Felipe Lemee3cab982020-03-12 11:39:29 -0700139 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
140
Eric Jeongc91f9452019-08-30 15:04:21 -0700141 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
142 new CopyOnWriteArrayList<>();
143
144 /** Interface for callbaks related to passenger activities. */
145 public interface PassengerCallback {
146 /** Called when passenger is started at a certain zone. */
147 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
148 /** Called when passenger is stopped. */
149 void onPassengerStopped(@UserIdInt int passengerId);
150 }
151
152 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
153 public interface ZoneUserBindingHelper {
154 /** Gets occupant zones corresponding to the occupant type. */
155 @NonNull
156 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
157 /** Assigns the user to the occupant zone. */
158 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
159 /** Makes the occupant zone unoccupied. */
160 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
161 /** Returns whether there is a passenger display. */
162 boolean isPassengerDisplayAvailable();
163 }
164
165 private final Object mLockHelper = new Object();
166 @GuardedBy("mLockHelper")
167 private ZoneUserBindingHelper mZoneUserBindingHelper;
168
Felipe Leme58412202020-01-09 13:45:33 -0800169 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
170 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700171 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700172 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
173 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700174 }
175 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800176 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700177 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700178 mAm = am;
179 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700180 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700181 mLastPassengerId = UserHandle.USER_NULL;
182 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700183 }
184
185 @Override
186 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700187 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
188 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700189 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700190 }
191
192 @Override
193 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700194 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
195 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700196 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700197 }
198
199 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700200 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700201 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700202 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800203 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700204 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800205 int numberListeners = mLifecycleListeners.size();
206 if (numberListeners == 0) {
207 writer.println("No lifecycle listeners");
208 } else {
209 writer.printf("%d lifecycle listeners\n", numberListeners);
210 for (int i = 0; i < numberListeners; i++) {
211 int uid = mLifecycleListeners.keyAt(i);
212 IResultReceiver listener = mLifecycleListeners.valueAt(i);
213 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
214 }
215 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700216 writer.println("User0Unlocked: " + mUser0Unlocked);
217 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
218 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
219 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700220 List<UserInfo> allDrivers = getAllDrivers();
221 int driversSize = allDrivers.size();
222 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700223 for (int i = 0; i < driversSize; i++) {
224 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800225 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700226 List<UserInfo> passengers = getPassengers(driverId);
227 int passengersSize = passengers.size();
228 writer.print(" NumberPassengers: " + passengersSize);
229 if (passengersSize > 0) {
230 writer.print(" [");
231 for (int j = 0; j < passengersSize; j++) {
232 writer.print(passengers.get(j).id);
233 if (j < passengersSize - 1) {
234 writer.print(" ");
235 }
236 }
237 writer.print("]");
238 }
239 writer.println();
240 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700241 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Felipe Lemee3cab982020-03-12 11:39:29 -0700242 writer.println("User HAL timeout: " + mHalTimeoutMs + "ms");
Felipe Leme315a53b2020-03-12 10:51:04 -0700243 writer.println("Relevant overlayable properties");
244 Resources res = mContext.getResources();
245 writer.printf("%sowner_name=%s\n", indent,
246 res.getString(com.android.internal.R.string.owner_name));
247 writer.printf("%sdefault_guest_name=%s\n", indent,
248 res.getString(R.string.default_guest_name));
Keun-young Parkd462a912019-02-11 08:53:42 -0800249 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700250 }
251
252 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800253 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
254 *
255 * @param name The name of the driver to be created.
256 * @param admin Whether the created driver will be an admin.
257 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
258 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700259 */
260 @Override
261 @Nullable
262 public UserInfo createDriver(@NonNull String name, boolean admin) {
263 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000264 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700265 if (admin) {
266 return createNewAdminUser(name);
267 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700268 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700269 }
270
271 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800272 * Creates a passenger who is a profile of the given driver.
273 *
274 * @param name The name of the passenger to be created.
275 * @param driverId User id of the driver under whom a passenger is created.
276 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
277 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700278 */
279 @Override
280 @Nullable
281 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
282 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000283 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700284 UserInfo driver = mUserManager.getUserInfo(driverId);
285 if (driver == null) {
286 Log.w(TAG_USER, "the driver is invalid");
287 return null;
288 }
289 if (driver.isGuest()) {
290 Log.w(TAG_USER, "a guest driver cannot create a passenger");
291 return null;
292 }
Bookatz42fb1a62019-10-30 11:45:01 -0700293 UserInfo user = mUserManager.createProfileForUser(name,
294 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700295 if (user == null) {
296 // Couldn't create user, most likely because there are too many.
297 Log.w(TAG_USER, "can't create a profile for user" + driverId);
298 return null;
299 }
300 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700301 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700302 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700303 return user;
304 }
305
306 /**
307 * @see CarUserManager.switchDriver
308 */
309 @Override
310 public boolean switchDriver(@UserIdInt int driverId) {
311 checkManageUsersPermission("switchDriver");
312 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
313 // System user doesn't associate with real person, can not be switched to.
314 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
315 return false;
316 }
317 int userSwitchable = mUserManager.getUserSwitchability();
318 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
319 Log.w(TAG_USER, "current process is not allowed to switch user");
320 return false;
321 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700322 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700323 // The current user is already the given user.
324 return true;
325 }
326 try {
327 return mAm.switchUser(driverId);
328 } catch (RemoteException e) {
329 // ignore
330 Log.w(TAG_USER, "error while switching user", e);
331 }
332 return false;
333 }
334
335 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800336 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
337 *
338 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700339 */
340 @Override
341 @NonNull
342 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700343 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700344 return getUsers((user) -> {
345 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
346 && !user.isEphemeral();
347 });
348 }
349
350 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800351 * Returns all passengers under the given driver.
352 *
353 * @param driverId User id of a driver.
354 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700355 */
356 @Override
357 @NonNull
358 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700359 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700360 return getUsers((user) -> {
361 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
362 && user.profileGroupId == driverId;
363 });
364 }
365
366 /**
367 * @see CarUserManager.startPassenger
368 */
369 @Override
370 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
371 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700372 synchronized (mLockUser) {
373 try {
374 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
375 Log.w(TAG_USER, "could not start passenger");
376 return false;
377 }
378 } catch (RemoteException e) {
379 // ignore
380 Log.w(TAG_USER, "error while starting passenger", e);
381 return false;
382 }
383 if (!assignUserToOccupantZone(passengerId, zoneId)) {
384 Log.w(TAG_USER, "could not assign passenger to zone");
385 return false;
386 }
387 mLastPassengerId = passengerId;
388 }
389 for (PassengerCallback callback : mPassengerCallbacks) {
390 callback.onPassengerStarted(passengerId, zoneId);
391 }
392 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700393 }
394
395 /**
396 * @see CarUserManager.stopPassenger
397 */
398 @Override
399 public boolean stopPassenger(@UserIdInt int passengerId) {
400 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700401 return stopPassengerInternal(passengerId, true);
402 }
403
404 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
405 synchronized (mLockUser) {
406 UserInfo passenger = mUserManager.getUserInfo(passengerId);
407 if (passenger == null) {
408 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
409 return false;
410 }
411 if (mLastPassengerId != passengerId) {
412 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
413 return true;
414 }
415 if (checkCurrentDriver) {
416 int currentUser = ActivityManager.getCurrentUser();
417 if (passenger.profileGroupId != currentUser) {
418 Log.w(TAG_USER, "passenger " + passengerId
419 + " is not a profile of the current user");
420 return false;
421 }
422 }
423 // Passenger is a profile, so cannot be stopped through activity manager.
424 // Instead, activities started by the passenger are stopped and the passenger is
425 // unassigned from the zone.
426 stopAllTasks(passengerId);
427 if (!unassignUserFromOccupantZone(passengerId)) {
428 Log.w(TAG_USER, "could not unassign user from occupant zone");
429 return false;
430 }
431 mLastPassengerId = UserHandle.USER_NULL;
432 }
433 for (PassengerCallback callback : mPassengerCallbacks) {
434 callback.onPassengerStopped(passengerId);
435 }
436 return true;
437 }
438
439 private void stopAllTasks(@UserIdInt int userId) {
440 try {
441 for (StackInfo info : mAm.getAllStackInfos()) {
442 for (int i = 0; i < info.taskIds.length; i++) {
443 if (info.taskUserIds[i] == userId) {
444 int taskId = info.taskIds[i];
445 if (!mAm.removeTask(taskId)) {
446 Log.w(TAG_USER, "could not remove task " + taskId);
447 }
448 }
449 }
450 }
451 } catch (RemoteException e) {
452 Log.e(TAG_USER, "could not get stack info", e);
453 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700454 }
455
Felipe Leme5528ff72020-02-10 19:05:14 -0800456 @Override
457 public void setLifecycleListenerForUid(IResultReceiver listener) {
458 int uid = Binder.getCallingUid();
459 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
460
461 try {
462 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
463 } catch (RemoteException e) {
464 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
465 }
466 synchronized (mLockUser) {
467 mLifecycleListeners.append(uid, listener);
468 }
469 }
470
471 private void onListenerDeath(int uid) {
472 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
473 synchronized (mLockUser) {
474 removeLifecycleListenerLocked(uid);
475 }
476 }
477
478 @Override
479 public void resetLifecycleListenerForUid() {
480 int uid = Binder.getCallingUid();
481 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
482
483 synchronized (mLockUser) {
484 removeLifecycleListenerLocked(uid);
485 }
486 }
487
488 private void removeLifecycleListenerLocked(int uid) {
489 mLifecycleListeners.remove(uid);
490 }
491
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800492 @Override
493 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800494 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800495 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700496 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800497 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800498 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
499 try {
500 Bundle resultData = null;
501 if (resp != null) {
502 switch (resp.action) {
503 case InitialUserInfoResponseAction.SWITCH:
504 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800505 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800506 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
507 break;
508 case InitialUserInfoResponseAction.CREATE:
509 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800510 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800511 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
512 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
513 break;
514 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800515 resultData = new Bundle();
516 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800517 break;
518 default:
519 // That's ok, it will be the same as DEFAULT...
520 Log.w(TAG_USER, "invalid response action on " + resp);
521 }
522 }
523 receiver.send(status, resultData);
524 } catch (RemoteException e) {
525 Log.w(TAG_USER, "Could not send result back to receiver", e);
526 }
527 });
528 }
529
Felipe Lemee3cab982020-03-12 11:39:29 -0700530 /**
531 * Calls the User HAL to get the initial user info.
532 *
533 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
534 * @param callback callback to receive the results.
535 */
536 public void getInitialUserInfo(int requestType,
537 HalCallback<InitialUserInfoResponse> callback) {
538 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700539 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700540 UsersInfo usersInfo = getUsersInfo();
541 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
542 }
543
544 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700545 * Calls the User HAL to switch user.
546 *
Mayank Garge19c2922020-03-30 18:05:53 -0700547 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700548 * @param timeoutMs - timeout for HAL to wait
549 * @param receiver - receiver for the results
550 */
Mayank Garge19c2922020-03-30 18:05:53 -0700551 @Override
552 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
Mayank Garg59f22192020-03-27 00:51:45 -0700553 @NonNull IResultReceiver receiver) {
554 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700555 Objects.requireNonNull(receiver);
556 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
557 Preconditions.checkArgument(targetUser != null, "Invalid target user Id");
Mayank Garg59f22192020-03-27 00:51:45 -0700558 UsersInfo usersInfo = getUsersInfo();
559 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
560 new android.hardware.automotive.vehicle.V2_0.UserInfo();
561 halUser.userId = targetUser.id;
562 halUser.flags = UserHalHelper.convertFlags(targetUser);
563 mHal.switchUser(halUser, timeoutMs, usersInfo, (status, resp) -> {
564 Bundle resultData = null;
565 resultData = new Bundle();
Mayank Garge19c2922020-03-30 18:05:53 -0700566 int resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_INTERNAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700567 if (resp != null) {
Mayank Garge19c2922020-03-30 18:05:53 -0700568 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
569 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
570 if (resp.errorMessage != null) {
571 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
572 resp.errorMessage);
573 }
Mayank Garg59f22192020-03-27 00:51:45 -0700574 switch (resp.status) {
575 case SwitchUserStatus.SUCCESS:
576 boolean result;
577 try {
Mayank Garge19c2922020-03-30 18:05:53 -0700578 result = mAm.switchUser(targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700579 // TODO(b/150409110): post user switch OK/FAIL to Hal using
580 // ANDROID_POST_SWITCH
581 if (result) {
Mayank Garge19c2922020-03-30 18:05:53 -0700582 resultStatus = CarUserManager.USER_SWITCH_STATUS_SUCCESSFUL;
Mayank Garg59f22192020-03-27 00:51:45 -0700583 } else {
Mayank Garge19c2922020-03-30 18:05:53 -0700584 resultStatus = CarUserManager.USER_SWITCH_STATUS_ANDROID_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700585 }
586 } catch (RemoteException e) {
587 // ignore
588 Log.w(TAG_USER,
589 "error while switching user " + targetUser.toFullString(), e);
590 }
591 break;
592 case SwitchUserStatus.FAILURE:
593 // HAL failed to switch user
Mayank Garge19c2922020-03-30 18:05:53 -0700594 resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700595 break;
596 }
Mayank Garg59f22192020-03-27 00:51:45 -0700597 }
Mayank Garge19c2922020-03-30 18:05:53 -0700598 try {
599 receiver.send(resultStatus, resultData);
600 } catch (RemoteException e) {
601 // ignore
602 Log.w(TAG_USER, "error while sending results", e);
603 }
604
Mayank Garg59f22192020-03-27 00:51:45 -0700605 });
606 }
607
608 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700609 * Checks if the User HAL is supported.
610 */
611 public boolean isUserHalSupported() {
612 return mHal.isSupported();
613 }
614
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800615 // TODO(b/144120654): use helper to generate UsersInfo
616 private UsersInfo getUsersInfo() {
617 UserInfo currentUser;
618 try {
619 currentUser = mAm.getCurrentUser();
620 } catch (RemoteException e) {
621 // shouldn't happen
622 throw new IllegalStateException("Could not get current user: ", e);
623 }
624 List<UserInfo> existingUsers = mUserManager.getUsers();
625 int size = existingUsers.size();
626
627 UsersInfo usersInfo = new UsersInfo();
628 usersInfo.numberUsers = size;
629 usersInfo.currentUser.userId = currentUser.id;
630 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
631
632 for (int i = 0; i < size; i++) {
633 UserInfo androidUser = existingUsers.get(i);
634 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
635 new android.hardware.automotive.vehicle.V2_0.UserInfo();
636 halUser.userId = androidUser.id;
637 halUser.flags = UserHalHelper.convertFlags(androidUser);
638 usersInfo.existingUsers.add(halUser);
639 }
640
641 return usersInfo;
642 }
643
Eric Jeong1545f3b2019-09-16 13:56:52 -0700644 /** Returns whether the given user is a system user. */
645 private static boolean isSystemUser(@UserIdInt int userId) {
646 return userId == UserHandle.USER_SYSTEM;
647 }
648
Keun young Park13a7a822019-04-04 15:53:08 -0700649 private void updateDefaultUserRestriction() {
650 // We want to set restrictions on system and guest users only once. These are persisted
651 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
652 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700653 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
654 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700655 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700656 // Only apply the system user restrictions if the system user is headless.
657 if (UserManager.isHeadlessSystemUserMode()) {
658 setSystemUserRestrictions();
659 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700660 Settings.Global.putInt(mContext.getContentResolver(),
661 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700662 }
663
Eric Jeong1545f3b2019-09-16 13:56:52 -0700664 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700665 return !mUserManager.getUserInfo(userId).isEphemeral();
666 }
667
Antonio Kantekc8114752020-03-05 21:37:39 -0800668 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800669 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
670 */
671 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
672 Objects.requireNonNull(listener, "listener cannot be null");
673 mUserLifecycleListeners.add(listener);
674 }
675
676 /**
677 * Removes previously added {@link UserLifecycleListener}.
678 */
679 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
680 Objects.requireNonNull(listener, "listener cannot be null");
681 mUserLifecycleListeners.remove(listener);
682 }
683
Eric Jeongc91f9452019-08-30 15:04:21 -0700684 /** Adds callback to listen to passenger activity events. */
685 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000686 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700687 mPassengerCallbacks.add(callback);
688 }
689
690 /** Removes previously added callback to listen passenger events. */
691 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000692 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700693 mPassengerCallbacks.remove(callback);
694 }
695
696 /** Sets the implementation of ZoneUserBindingHelper. */
697 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
698 synchronized (mLockHelper) {
699 mZoneUserBindingHelper = helper;
700 }
701 }
702
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700703 private void unlockUser(@UserIdInt int userId) {
704 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
705 notifyUserLifecycleListeners(
felipeal042a73c2020-03-30 09:24:05 -0700706 new UserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, userId));
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700707 t.traceBegin("UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800708 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700709 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700710 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700711 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
712 updateDefaultUserRestriction();
713 tasks = new ArrayList<>(mUser0UnlockTasks);
714 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700715 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700716 }
717 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700718 Integer user = userId;
719 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700720 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700721 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700722 mBackgroundUsersToRestart.remove(user);
723 mBackgroundUsersToRestart.add(0, user);
724 }
725 // -1 for user 0
726 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700727 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700728 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700729 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700730 + ", dropping least recently user from restart list:" + userToDrop);
731 // Drop the least recently used user.
732 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
733 }
734 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800735 }
736 }
737 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700738 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800739 for (Runnable r : tasks) {
740 r.run();
741 }
742 }
Mayank Garg31e73042020-01-23 00:10:38 -0800743 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800744 }
745
746 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700747 * Starts all background users that were active in system.
748 *
Keun young Parkfb656372019-03-12 18:37:55 -0700749 * @return list of background users started successfully.
750 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700751 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700752 public ArrayList<Integer> startAllBackgroundUsers() {
753 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700754 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700755 users = new ArrayList<>(mBackgroundUsersToRestart);
756 mBackgroundUsersRestartedHere.clear();
757 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700758 }
759 ArrayList<Integer> startedUsers = new ArrayList<>();
760 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700761 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700762 continue;
763 }
764 try {
765 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700766 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
767 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700768 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700769 } else if (mAm.unlockUser(user, null, null, null)) {
770 startedUsers.add(user);
771 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700772 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700773 if (mUserManager.isUserRunning(user)) {
774 // add to started list so that it can be stopped later.
775 startedUsers.add(user);
776 }
Keun young Parkfb656372019-03-12 18:37:55 -0700777 }
778 }
779 } catch (RemoteException e) {
780 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700781 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700782 }
783 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700784 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700785 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700786 ArrayList<Integer> usersToRemove = new ArrayList<>();
787 for (Integer user : mBackgroundUsersToRestart) {
788 if (!startedUsers.contains(user)) {
789 usersToRemove.add(user);
790 }
791 }
792 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
793 }
Keun young Parkfb656372019-03-12 18:37:55 -0700794 return startedUsers;
795 }
796
797 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700798 * Stops all background users that were active in system.
799 *
800 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700801 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700802 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700803 if (userId == UserHandle.USER_SYSTEM) {
804 return false;
805 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700806 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700807 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700808 return false;
809 }
810 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700811 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700812 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700813 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700814 Integer user = userId;
815 mBackgroundUsersRestartedHere.remove(user);
816 }
817 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
818 return false;
819 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700820 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700821 return false;
822 }
823 } catch (RemoteException e) {
824 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700825 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700826 }
827 return true;
828 }
829
830 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700831 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700832 */
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700833 public void onUserLifecycleEvent(UserLifecycleEvent event) {
834 int userId = event.getUserId();
835 if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
836 onSwitchUser(userId);
837 } else if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) {
838 unlockUser(userId);
839 }
840
841 // TODO(b/144120654): right now just the app listeners are running in the background so the
842 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
843 // but once we refactor the car service callback into lifecycle listeners, we should use a
844 // proper thread management (like a Threadpool / executor);
845
846 // Notify all user listeners
847 notifyUserLifecycleListeners(event);
848
849 // Notify all app listeners
850 notifyAppLifecycleListeners(event);
851 }
852
853 private void notifyAppLifecycleListeners(UserLifecycleEvent event) {
854 int listenersSize = mLifecycleListeners.size();
855 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -0700856 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
857 Log.d(TAG_USER, "No app listener to be notified of " + event);
858 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700859 return;
860 }
felipeal2a84d512020-04-06 18:52:15 -0700861 int userId = event.getUserId();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700862 new Thread(() -> {
863 // Must use a different TimingsTraceLog because it's another thread
864 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal2a84d512020-04-06 18:52:15 -0700865 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
866 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
867 }
868 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700869 for (int i = 0; i < listenersSize; i++) {
870 int uid = mLifecycleListeners.keyAt(i);
felipeal2a84d512020-04-06 18:52:15 -0700871 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700872 Bundle data = new Bundle();
873 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
874 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
875 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
felipeal2a84d512020-04-06 18:52:15 -0700876 IResultReceiver listener = mLifecycleListeners.valueAt(i);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700877 try {
878 listener.send(userId, data);
879 } catch (RemoteException e) {
880 Log.e(TAG_USER, "Error calling lifecycle listener", e);
881 } finally {
882 t.traceEnd();
883 }
884 }
felipeal2a84d512020-04-06 18:52:15 -0700885 t.traceEnd();
886 }, "SwitchUser-" + userId + "-AppListeners").start();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700887 }
888
889 private void notifyUserLifecycleListeners(UserLifecycleEvent event) {
890 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
891 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -0700892 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700893 return;
felipeal2a84d512020-04-06 18:52:15 -0700894 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
895 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
896 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700897 }
felipeal2a84d512020-04-06 18:52:15 -0700898
899 t.traceBegin("notify-listeners-" + event.getUserId() + "-event-" + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700900 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -0700901 String listenerName = FunctionalUtils.getLambdaName(listener);
902 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700903 try {
904 listener.onEvent(event);
905 } catch (RuntimeException e) {
906 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -0700907 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700908 }
909 t.traceEnd();
910 }
911 t.traceEnd();
912 }
913
914 private void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800915 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
916 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800917 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800918
Felipe Lemef45ee502019-12-19 10:00:14 -0800919 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700920 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700921 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700922 if (mLastPassengerId != UserHandle.USER_NULL) {
923 stopPassengerInternal(mLastPassengerId, false);
924 }
925 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
926 setupPassengerUser();
927 startFirstPassenger(userId);
928 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700929 }
930
931 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700932 * 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 -0800933 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700934 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800935 * @param r Runnable to run.
936 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700937 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000938 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800939 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700940 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800941 if (mUser0Unlocked) {
942 runNow = true;
943 } else {
944 mUser0UnlockTasks.add(r);
945 }
946 }
947 if (runNow) {
948 r.run();
949 }
950 }
951
Keun young Parkf3523cd2019-04-08 10:09:17 -0700952 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700953 @NonNull
954 ArrayList<Integer> getBackgroundUsersToRestart() {
955 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700956 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700957 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
958 }
959 return backgroundUsersToRestart;
960 }
961
Ying Zheng1ab32b62018-06-26 12:47:26 -0700962 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700963 // Disable Location service for system user.
964 LocationManager locationManager =
965 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800966 locationManager.setLocationEnabledForUser(
967 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700968 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700969
970 /**
971 * Creates a new user on the system, the created user would be granted admin role.
972 *
973 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700974 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700975 */
976 @Nullable
977 private UserInfo createNewAdminUser(String name) {
978 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
979 // Only admins or system user can create other privileged users.
980 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
981 return null;
982 }
983
984 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
985 if (user == null) {
986 // Couldn't create user, most likely because there are too many.
987 Log.w(TAG_USER, "can't create admin user.");
988 return null;
989 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700990 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700991
992 return user;
993 }
994
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700995 /**
996 * Assigns a default icon to a user according to the user's id.
997 *
998 * @param userInfo User whose avatar is set to default icon.
999 * @return Bitmap of the user icon.
1000 */
1001 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1002 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1003 Bitmap bitmap = UserIcons.convertToBitmap(
1004 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1005 mUserManager.setUserIcon(userInfo.id, bitmap);
1006 return bitmap;
1007 }
1008
Eric Jeong1545f3b2019-09-16 13:56:52 -07001009 private interface UserFilter {
1010 boolean isEligibleUser(UserInfo user);
1011 }
1012
1013 /** Returns all users who are matched by the given filter. */
1014 private List<UserInfo> getUsers(UserFilter filter) {
1015 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1016
1017 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1018 UserInfo user = iterator.next();
1019 if (!filter.isEligibleUser(user)) {
1020 iterator.remove();
1021 }
1022 }
1023 return users;
1024 }
1025
1026 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001027 * Enforces that apps which have the
1028 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1029 * can make certain calls to the CarUserManager.
1030 *
1031 * @param message used as message if SecurityException is thrown.
1032 * @throws SecurityException if the caller is not system or root.
1033 */
1034 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001035 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1036 }
1037
1038 private static void checkManageUsersOrDumpPermission(String message) {
1039 checkAtLeastOnePermission(message,
1040 android.Manifest.permission.MANAGE_USERS,
1041 android.Manifest.permission.DUMP);
1042 }
1043
Felipe Leme5528ff72020-02-10 19:05:14 -08001044 private void checkInteractAcrossUsersPermission(String message) {
1045 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1046 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1047 }
1048
felipeal2d0483c2019-11-02 14:07:22 -07001049 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001050 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001051 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1052 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001053 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001054 }
1055 }
1056
felipeal2d0483c2019-11-02 14:07:22 -07001057 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1058 for (String permission : permissions) {
1059 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1060 /* exported = */ true)
1061 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1062 return true;
1063 }
1064 }
1065 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001066 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001067
1068 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1069 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1070 // Count all users that are managed profiles of the given user.
1071 int managedProfilesCount = 0;
1072 for (UserInfo user : users) {
1073 if (user.isManagedProfile() && user.profileGroupId == userId) {
1074 managedProfilesCount++;
1075 }
1076 }
1077 return managedProfilesCount;
1078 }
1079
1080 /**
1081 * Starts the first passenger of the given driver and assigns the passenger to the front
1082 * passenger zone.
1083 *
1084 * @param driverId User id of the driver.
1085 * @return whether it succeeds.
1086 */
1087 private boolean startFirstPassenger(@UserIdInt int driverId) {
1088 int zoneId = getAvailablePassengerZone();
1089 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1090 Log.w(TAG_USER, "passenger occupant zone is not found");
1091 return false;
1092 }
1093 List<UserInfo> passengers = getPassengers(driverId);
1094 if (passengers.size() < 1) {
1095 Log.w(TAG_USER, "passenger is not found");
1096 return false;
1097 }
1098 // Only one passenger is supported. If there are two or more passengers, the first passenger
1099 // is chosen.
1100 int passengerId = passengers.get(0).id;
1101 if (!startPassenger(passengerId, zoneId)) {
1102 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1103 return false;
1104 }
1105 return true;
1106 }
1107
1108 private int getAvailablePassengerZone() {
1109 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1110 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1111 for (int occupantType : occupantTypes) {
1112 int zoneId = getZoneId(occupantType);
1113 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1114 return zoneId;
1115 }
1116 }
1117 return OccupantZoneInfo.INVALID_ZONE_ID;
1118 }
1119
1120 /**
1121 * Creates a new passenger user when there is no passenger user.
1122 */
1123 private void setupPassengerUser() {
1124 int currentUser = ActivityManager.getCurrentUser();
1125 int profileCount = getNumberOfManagedProfiles(currentUser);
1126 if (profileCount > 0) {
1127 Log.w(TAG_USER, "max profile of user" + currentUser
1128 + " is exceeded: current profile count is " + profileCount);
1129 return;
1130 }
1131 // TODO(b/140311342): Use resource string for the default passenger name.
1132 UserInfo passenger = createPassenger("Passenger", currentUser);
1133 if (passenger == null) {
1134 // Couldn't create user, most likely because there are too many.
1135 Log.w(TAG_USER, "cannot create a passenger user");
1136 return;
1137 }
1138 }
1139
1140 @NonNull
1141 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1142 ZoneUserBindingHelper helper = null;
1143 synchronized (mLockHelper) {
1144 if (mZoneUserBindingHelper == null) {
1145 Log.w(TAG_USER, "implementation is not delegated");
1146 return new ArrayList<OccupantZoneInfo>();
1147 }
1148 helper = mZoneUserBindingHelper;
1149 }
1150 return helper.getOccupantZones(occupantType);
1151 }
1152
1153 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1154 ZoneUserBindingHelper helper = null;
1155 synchronized (mLockHelper) {
1156 if (mZoneUserBindingHelper == null) {
1157 Log.w(TAG_USER, "implementation is not delegated");
1158 return false;
1159 }
1160 helper = mZoneUserBindingHelper;
1161 }
1162 return helper.assignUserToOccupantZone(userId, zoneId);
1163 }
1164
1165 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1166 ZoneUserBindingHelper helper = null;
1167 synchronized (mLockHelper) {
1168 if (mZoneUserBindingHelper == null) {
1169 Log.w(TAG_USER, "implementation is not delegated");
1170 return false;
1171 }
1172 helper = mZoneUserBindingHelper;
1173 }
1174 return helper.unassignUserFromOccupantZone(userId);
1175 }
1176
1177 private boolean isPassengerDisplayAvailable() {
1178 ZoneUserBindingHelper helper = null;
1179 synchronized (mLockHelper) {
1180 if (mZoneUserBindingHelper == null) {
1181 Log.w(TAG_USER, "implementation is not delegated");
1182 return false;
1183 }
1184 helper = mZoneUserBindingHelper;
1185 }
1186 return helper.isPassengerDisplayAvailable();
1187 }
1188
1189 /**
1190 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1191 * zone is returned.
1192 *
1193 * @param occupantType The type of an occupant.
1194 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1195 * if not found.
1196 */
1197 private int getZoneId(@OccupantTypeEnum int occupantType) {
1198 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1199 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1200 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001201}