blob: ec10818cd4d0d061c673c5d0e97e626f20b7ae1e [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
Felipe Leme58412202020-01-09 13:45:33 -0800123 private final UserHalService mHal;
124
Felipe Leme5528ff72020-02-10 19:05:14 -0800125 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800126 * List of listeners to be notified on new user activities events.
127 */
128 private final CopyOnWriteArrayList<UserLifecycleListener>
129 mUserLifecycleListeners = new CopyOnWriteArrayList<>();
130
131 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800132 * List of lifecycle listeners by uid.
133 */
134 @GuardedBy("mLockUser")
135 private final SparseArray<IResultReceiver> mLifecycleListeners = new SparseArray<>();
136
Felipe Lemee3cab982020-03-12 11:39:29 -0700137 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
138
Eric Jeongc91f9452019-08-30 15:04:21 -0700139 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
140 new CopyOnWriteArrayList<>();
141
142 /** Interface for callbaks related to passenger activities. */
143 public interface PassengerCallback {
144 /** Called when passenger is started at a certain zone. */
145 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
146 /** Called when passenger is stopped. */
147 void onPassengerStopped(@UserIdInt int passengerId);
148 }
149
150 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
151 public interface ZoneUserBindingHelper {
152 /** Gets occupant zones corresponding to the occupant type. */
153 @NonNull
154 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
155 /** Assigns the user to the occupant zone. */
156 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
157 /** Makes the occupant zone unoccupied. */
158 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
159 /** Returns whether there is a passenger display. */
160 boolean isPassengerDisplayAvailable();
161 }
162
163 private final Object mLockHelper = new Object();
164 @GuardedBy("mLockHelper")
165 private ZoneUserBindingHelper mZoneUserBindingHelper;
166
Felipe Leme58412202020-01-09 13:45:33 -0800167 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
168 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700169 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700170 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
171 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700172 }
173 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800174 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700175 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700176 mAm = am;
177 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700178 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700179 mLastPassengerId = UserHandle.USER_NULL;
180 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700181 }
182
183 @Override
184 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700185 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
186 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700187 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700188 }
189
190 @Override
191 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700192 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
193 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700194 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700195 }
196
197 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700198 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700199 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700200 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800201 String indent = " ";
Eric Jeongc91f9452019-08-30 15:04:21 -0700202 synchronized (mLockUser) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800203 int numberListeners = mLifecycleListeners.size();
204 if (numberListeners == 0) {
205 writer.println("No lifecycle listeners");
206 } else {
207 writer.printf("%d lifecycle listeners\n", numberListeners);
208 for (int i = 0; i < numberListeners; i++) {
209 int uid = mLifecycleListeners.keyAt(i);
210 IResultReceiver listener = mLifecycleListeners.valueAt(i);
211 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
212 }
213 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700214 writer.println("User0Unlocked: " + mUser0Unlocked);
215 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
216 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
217 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
felipeal2d0483c2019-11-02 14:07:22 -0700218 List<UserInfo> allDrivers = getAllDrivers();
219 int driversSize = allDrivers.size();
220 writer.println("NumberOfDrivers: " + driversSize);
felipeal2d0483c2019-11-02 14:07:22 -0700221 for (int i = 0; i < driversSize; i++) {
222 int driverId = allDrivers.get(i).id;
Felipe Leme5528ff72020-02-10 19:05:14 -0800223 writer.print(indent + "#" + i + ": id=" + driverId);
felipeal2d0483c2019-11-02 14:07:22 -0700224 List<UserInfo> passengers = getPassengers(driverId);
225 int passengersSize = passengers.size();
226 writer.print(" NumberPassengers: " + passengersSize);
227 if (passengersSize > 0) {
228 writer.print(" [");
229 for (int j = 0; j < passengersSize; j++) {
230 writer.print(passengers.get(j).id);
231 if (j < passengersSize - 1) {
232 writer.print(" ");
233 }
234 }
235 writer.print("]");
236 }
237 writer.println();
238 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700239 writer.println("EnablePassengerSupport: " + mEnablePassengerSupport);
Felipe Lemee3cab982020-03-12 11:39:29 -0700240 writer.println("User HAL timeout: " + mHalTimeoutMs + "ms");
Felipe Leme315a53b2020-03-12 10:51:04 -0700241 writer.println("Relevant overlayable properties");
242 Resources res = mContext.getResources();
243 writer.printf("%sowner_name=%s\n", indent,
244 res.getString(com.android.internal.R.string.owner_name));
245 writer.printf("%sdefault_guest_name=%s\n", indent,
246 res.getString(R.string.default_guest_name));
Keun-young Parkd462a912019-02-11 08:53:42 -0800247 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 }
249
250 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800251 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
252 *
253 * @param name The name of the driver to be created.
254 * @param admin Whether the created driver will be an admin.
255 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
256 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700257 */
258 @Override
259 @Nullable
260 public UserInfo createDriver(@NonNull String name, boolean admin) {
261 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000262 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700263 if (admin) {
264 return createNewAdminUser(name);
265 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700266 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700267 }
268
269 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800270 * Creates a passenger who is a profile of the given driver.
271 *
272 * @param name The name of the passenger to be created.
273 * @param driverId User id of the driver under whom a passenger is created.
274 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
275 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700276 */
277 @Override
278 @Nullable
279 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
280 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000281 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700282 UserInfo driver = mUserManager.getUserInfo(driverId);
283 if (driver == null) {
284 Log.w(TAG_USER, "the driver is invalid");
285 return null;
286 }
287 if (driver.isGuest()) {
288 Log.w(TAG_USER, "a guest driver cannot create a passenger");
289 return null;
290 }
Bookatz42fb1a62019-10-30 11:45:01 -0700291 UserInfo user = mUserManager.createProfileForUser(name,
292 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700293 if (user == null) {
294 // Couldn't create user, most likely because there are too many.
295 Log.w(TAG_USER, "can't create a profile for user" + driverId);
296 return null;
297 }
298 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700299 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700300 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700301 return user;
302 }
303
304 /**
305 * @see CarUserManager.switchDriver
306 */
307 @Override
308 public boolean switchDriver(@UserIdInt int driverId) {
309 checkManageUsersPermission("switchDriver");
310 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
311 // System user doesn't associate with real person, can not be switched to.
312 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
313 return false;
314 }
315 int userSwitchable = mUserManager.getUserSwitchability();
316 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
317 Log.w(TAG_USER, "current process is not allowed to switch user");
318 return false;
319 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700320 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700321 // The current user is already the given user.
322 return true;
323 }
324 try {
325 return mAm.switchUser(driverId);
326 } catch (RemoteException e) {
327 // ignore
328 Log.w(TAG_USER, "error while switching user", e);
329 }
330 return false;
331 }
332
333 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800334 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
335 *
336 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700337 */
338 @Override
339 @NonNull
340 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700341 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700342 return getUsers((user) -> {
343 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
344 && !user.isEphemeral();
345 });
346 }
347
348 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800349 * Returns all passengers under the given driver.
350 *
351 * @param driverId User id of a driver.
352 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700353 */
354 @Override
355 @NonNull
356 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700357 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700358 return getUsers((user) -> {
359 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
360 && user.profileGroupId == driverId;
361 });
362 }
363
364 /**
365 * @see CarUserManager.startPassenger
366 */
367 @Override
368 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
369 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700370 synchronized (mLockUser) {
371 try {
372 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
373 Log.w(TAG_USER, "could not start passenger");
374 return false;
375 }
376 } catch (RemoteException e) {
377 // ignore
378 Log.w(TAG_USER, "error while starting passenger", e);
379 return false;
380 }
381 if (!assignUserToOccupantZone(passengerId, zoneId)) {
382 Log.w(TAG_USER, "could not assign passenger to zone");
383 return false;
384 }
385 mLastPassengerId = passengerId;
386 }
387 for (PassengerCallback callback : mPassengerCallbacks) {
388 callback.onPassengerStarted(passengerId, zoneId);
389 }
390 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700391 }
392
393 /**
394 * @see CarUserManager.stopPassenger
395 */
396 @Override
397 public boolean stopPassenger(@UserIdInt int passengerId) {
398 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700399 return stopPassengerInternal(passengerId, true);
400 }
401
402 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
403 synchronized (mLockUser) {
404 UserInfo passenger = mUserManager.getUserInfo(passengerId);
405 if (passenger == null) {
406 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
407 return false;
408 }
409 if (mLastPassengerId != passengerId) {
410 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
411 return true;
412 }
413 if (checkCurrentDriver) {
414 int currentUser = ActivityManager.getCurrentUser();
415 if (passenger.profileGroupId != currentUser) {
416 Log.w(TAG_USER, "passenger " + passengerId
417 + " is not a profile of the current user");
418 return false;
419 }
420 }
421 // Passenger is a profile, so cannot be stopped through activity manager.
422 // Instead, activities started by the passenger are stopped and the passenger is
423 // unassigned from the zone.
424 stopAllTasks(passengerId);
425 if (!unassignUserFromOccupantZone(passengerId)) {
426 Log.w(TAG_USER, "could not unassign user from occupant zone");
427 return false;
428 }
429 mLastPassengerId = UserHandle.USER_NULL;
430 }
431 for (PassengerCallback callback : mPassengerCallbacks) {
432 callback.onPassengerStopped(passengerId);
433 }
434 return true;
435 }
436
437 private void stopAllTasks(@UserIdInt int userId) {
438 try {
439 for (StackInfo info : mAm.getAllStackInfos()) {
440 for (int i = 0; i < info.taskIds.length; i++) {
441 if (info.taskUserIds[i] == userId) {
442 int taskId = info.taskIds[i];
443 if (!mAm.removeTask(taskId)) {
444 Log.w(TAG_USER, "could not remove task " + taskId);
445 }
446 }
447 }
448 }
449 } catch (RemoteException e) {
450 Log.e(TAG_USER, "could not get stack info", e);
451 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700452 }
453
Felipe Leme5528ff72020-02-10 19:05:14 -0800454 @Override
455 public void setLifecycleListenerForUid(IResultReceiver listener) {
456 int uid = Binder.getCallingUid();
457 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
458
459 try {
460 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
461 } catch (RemoteException e) {
462 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
463 }
464 synchronized (mLockUser) {
465 mLifecycleListeners.append(uid, listener);
466 }
467 }
468
469 private void onListenerDeath(int uid) {
470 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
471 synchronized (mLockUser) {
472 removeLifecycleListenerLocked(uid);
473 }
474 }
475
476 @Override
477 public void resetLifecycleListenerForUid() {
478 int uid = Binder.getCallingUid();
479 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
480
481 synchronized (mLockUser) {
482 removeLifecycleListenerLocked(uid);
483 }
484 }
485
486 private void removeLifecycleListenerLocked(int uid) {
487 mLifecycleListeners.remove(uid);
488 }
489
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800490 @Override
491 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800492 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800493 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700494 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800495 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800496 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
497 try {
498 Bundle resultData = null;
499 if (resp != null) {
500 switch (resp.action) {
501 case InitialUserInfoResponseAction.SWITCH:
502 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800503 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800504 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
505 break;
506 case InitialUserInfoResponseAction.CREATE:
507 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800508 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800509 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
510 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
511 break;
512 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800513 resultData = new Bundle();
514 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800515 break;
516 default:
517 // That's ok, it will be the same as DEFAULT...
518 Log.w(TAG_USER, "invalid response action on " + resp);
519 }
520 }
521 receiver.send(status, resultData);
522 } catch (RemoteException e) {
523 Log.w(TAG_USER, "Could not send result back to receiver", e);
524 }
525 });
526 }
527
Felipe Lemee3cab982020-03-12 11:39:29 -0700528 /**
529 * Calls the User HAL to get the initial user info.
530 *
531 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
532 * @param callback callback to receive the results.
533 */
534 public void getInitialUserInfo(int requestType,
535 HalCallback<InitialUserInfoResponse> callback) {
536 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700537 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700538 UsersInfo usersInfo = getUsersInfo();
539 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
540 }
541
542 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700543 * Calls the User HAL to switch user.
544 *
545 * @param targetUser - target user info
546 * @param timeoutMs - timeout for HAL to wait
547 * @param receiver - receiver for the results
548 */
549 public void switchUser(@NonNull UserInfo targetUser, int timeoutMs,
550 @NonNull IResultReceiver receiver) {
551 checkManageUsersPermission("switchUser");
552 UsersInfo usersInfo = getUsersInfo();
553 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
554 new android.hardware.automotive.vehicle.V2_0.UserInfo();
555 halUser.userId = targetUser.id;
556 halUser.flags = UserHalHelper.convertFlags(targetUser);
557 mHal.switchUser(halUser, timeoutMs, usersInfo, (status, resp) -> {
558 Bundle resultData = null;
559 resultData = new Bundle();
560 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
561 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
562 int resultStatus = CarUserManager.USER_SWICTH_STATUS_UNKNOWN;
563 if (resp != null) {
564 switch (resp.status) {
565 case SwitchUserStatus.SUCCESS:
566 boolean result;
567 try {
568 result = mAm.switchUser(targetUser.id);
569 // TODO(b/150409110): post user switch OK/FAIL to Hal using
570 // ANDROID_POST_SWITCH
571 if (result) {
572 resultStatus = CarUserManager.USER_SWICTH_STATUS_SUCCESSFUL;
573 } else {
574 resultStatus = CarUserManager.USER_SWICTH_STATUS_ANDROID_FAILURE;
575 }
576 } catch (RemoteException e) {
577 // ignore
578 Log.w(TAG_USER,
579 "error while switching user " + targetUser.toFullString(), e);
580 }
581 break;
582 case SwitchUserStatus.FAILURE:
583 // HAL failed to switch user
584 resultStatus = CarUserManager.USER_SWICTH_STATUS_HAL_FAILURE;
585 if (resp.errorMessage != null) {
586 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
587 resp.errorMessage);
588 }
589 break;
590 }
591 try {
592 receiver.send(resultStatus, resultData);
593 } catch (RemoteException e) {
594 // ignore
595 Log.w(TAG_USER, "error while sending results", e);
596 }
597 }
598 });
599 }
600
601 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700602 * Checks if the User HAL is supported.
603 */
604 public boolean isUserHalSupported() {
605 return mHal.isSupported();
606 }
607
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800608 // TODO(b/144120654): use helper to generate UsersInfo
609 private UsersInfo getUsersInfo() {
610 UserInfo currentUser;
611 try {
612 currentUser = mAm.getCurrentUser();
613 } catch (RemoteException e) {
614 // shouldn't happen
615 throw new IllegalStateException("Could not get current user: ", e);
616 }
617 List<UserInfo> existingUsers = mUserManager.getUsers();
618 int size = existingUsers.size();
619
620 UsersInfo usersInfo = new UsersInfo();
621 usersInfo.numberUsers = size;
622 usersInfo.currentUser.userId = currentUser.id;
623 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
624
625 for (int i = 0; i < size; i++) {
626 UserInfo androidUser = existingUsers.get(i);
627 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
628 new android.hardware.automotive.vehicle.V2_0.UserInfo();
629 halUser.userId = androidUser.id;
630 halUser.flags = UserHalHelper.convertFlags(androidUser);
631 usersInfo.existingUsers.add(halUser);
632 }
633
634 return usersInfo;
635 }
636
Eric Jeong1545f3b2019-09-16 13:56:52 -0700637 /** Returns whether the given user is a system user. */
638 private static boolean isSystemUser(@UserIdInt int userId) {
639 return userId == UserHandle.USER_SYSTEM;
640 }
641
Keun young Park13a7a822019-04-04 15:53:08 -0700642 private void updateDefaultUserRestriction() {
643 // We want to set restrictions on system and guest users only once. These are persisted
644 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
645 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700646 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
647 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700648 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700649 // Only apply the system user restrictions if the system user is headless.
650 if (UserManager.isHeadlessSystemUserMode()) {
651 setSystemUserRestrictions();
652 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700653 Settings.Global.putInt(mContext.getContentResolver(),
654 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700655 }
656
Eric Jeong1545f3b2019-09-16 13:56:52 -0700657 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700658 return !mUserManager.getUserInfo(userId).isEphemeral();
659 }
660
Antonio Kantekc8114752020-03-05 21:37:39 -0800661 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800662 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
663 */
664 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
665 Objects.requireNonNull(listener, "listener cannot be null");
666 mUserLifecycleListeners.add(listener);
667 }
668
669 /**
670 * Removes previously added {@link UserLifecycleListener}.
671 */
672 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
673 Objects.requireNonNull(listener, "listener cannot be null");
674 mUserLifecycleListeners.remove(listener);
675 }
676
Eric Jeongc91f9452019-08-30 15:04:21 -0700677 /** Adds callback to listen to passenger activity events. */
678 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000679 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700680 mPassengerCallbacks.add(callback);
681 }
682
683 /** Removes previously added callback to listen passenger events. */
684 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000685 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700686 mPassengerCallbacks.remove(callback);
687 }
688
689 /** Sets the implementation of ZoneUserBindingHelper. */
690 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
691 synchronized (mLockHelper) {
692 mZoneUserBindingHelper = helper;
693 }
694 }
695
Keun-young Parkd462a912019-02-11 08:53:42 -0800696 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700697 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
698 *
699 * @param userId User id whoes lock status is changed.
700 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Antonio Kantekf7007532020-03-17 10:37:58 -0700701 *
702 * @deprecated TODO(b/151895715): method to be folded into onUserLifecycleEvent
Keun-young Parkd462a912019-02-11 08:53:42 -0800703 */
Antonio Kantekf7007532020-03-17 10:37:58 -0700704 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700705 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Mayank Garg31e73042020-01-23 00:10:38 -0800706 TimingsTraceLog t = new TimingsTraceLog(TAG_USER,
707 Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal042a73c2020-03-30 09:24:05 -0700708 notifyUserLifecycleListeners(t,
709 new UserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, userId));
Mayank Garg31e73042020-01-23 00:10:38 -0800710
Keun young Parkf3523cd2019-04-08 10:09:17 -0700711 if (!unlocked) { // nothing else to do when it is locked back.
712 return;
713 }
Mayank Garg31e73042020-01-23 00:10:38 -0800714
715 t.traceBegin("setUserLockStatus-UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800716 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700717 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700718 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700719 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
720 updateDefaultUserRestriction();
721 tasks = new ArrayList<>(mUser0UnlockTasks);
722 mUser0UnlockTasks.clear();
723 mUser0Unlocked = unlocked;
724 }
725 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700726 Integer user = userId;
727 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700728 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700729 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700730 mBackgroundUsersToRestart.remove(user);
731 mBackgroundUsersToRestart.add(0, user);
732 }
733 // -1 for user 0
734 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700735 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700736 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700737 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700738 + ", dropping least recently user from restart list:" + userToDrop);
739 // Drop the least recently used user.
740 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
741 }
742 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800743 }
744 }
745 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700746 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800747 for (Runnable r : tasks) {
748 r.run();
749 }
750 }
Mayank Garg31e73042020-01-23 00:10:38 -0800751 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800752 }
753
754 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700755 * Starts all background users that were active in system.
756 *
Keun young Parkfb656372019-03-12 18:37:55 -0700757 * @return list of background users started successfully.
758 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700759 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700760 public ArrayList<Integer> startAllBackgroundUsers() {
761 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700762 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700763 users = new ArrayList<>(mBackgroundUsersToRestart);
764 mBackgroundUsersRestartedHere.clear();
765 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700766 }
767 ArrayList<Integer> startedUsers = new ArrayList<>();
768 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700769 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700770 continue;
771 }
772 try {
773 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700774 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
775 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700776 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700777 } else if (mAm.unlockUser(user, null, null, null)) {
778 startedUsers.add(user);
779 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700780 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700781 if (mUserManager.isUserRunning(user)) {
782 // add to started list so that it can be stopped later.
783 startedUsers.add(user);
784 }
Keun young Parkfb656372019-03-12 18:37:55 -0700785 }
786 }
787 } catch (RemoteException e) {
788 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700789 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700790 }
791 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700792 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700793 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700794 ArrayList<Integer> usersToRemove = new ArrayList<>();
795 for (Integer user : mBackgroundUsersToRestart) {
796 if (!startedUsers.contains(user)) {
797 usersToRemove.add(user);
798 }
799 }
800 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
801 }
Keun young Parkfb656372019-03-12 18:37:55 -0700802 return startedUsers;
803 }
804
805 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700806 * Stops all background users that were active in system.
807 *
808 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700809 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700810 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700811 if (userId == UserHandle.USER_SYSTEM) {
812 return false;
813 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700814 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700815 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700816 return false;
817 }
818 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700819 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700820 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700821 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700822 Integer user = userId;
823 mBackgroundUsersRestartedHere.remove(user);
824 }
825 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
826 return false;
827 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700828 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700829 return false;
830 }
831 } catch (RemoteException e) {
832 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700833 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700834 }
835 return true;
836 }
837
838 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700839 * Called when new foreground user started to boot.
840 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700841 * @param userId User id of new user.
Antonio Kantekf7007532020-03-17 10:37:58 -0700842 * @deprecated TODO(b/151895715): method to be folded into onUserLifecycleEvent
Pavel Maltsev17e81832019-04-04 14:38:41 -0700843 */
Antonio Kantekf7007532020-03-17 10:37:58 -0700844 @Deprecated
Eric Jeong1545f3b2019-09-16 13:56:52 -0700845 public void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800846 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
847 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800848 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800849
Felipe Lemef45ee502019-12-19 10:00:14 -0800850 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700851 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700852 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700853 if (mLastPassengerId != UserHandle.USER_NULL) {
854 stopPassengerInternal(mLastPassengerId, false);
855 }
856 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
857 setupPassengerUser();
858 startFirstPassenger(userId);
859 }
Felipe Leme5528ff72020-02-10 19:05:14 -0800860
861 // TODO(b/144120654): right now just the app listeners are running in the background so the
862 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
863 // but once we refactor the car service callback into lifecycle listeners, we should use a
864 // proper thread management (like a Threadpool / executor);
865
866 int listenersSize = mLifecycleListeners.size();
867 if (listenersSize == 0) {
868 Log.i(TAG_USER, "Not notifying app listeners");
869 } else {
870 new Thread(() -> {
871 // Must use a different TimingsTraceLog because it's another thread
872 TimingsTraceLog t2 = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
873 Log.i(TAG_USER, "Notifying " + listenersSize + " listeners");
874 for (int i = 0; i < listenersSize; i++) {
875 int uid = mLifecycleListeners.keyAt(i);
876 IResultReceiver listener = mLifecycleListeners.valueAt(i);
877 t2.traceBegin("notify-listener-" + uid);
878 Bundle data = new Bundle();
879 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION,
880 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
881 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
felipeal042a73c2020-03-30 09:24:05 -0700882 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
Felipe Leme5528ff72020-02-10 19:05:14 -0800883 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
884 Log.d(TAG_USER, "Notifying listener for uid " + uid);
885 }
886 try {
887 listener.send(userId, data);
888 } catch (RemoteException e) {
889 Log.e(TAG_USER, "Error calling lifecycle listener", e);
890 } finally {
891 t2.traceEnd();
892 }
893 }
894
895 }, "SwitchUser-" + userId + "-Listeners").start();
896 }
897
felipeal042a73c2020-03-30 09:24:05 -0700898 // TODO(b/145689885): not passing `from` parameter until it gets properly replaced
Antonio Kantekc8114752020-03-05 21:37:39 -0800899 // the expected Binder call.
felipeal042a73c2020-03-30 09:24:05 -0700900 notifyUserLifecycleListeners(t,
901 new UserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, userId));
Antonio Kantekf7007532020-03-17 10:37:58 -0700902 }
903
904 private void notifyUserLifecycleListeners(TimingsTraceLog t, UserLifecycleEvent event) {
905 t.traceBegin("notifyInternalUserLifecycleListeners");
Antonio Kantekc8114752020-03-05 21:37:39 -0800906 for (UserLifecycleListener listener : mUserLifecycleListeners) {
Antonio Kantekf7007532020-03-17 10:37:58 -0700907 t.traceBegin("onEvent-" + listener.getClass().getSimpleName());
Antonio Kantekc8114752020-03-05 21:37:39 -0800908 try {
909 listener.onEvent(event);
910 } catch (RuntimeException e) {
911 Log.e(TAG_USER,
912 "Exception raised when invoking onEvent for " + listener, e);
913 }
914 t.traceEnd();
915 }
Antonio Kantekf7007532020-03-17 10:37:58 -0700916 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -0700917 }
918
919 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700920 * 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 -0800921 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700922 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800923 * @param r Runnable to run.
924 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700925 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000926 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800927 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700928 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800929 if (mUser0Unlocked) {
930 runNow = true;
931 } else {
932 mUser0UnlockTasks.add(r);
933 }
934 }
935 if (runNow) {
936 r.run();
937 }
938 }
939
Keun young Parkf3523cd2019-04-08 10:09:17 -0700940 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700941 @NonNull
942 ArrayList<Integer> getBackgroundUsersToRestart() {
943 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700944 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700945 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
946 }
947 return backgroundUsersToRestart;
948 }
949
Ying Zheng1ab32b62018-06-26 12:47:26 -0700950 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700951 // Disable Location service for system user.
952 LocationManager locationManager =
953 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800954 locationManager.setLocationEnabledForUser(
955 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700956 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700957
958 /**
959 * Creates a new user on the system, the created user would be granted admin role.
960 *
961 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700962 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700963 */
964 @Nullable
965 private UserInfo createNewAdminUser(String name) {
966 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
967 // Only admins or system user can create other privileged users.
968 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
969 return null;
970 }
971
972 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
973 if (user == null) {
974 // Couldn't create user, most likely because there are too many.
975 Log.w(TAG_USER, "can't create admin user.");
976 return null;
977 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700978 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700979
980 return user;
981 }
982
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700983 /**
984 * Assigns a default icon to a user according to the user's id.
985 *
986 * @param userInfo User whose avatar is set to default icon.
987 * @return Bitmap of the user icon.
988 */
989 private Bitmap assignDefaultIcon(UserInfo userInfo) {
990 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
991 Bitmap bitmap = UserIcons.convertToBitmap(
992 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
993 mUserManager.setUserIcon(userInfo.id, bitmap);
994 return bitmap;
995 }
996
Eric Jeong1545f3b2019-09-16 13:56:52 -0700997 private interface UserFilter {
998 boolean isEligibleUser(UserInfo user);
999 }
1000
1001 /** Returns all users who are matched by the given filter. */
1002 private List<UserInfo> getUsers(UserFilter filter) {
1003 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1004
1005 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1006 UserInfo user = iterator.next();
1007 if (!filter.isEligibleUser(user)) {
1008 iterator.remove();
1009 }
1010 }
1011 return users;
1012 }
1013
1014 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001015 * Enforces that apps which have the
1016 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1017 * can make certain calls to the CarUserManager.
1018 *
1019 * @param message used as message if SecurityException is thrown.
1020 * @throws SecurityException if the caller is not system or root.
1021 */
1022 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001023 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1024 }
1025
1026 private static void checkManageUsersOrDumpPermission(String message) {
1027 checkAtLeastOnePermission(message,
1028 android.Manifest.permission.MANAGE_USERS,
1029 android.Manifest.permission.DUMP);
1030 }
1031
Felipe Leme5528ff72020-02-10 19:05:14 -08001032 private void checkInteractAcrossUsersPermission(String message) {
1033 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1034 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1035 }
1036
felipeal2d0483c2019-11-02 14:07:22 -07001037 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001038 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001039 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1040 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001041 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001042 }
1043 }
1044
felipeal2d0483c2019-11-02 14:07:22 -07001045 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1046 for (String permission : permissions) {
1047 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1048 /* exported = */ true)
1049 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1050 return true;
1051 }
1052 }
1053 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001054 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001055
1056 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1057 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1058 // Count all users that are managed profiles of the given user.
1059 int managedProfilesCount = 0;
1060 for (UserInfo user : users) {
1061 if (user.isManagedProfile() && user.profileGroupId == userId) {
1062 managedProfilesCount++;
1063 }
1064 }
1065 return managedProfilesCount;
1066 }
1067
1068 /**
1069 * Starts the first passenger of the given driver and assigns the passenger to the front
1070 * passenger zone.
1071 *
1072 * @param driverId User id of the driver.
1073 * @return whether it succeeds.
1074 */
1075 private boolean startFirstPassenger(@UserIdInt int driverId) {
1076 int zoneId = getAvailablePassengerZone();
1077 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1078 Log.w(TAG_USER, "passenger occupant zone is not found");
1079 return false;
1080 }
1081 List<UserInfo> passengers = getPassengers(driverId);
1082 if (passengers.size() < 1) {
1083 Log.w(TAG_USER, "passenger is not found");
1084 return false;
1085 }
1086 // Only one passenger is supported. If there are two or more passengers, the first passenger
1087 // is chosen.
1088 int passengerId = passengers.get(0).id;
1089 if (!startPassenger(passengerId, zoneId)) {
1090 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1091 return false;
1092 }
1093 return true;
1094 }
1095
1096 private int getAvailablePassengerZone() {
1097 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1098 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1099 for (int occupantType : occupantTypes) {
1100 int zoneId = getZoneId(occupantType);
1101 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1102 return zoneId;
1103 }
1104 }
1105 return OccupantZoneInfo.INVALID_ZONE_ID;
1106 }
1107
1108 /**
1109 * Creates a new passenger user when there is no passenger user.
1110 */
1111 private void setupPassengerUser() {
1112 int currentUser = ActivityManager.getCurrentUser();
1113 int profileCount = getNumberOfManagedProfiles(currentUser);
1114 if (profileCount > 0) {
1115 Log.w(TAG_USER, "max profile of user" + currentUser
1116 + " is exceeded: current profile count is " + profileCount);
1117 return;
1118 }
1119 // TODO(b/140311342): Use resource string for the default passenger name.
1120 UserInfo passenger = createPassenger("Passenger", currentUser);
1121 if (passenger == null) {
1122 // Couldn't create user, most likely because there are too many.
1123 Log.w(TAG_USER, "cannot create a passenger user");
1124 return;
1125 }
1126 }
1127
1128 @NonNull
1129 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1130 ZoneUserBindingHelper helper = null;
1131 synchronized (mLockHelper) {
1132 if (mZoneUserBindingHelper == null) {
1133 Log.w(TAG_USER, "implementation is not delegated");
1134 return new ArrayList<OccupantZoneInfo>();
1135 }
1136 helper = mZoneUserBindingHelper;
1137 }
1138 return helper.getOccupantZones(occupantType);
1139 }
1140
1141 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1142 ZoneUserBindingHelper helper = null;
1143 synchronized (mLockHelper) {
1144 if (mZoneUserBindingHelper == null) {
1145 Log.w(TAG_USER, "implementation is not delegated");
1146 return false;
1147 }
1148 helper = mZoneUserBindingHelper;
1149 }
1150 return helper.assignUserToOccupantZone(userId, zoneId);
1151 }
1152
1153 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
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.unassignUserFromOccupantZone(userId);
1163 }
1164
1165 private boolean isPassengerDisplayAvailable() {
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.isPassengerDisplayAvailable();
1175 }
1176
1177 /**
1178 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1179 * zone is returned.
1180 *
1181 * @param occupantType The type of an occupant.
1182 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1183 * if not found.
1184 */
1185 private int getZoneId(@OccupantTypeEnum int occupantType) {
1186 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1187 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1188 }
Antonio Kantekf7007532020-03-17 10:37:58 -07001189}