blob: 6606fa367f5f168d2ac70c16b34a2ee8fce2b5fe [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;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070065import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070066
67import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080068import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070069import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070070import java.util.Iterator;
71import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000072import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070073import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070074
75/**
76 * User service for cars. Manages users at boot time. Including:
77 *
78 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070079 * <li> Creates a user used as driver.
80 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070082 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070083 * <ol/>
84 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070085public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080086
Felipe Lemeabbf2da2020-02-24 18:25:29 -080087 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080088 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080089 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080090 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080091 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080092 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080093 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
94 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -080095
Ying Zhengd3cb98e2018-05-11 11:42:48 -070096 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -070097 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070098 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070099 private final UserManager mUserManager;
100 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700101 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700102
Eric Jeongc91f9452019-08-30 15:04:21 -0700103 private final Object mLockUser = new Object();
104 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800105 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700106 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800107 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700108 // Only one passenger is supported.
109 @GuardedBy("mLockUser")
110 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700111 /**
112 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800113 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700114 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700115 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700116 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
117 /**
118 * Keep the list of background users started here. This is wholly for debugging purpose.
119 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700120 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700121 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
122
Antonio Kantekc8114752020-03-05 21:37:39 -0800123 // TODO(b/144120654): merge then
Pavel Maltsev17e81832019-04-04 14:38:41 -0700124 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
125
Felipe Leme58412202020-01-09 13:45:33 -0800126 private final UserHalService mHal;
127
Felipe Leme5528ff72020-02-10 19:05:14 -0800128 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800129 * List of listeners to be notified on new user activities events.
130 */
131 private final CopyOnWriteArrayList<UserLifecycleListener>
132 mUserLifecycleListeners = new CopyOnWriteArrayList<>();
133
134 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800135 * List of lifecycle listeners by uid.
136 */
137 @GuardedBy("mLockUser")
138 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
139
Felipe Lemee3cab982020-03-12 11:39:29 -0700140 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
141
Antonio Kantekc8114752020-03-05 21:37:39 -0800142 /**
143 * Interface for callbacks related to user activities.
144 *
145 * @deprecated {@link UserCallback} will be fully replaced by
146 * {@link UserLifecycleListener} as part of b/145689885
147 */
148 @Deprecated
Pavel Maltsev17e81832019-04-04 14:38:41 -0700149 public interface UserCallback {
150 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700151 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700152 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700153 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700154 }
155
Eric Jeongc91f9452019-08-30 15:04:21 -0700156 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
157 new CopyOnWriteArrayList<>();
158
159 /** Interface for callbaks related to passenger activities. */
160 public interface PassengerCallback {
161 /** Called when passenger is started at a certain zone. */
162 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
163 /** Called when passenger is stopped. */
164 void onPassengerStopped(@UserIdInt int passengerId);
165 }
166
167 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
168 public interface ZoneUserBindingHelper {
169 /** Gets occupant zones corresponding to the occupant type. */
170 @NonNull
171 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
172 /** Assigns the user to the occupant zone. */
173 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
174 /** Makes the occupant zone unoccupied. */
175 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
176 /** Returns whether there is a passenger display. */
177 boolean isPassengerDisplayAvailable();
178 }
179
180 private final Object mLockHelper = new Object();
181 @GuardedBy("mLockHelper")
182 private ZoneUserBindingHelper mZoneUserBindingHelper;
183
Felipe Leme58412202020-01-09 13:45:33 -0800184 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
185 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700186 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700187 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
188 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700189 }
190 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800191 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700192 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700193 mAm = am;
194 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700195 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700196 mLastPassengerId = UserHandle.USER_NULL;
197 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700198 }
199
200 @Override
201 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700202 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
203 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700204 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700205 }
206
207 @Override
208 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700209 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
210 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700211 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700212 }
213
214 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700215 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700216 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700217 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800218 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700219 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800220 int numberListeners = mLifecycleListeners.size();
221 if (numberListeners == 0) {
222 writer.println("No lifecycle listeners");
223 } else {
224 writer.printf("%d lifecycle listeners\n", numberListeners);
225 for (int i = 0; i < numberListeners; i++) {
226 int uid = mLifecycleListeners.keyAt(i);
227 IResultReceiver listener = mLifecycleListeners.valueAt(i);
228 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
229 }
230 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700231 writer.println("User0Unlocked: " + mUser0Unlocked);
232 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
233 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
234 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700235 List<UserInfo> allDrivers = getAllDrivers();
236 int driversSize = allDrivers.size();
237 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700238 for (int i = 0; i < driversSize; i++) {
239 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800240 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700241 List<UserInfo> passengers = getPassengers(driverId);
242 int passengersSize = passengers.size();
243 writer.print(" NumberPassengers: " + passengersSize);
244 if (passengersSize > 0) {
245 writer.print(" [");
246 for (int j = 0; j < passengersSize; j++) {
247 writer.print(passengers.get(j).id);
248 if (j < passengersSize - 1) {
249 writer.print(" ");
250 }
251 }
252 writer.print("]");
253 }
254 writer.println();
255 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700256 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Felipe Lemee3cab982020-03-12 11:39:29 -0700257 writer.println("User HAL timeout: " + mHalTimeoutMs + "ms");
Felipe Leme315a53b2020-03-12 10:51:04 -0700258 writer.println("Relevant overlayable properties");
259 Resources res = mContext.getResources();
260 writer.printf("%sowner_name=%s\n", indent,
261 res.getString(com.android.internal.R.string.owner_name));
262 writer.printf("%sdefault_guest_name=%s\n", indent,
263 res.getString(R.string.default_guest_name));
Keun-young Parkd462a912019-02-11 08:53:42 -0800264 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700265 }
266
267 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800268 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
269 *
270 * @param name The name of the driver to be created.
271 * @param admin Whether the created driver will be an admin.
272 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
273 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700274 */
275 @Override
276 @Nullable
277 public UserInfo createDriver(@NonNull String name, boolean admin) {
278 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000279 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700280 if (admin) {
281 return createNewAdminUser(name);
282 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700283 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700284 }
285
286 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800287 * Creates a passenger who is a profile of the given driver.
288 *
289 * @param name The name of the passenger to be created.
290 * @param driverId User id of the driver under whom a passenger is created.
291 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
292 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700293 */
294 @Override
295 @Nullable
296 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
297 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000298 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700299 UserInfo driver = mUserManager.getUserInfo(driverId);
300 if (driver == null) {
301 Log.w(TAG_USER, "the driver is invalid");
302 return null;
303 }
304 if (driver.isGuest()) {
305 Log.w(TAG_USER, "a guest driver cannot create a passenger");
306 return null;
307 }
Bookatz42fb1a62019-10-30 11:45:01 -0700308 UserInfo user = mUserManager.createProfileForUser(name,
309 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700310 if (user == null) {
311 // Couldn't create user, most likely because there are too many.
312 Log.w(TAG_USER, "can't create a profile for user" + driverId);
313 return null;
314 }
315 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700316 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700317 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700318 return user;
319 }
320
321 /**
322 * @see CarUserManager.switchDriver
323 */
324 @Override
325 public boolean switchDriver(@UserIdInt int driverId) {
326 checkManageUsersPermission("switchDriver");
327 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
328 // System user doesn't associate with real person, can not be switched to.
329 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
330 return false;
331 }
332 int userSwitchable = mUserManager.getUserSwitchability();
333 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
334 Log.w(TAG_USER, "current process is not allowed to switch user");
335 return false;
336 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700337 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700338 // The current user is already the given user.
339 return true;
340 }
341 try {
342 return mAm.switchUser(driverId);
343 } catch (RemoteException e) {
344 // ignore
345 Log.w(TAG_USER, "error while switching user", e);
346 }
347 return false;
348 }
349
350 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800351 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
352 *
353 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700354 */
355 @Override
356 @NonNull
357 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700358 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700359 return getUsers((user) -> {
360 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
361 && !user.isEphemeral();
362 });
363 }
364
365 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800366 * Returns all passengers under the given driver.
367 *
368 * @param driverId User id of a driver.
369 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700370 */
371 @Override
372 @NonNull
373 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700374 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700375 return getUsers((user) -> {
376 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
377 && user.profileGroupId == driverId;
378 });
379 }
380
381 /**
382 * @see CarUserManager.startPassenger
383 */
384 @Override
385 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
386 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700387 synchronized (mLockUser) {
388 try {
389 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
390 Log.w(TAG_USER, "could not start passenger");
391 return false;
392 }
393 } catch (RemoteException e) {
394 // ignore
395 Log.w(TAG_USER, "error while starting passenger", e);
396 return false;
397 }
398 if (!assignUserToOccupantZone(passengerId, zoneId)) {
399 Log.w(TAG_USER, "could not assign passenger to zone");
400 return false;
401 }
402 mLastPassengerId = passengerId;
403 }
404 for (PassengerCallback callback : mPassengerCallbacks) {
405 callback.onPassengerStarted(passengerId, zoneId);
406 }
407 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700408 }
409
410 /**
411 * @see CarUserManager.stopPassenger
412 */
413 @Override
414 public boolean stopPassenger(@UserIdInt int passengerId) {
415 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700416 return stopPassengerInternal(passengerId, true);
417 }
418
419 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
420 synchronized (mLockUser) {
421 UserInfo passenger = mUserManager.getUserInfo(passengerId);
422 if (passenger == null) {
423 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
424 return false;
425 }
426 if (mLastPassengerId != passengerId) {
427 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
428 return true;
429 }
430 if (checkCurrentDriver) {
431 int currentUser = ActivityManager.getCurrentUser();
432 if (passenger.profileGroupId != currentUser) {
433 Log.w(TAG_USER, "passenger " + passengerId
434 + " is not a profile of the current user");
435 return false;
436 }
437 }
438 // Passenger is a profile, so cannot be stopped through activity manager.
439 // Instead, activities started by the passenger are stopped and the passenger is
440 // unassigned from the zone.
441 stopAllTasks(passengerId);
442 if (!unassignUserFromOccupantZone(passengerId)) {
443 Log.w(TAG_USER, "could not unassign user from occupant zone");
444 return false;
445 }
446 mLastPassengerId = UserHandle.USER_NULL;
447 }
448 for (PassengerCallback callback : mPassengerCallbacks) {
449 callback.onPassengerStopped(passengerId);
450 }
451 return true;
452 }
453
454 private void stopAllTasks(@UserIdInt int userId) {
455 try {
456 for (StackInfo info : mAm.getAllStackInfos()) {
457 for (int i = 0; i < info.taskIds.length; i++) {
458 if (info.taskUserIds[i] == userId) {
459 int taskId = info.taskIds[i];
460 if (!mAm.removeTask(taskId)) {
461 Log.w(TAG_USER, "could not remove task " + taskId);
462 }
463 }
464 }
465 }
466 } catch (RemoteException e) {
467 Log.e(TAG_USER, "could not get stack info", e);
468 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700469 }
470
Felipe Leme5528ff72020-02-10 19:05:14 -0800471 @Override
472 public void setLifecycleListenerForUid(IResultReceiver listener) {
473 int uid = Binder.getCallingUid();
474 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
475
476 try {
477 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
478 } catch (RemoteException e) {
479 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
480 }
481 synchronized (mLockUser) {
482 mLifecycleListeners.append(uid, listener);
483 }
484 }
485
486 private void onListenerDeath(int uid) {
487 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
488 synchronized (mLockUser) {
489 removeLifecycleListenerLocked(uid);
490 }
491 }
492
493 @Override
494 public void resetLifecycleListenerForUid() {
495 int uid = Binder.getCallingUid();
496 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
497
498 synchronized (mLockUser) {
499 removeLifecycleListenerLocked(uid);
500 }
501 }
502
503 private void removeLifecycleListenerLocked(int uid) {
504 mLifecycleListeners.remove(uid);
505 }
506
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800507 @Override
508 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800509 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800510 Objects.requireNonNull(receiver, "receiver cannot be null");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800511 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800512 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
513 try {
514 Bundle resultData = null;
515 if (resp != null) {
516 switch (resp.action) {
517 case InitialUserInfoResponseAction.SWITCH:
518 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800519 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800520 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
521 break;
522 case InitialUserInfoResponseAction.CREATE:
523 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800524 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800525 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
526 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
527 break;
528 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800529 resultData = new Bundle();
530 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800531 break;
532 default:
533 // That's ok, it will be the same as DEFAULT...
534 Log.w(TAG_USER, "invalid response action on " + resp);
535 }
536 }
537 receiver.send(status, resultData);
538 } catch (RemoteException e) {
539 Log.w(TAG_USER, "Could not send result back to receiver", e);
540 }
541 });
542 }
543
Felipe Lemee3cab982020-03-12 11:39:29 -0700544 /**
545 * Calls the User HAL to get the initial user info.
546 *
547 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
548 * @param callback callback to receive the results.
549 */
550 public void getInitialUserInfo(int requestType,
551 HalCallback<InitialUserInfoResponse> callback) {
552 Objects.requireNonNull(callback, "callback cannot be null");
553 UsersInfo usersInfo = getUsersInfo();
554 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
555 }
556
557 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700558 * Calls the User HAL to switch user.
559 *
560 * @param targetUser - target user info
561 * @param timeoutMs - timeout for HAL to wait
562 * @param receiver - receiver for the results
563 */
564 public void switchUser(@NonNull UserInfo targetUser, int timeoutMs,
565 @NonNull IResultReceiver receiver) {
566 checkManageUsersPermission("switchUser");
567 UsersInfo usersInfo = getUsersInfo();
568 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
569 new android.hardware.automotive.vehicle.V2_0.UserInfo();
570 halUser.userId = targetUser.id;
571 halUser.flags = UserHalHelper.convertFlags(targetUser);
572 mHal.switchUser(halUser, timeoutMs, usersInfo, (status, resp) -> {
573 Bundle resultData = null;
574 resultData = new Bundle();
575 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
576 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
577 int resultStatus = CarUserManager.USER_SWICTH_STATUS_UNKNOWN;
578 if (resp != null) {
579 switch (resp.status) {
580 case SwitchUserStatus.SUCCESS:
581 boolean result;
582 try {
583 result = mAm.switchUser(targetUser.id);
584 // TODO(b/150409110): post user switch OK/FAIL to Hal using
585 // ANDROID_POST_SWITCH
586 if (result) {
587 resultStatus = CarUserManager.USER_SWICTH_STATUS_SUCCESSFUL;
588 } else {
589 resultStatus = CarUserManager.USER_SWICTH_STATUS_ANDROID_FAILURE;
590 }
591 } catch (RemoteException e) {
592 // ignore
593 Log.w(TAG_USER,
594 "error while switching user " + targetUser.toFullString(), e);
595 }
596 break;
597 case SwitchUserStatus.FAILURE:
598 // HAL failed to switch user
599 resultStatus = CarUserManager.USER_SWICTH_STATUS_HAL_FAILURE;
600 if (resp.errorMessage != null) {
601 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
602 resp.errorMessage);
603 }
604 break;
605 }
606 try {
607 receiver.send(resultStatus, resultData);
608 } catch (RemoteException e) {
609 // ignore
610 Log.w(TAG_USER, "error while sending results", e);
611 }
612 }
613 });
614 }
615
616 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700617 * Checks if the User HAL is supported.
618 */
619 public boolean isUserHalSupported() {
620 return mHal.isSupported();
621 }
622
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800623 // TODO(b/144120654): use helper to generate UsersInfo
624 private UsersInfo getUsersInfo() {
625 UserInfo currentUser;
626 try {
627 currentUser = mAm.getCurrentUser();
628 } catch (RemoteException e) {
629 // shouldn't happen
630 throw new IllegalStateException("Could not get current user: ", e);
631 }
632 List<UserInfo> existingUsers = mUserManager.getUsers();
633 int size = existingUsers.size();
634
635 UsersInfo usersInfo = new UsersInfo();
636 usersInfo.numberUsers = size;
637 usersInfo.currentUser.userId = currentUser.id;
638 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
639
640 for (int i = 0; i < size; i++) {
641 UserInfo androidUser = existingUsers.get(i);
642 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
643 new android.hardware.automotive.vehicle.V2_0.UserInfo();
644 halUser.userId = androidUser.id;
645 halUser.flags = UserHalHelper.convertFlags(androidUser);
646 usersInfo.existingUsers.add(halUser);
647 }
648
649 return usersInfo;
650 }
651
Eric Jeong1545f3b2019-09-16 13:56:52 -0700652 /** Returns whether the given user is a system user. */
653 private static boolean isSystemUser(@UserIdInt int userId) {
654 return userId == UserHandle.USER_SYSTEM;
655 }
656
Keun young Park13a7a822019-04-04 15:53:08 -0700657 private void updateDefaultUserRestriction() {
658 // We want to set restrictions on system and guest users only once. These are persisted
659 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
660 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700661 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
662 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700663 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700664 // Only apply the system user restrictions if the system user is headless.
665 if (UserManager.isHeadlessSystemUserMode()) {
666 setSystemUserRestrictions();
667 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700668 Settings.Global.putInt(mContext.getContentResolver(),
669 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700670 }
671
Eric Jeong1545f3b2019-09-16 13:56:52 -0700672 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700673 return !mUserManager.getUserInfo(userId).isEphemeral();
674 }
675
Antonio Kantekc8114752020-03-05 21:37:39 -0800676 /**
677 * Adds a new callback to listen to user activity events.
678 *
679 * @deprecated users should rely on {@link UserLifecycleListener} and invoke
680 * {@link #addUserLifecycleListener} instead
681 */
682 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700683 public void addUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000684 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700685 mUserCallbacks.add(callback);
686 }
687
Antonio Kantekc8114752020-03-05 21:37:39 -0800688 /**
689 * Removes previously added user callback.
690 *
691 * @deprecated users should rely on {@link UserLifecycleListener} and invoke
692 * {@link CarUserService#remove]UserLifecycleListener} instead
693 */
694 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700695 public void removeUserCallback(@NonNull UserCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000696 Objects.requireNonNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700697 mUserCallbacks.remove(callback);
698 }
699
Antonio Kantekc8114752020-03-05 21:37:39 -0800700 /**
701 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
702 */
703 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
704 Objects.requireNonNull(listener, "listener cannot be null");
705 mUserLifecycleListeners.add(listener);
706 }
707
708 /**
709 * Removes previously added {@link UserLifecycleListener}.
710 */
711 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
712 Objects.requireNonNull(listener, "listener cannot be null");
713 mUserLifecycleListeners.remove(listener);
714 }
715
Eric Jeongc91f9452019-08-30 15:04:21 -0700716 /** Adds callback to listen to passenger activity events. */
717 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000718 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700719 mPassengerCallbacks.add(callback);
720 }
721
722 /** Removes previously added callback to listen passenger events. */
723 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000724 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700725 mPassengerCallbacks.remove(callback);
726 }
727
728 /** Sets the implementation of ZoneUserBindingHelper. */
729 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
730 synchronized (mLockHelper) {
731 mZoneUserBindingHelper = helper;
732 }
733 }
734
Keun-young Parkd462a912019-02-11 08:53:42 -0800735 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700736 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
737 *
738 * @param userId User id whoes lock status is changed.
739 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800740 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700741 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Mayank Garg31e73042020-01-23 00:10:38 -0800742 TimingsTraceLog t = new TimingsTraceLog(TAG_USER,
743 Trace.TRACE_TAG_SYSTEM_SERVER);
744 t.traceBegin("onUserLockChanged-" + userId
745 + (unlocked ? "-unlocked" : "-locked"));
Pavel Maltsev17e81832019-04-04 14:38:41 -0700746 for (UserCallback callback : mUserCallbacks) {
Mayank Garg31e73042020-01-23 00:10:38 -0800747 t.traceBegin("onUserLockChanged-"
748 + callback.getClass().getSimpleName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700749 callback.onUserLockChanged(userId, unlocked);
Mayank Garg31e73042020-01-23 00:10:38 -0800750 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700751 }
Mayank Garg31e73042020-01-23 00:10:38 -0800752 t.traceEnd();
753
Keun young Parkf3523cd2019-04-08 10:09:17 -0700754 if (!unlocked) { // nothing else to do when it is locked back.
755 return;
756 }
Mayank Garg31e73042020-01-23 00:10:38 -0800757
758 t.traceBegin("setUserLockStatus-UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800759 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700760 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700761 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700762 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
763 updateDefaultUserRestriction();
764 tasks = new ArrayList<>(mUser0UnlockTasks);
765 mUser0UnlockTasks.clear();
766 mUser0Unlocked = unlocked;
767 }
768 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700769 Integer user = userId;
770 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700771 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700772 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700773 mBackgroundUsersToRestart.remove(user);
774 mBackgroundUsersToRestart.add(0, user);
775 }
776 // -1 for user 0
777 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700778 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700779 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700780 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700781 + ", dropping least recently user from restart list:" + userToDrop);
782 // Drop the least recently used user.
783 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
784 }
785 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800786 }
787 }
788 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700789 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800790 for (Runnable r : tasks) {
791 r.run();
792 }
793 }
Mayank Garg31e73042020-01-23 00:10:38 -0800794 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800795 }
796
797 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700798 * Starts all background users that were active in system.
799 *
Keun young Parkfb656372019-03-12 18:37:55 -0700800 * @return list of background users started successfully.
801 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700802 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700803 public ArrayList<Integer> startAllBackgroundUsers() {
804 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700805 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700806 users = new ArrayList<>(mBackgroundUsersToRestart);
807 mBackgroundUsersRestartedHere.clear();
808 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700809 }
810 ArrayList<Integer> startedUsers = new ArrayList<>();
811 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700812 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700813 continue;
814 }
815 try {
816 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700817 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
818 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700819 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700820 } else if (mAm.unlockUser(user, null, null, null)) {
821 startedUsers.add(user);
822 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700823 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700824 if (mUserManager.isUserRunning(user)) {
825 // add to started list so that it can be stopped later.
826 startedUsers.add(user);
827 }
Keun young Parkfb656372019-03-12 18:37:55 -0700828 }
829 }
830 } catch (RemoteException e) {
831 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700832 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700833 }
834 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700835 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700836 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700837 ArrayList<Integer> usersToRemove = new ArrayList<>();
838 for (Integer user : mBackgroundUsersToRestart) {
839 if (!startedUsers.contains(user)) {
840 usersToRemove.add(user);
841 }
842 }
843 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
844 }
Keun young Parkfb656372019-03-12 18:37:55 -0700845 return startedUsers;
846 }
847
848 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700849 * Stops all background users that were active in system.
850 *
851 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700852 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700853 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700854 if (userId == UserHandle.USER_SYSTEM) {
855 return false;
856 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700857 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700858 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700859 return false;
860 }
861 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700862 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700863 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700864 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700865 Integer user = userId;
866 mBackgroundUsersRestartedHere.remove(user);
867 }
868 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
869 return false;
870 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700871 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700872 return false;
873 }
874 } catch (RemoteException e) {
875 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700876 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700877 }
878 return true;
879 }
880
881 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700882 * Called when new foreground user started to boot.
883 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700884 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700885 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700886 public void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800887 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
888 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800889 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800890
Felipe Lemef45ee502019-12-19 10:00:14 -0800891 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700892 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700893 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700894 if (mLastPassengerId != UserHandle.USER_NULL) {
895 stopPassengerInternal(mLastPassengerId, false);
896 }
897 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
898 setupPassengerUser();
899 startFirstPassenger(userId);
900 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800901
902 // TODO(b/144120654): right now just the app listeners are running in the background so the
903 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
904 // but once we refactor the car service callback into lifecycle listeners, we should use a
905 // proper thread management (like a Threadpool / executor);
906
907 int listenersSize = mLifecycleListeners.size();
908 if (listenersSize == 0) {
909 Log.i(TAG_USER, "Not notifying app listeners");
910 } else {
911 new Thread(() -> {
912 // Must use a different TimingsTraceLog because it's another thread
913 TimingsTraceLog t2 = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
914 Log.i(TAG_USER, "Notifying " + listenersSize + " listeners");
915 for (int i = 0; i < listenersSize; i++) {
916 int uid = mLifecycleListeners.keyAt(i);
917 IResultReceiver listener = mLifecycleListeners.valueAt(i);
918 t2.traceBegin("notify-listener-" + uid);
919 Bundle data = new Bundle();
920 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION,
921 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
922 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
923 // can set BUNDLE_PARAM_PREVIOUS_USER_HANDLE
924 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
925 Log.d(TAG_USER, "Notifying listener for uid " + uid);
926 }
927 try {
928 listener.send(userId, data);
929 } catch (RemoteException e) {
930 Log.e(TAG_USER, "Error calling lifecycle listener", e);
931 } finally {
932 t2.traceEnd();
933 }
934 }
935
936 }, "SwitchUser-" + userId + "-Listeners").start();
937 }
938
Antonio Kantekc8114752020-03-05 21:37:39 -0800939 notifyUserLifecycleListeners(t, userId);
940 notifyCallbacks(t, userId);
941 }
942
943 private void notifyUserLifecycleListeners(TimingsTraceLog t,
944 @UserIdInt int userId) {
945 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
946 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size()
947 + " user lifecycle listeners");
948 }
949 // TODO(b/145689885): passing null for `from` parameter until it gets properly replaced
950 // the expected Binder call.
951 UserLifecycleEvent event = new UserLifecycleEvent(
952 /* eventType= */ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
953 /* from= */ null, /* to= */ new UserHandle(userId));
954 for (UserLifecycleListener listener : mUserLifecycleListeners) {
955 t.traceBegin("onEvent-" + listener.getClass().getName());
956 try {
957 listener.onEvent(event);
958 } catch (RuntimeException e) {
959 Log.e(TAG_USER,
960 "Exception raised when invoking onEvent for " + listener, e);
961 }
962 t.traceEnd();
963 }
964 }
965
966 private void notifyCallbacks(TimingsTraceLog t, @UserIdInt int userId) {
967 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
968 Log.d(TAG_USER, "Notifying " + mUserCallbacks.size() + " callbacks");
969 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700970 for (UserCallback callback : mUserCallbacks) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800971 t.traceBegin("onSwitchUser-" + callback.getClass().getName());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700972 callback.onSwitchUser(userId);
Mayank Garg31e73042020-01-23 00:10:38 -0800973 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700974 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800975 t.traceEnd(); // onSwitchUser
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 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001248}