blob: cfd336433c513b2934029f48b840d46968515daf [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
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700696 private void unlockUser(@UserIdInt int userId) {
697 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
698 notifyUserLifecycleListeners(
felipeal042a73c2020-03-30 09:24:05 -0700699 new UserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, userId));
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700700 t.traceBegin("UnlockTasks-" + userId);
Keun-young Parkd462a912019-02-11 08:53:42 -0800701 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700702 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700703 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700704 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
705 updateDefaultUserRestriction();
706 tasks = new ArrayList<>(mUser0UnlockTasks);
707 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700708 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700709 }
710 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700711 Integer user = userId;
712 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700713 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700714 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700715 mBackgroundUsersToRestart.remove(user);
716 mBackgroundUsersToRestart.add(0, user);
717 }
718 // -1 for user 0
719 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700720 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700721 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700722 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700723 + ", dropping least recently user from restart list:" + userToDrop);
724 // Drop the least recently used user.
725 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
726 }
727 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800728 }
729 }
730 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700731 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800732 for (Runnable r : tasks) {
733 r.run();
734 }
735 }
Mayank Garg31e73042020-01-23 00:10:38 -0800736 t.traceEnd();
Keun-young Parkd462a912019-02-11 08:53:42 -0800737 }
738
739 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700740 * Starts all background users that were active in system.
741 *
Keun young Parkfb656372019-03-12 18:37:55 -0700742 * @return list of background users started successfully.
743 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700744 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700745 public ArrayList<Integer> startAllBackgroundUsers() {
746 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700747 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700748 users = new ArrayList<>(mBackgroundUsersToRestart);
749 mBackgroundUsersRestartedHere.clear();
750 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700751 }
752 ArrayList<Integer> startedUsers = new ArrayList<>();
753 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700754 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700755 continue;
756 }
757 try {
758 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700759 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
760 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700761 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700762 } else if (mAm.unlockUser(user, null, null, null)) {
763 startedUsers.add(user);
764 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700765 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700766 if (mUserManager.isUserRunning(user)) {
767 // add to started list so that it can be stopped later.
768 startedUsers.add(user);
769 }
Keun young Parkfb656372019-03-12 18:37:55 -0700770 }
771 }
772 } catch (RemoteException e) {
773 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700774 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700775 }
776 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700777 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700778 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700779 ArrayList<Integer> usersToRemove = new ArrayList<>();
780 for (Integer user : mBackgroundUsersToRestart) {
781 if (!startedUsers.contains(user)) {
782 usersToRemove.add(user);
783 }
784 }
785 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
786 }
Keun young Parkfb656372019-03-12 18:37:55 -0700787 return startedUsers;
788 }
789
790 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700791 * Stops all background users that were active in system.
792 *
793 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700794 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700795 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700796 if (userId == UserHandle.USER_SYSTEM) {
797 return false;
798 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700799 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700800 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700801 return false;
802 }
803 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700804 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700805 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700806 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700807 Integer user = userId;
808 mBackgroundUsersRestartedHere.remove(user);
809 }
810 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
811 return false;
812 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700813 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700814 return false;
815 }
816 } catch (RemoteException e) {
817 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700818 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700819 }
820 return true;
821 }
822
823 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700824 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700825 */
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700826 public void onUserLifecycleEvent(UserLifecycleEvent event) {
827 int userId = event.getUserId();
828 if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
829 onSwitchUser(userId);
830 } else if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) {
831 unlockUser(userId);
832 }
833
834 // TODO(b/144120654): right now just the app listeners are running in the background so the
835 // CTS tests pass (as otherwise they might fail if a car service callback takes too long),
836 // but once we refactor the car service callback into lifecycle listeners, we should use a
837 // proper thread management (like a Threadpool / executor);
838
839 // Notify all user listeners
840 notifyUserLifecycleListeners(event);
841
842 // Notify all app listeners
843 notifyAppLifecycleListeners(event);
844 }
845
846 private void notifyAppLifecycleListeners(UserLifecycleEvent event) {
847 int listenersSize = mLifecycleListeners.size();
848 if (listenersSize == 0) {
849 Log.i(TAG_USER, "No app listener to be notified");
850 return;
851 }
852 new Thread(() -> {
853 // Must use a different TimingsTraceLog because it's another thread
854 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
855 Log.i(TAG_USER, "Notifying " + listenersSize + " app listeners");
856 int userId = event.getUserId();
857 for (int i = 0; i < listenersSize; i++) {
858 int uid = mLifecycleListeners.keyAt(i);
859 IResultReceiver listener = mLifecycleListeners.valueAt(i);
860 t.traceBegin("notify-" + event.getEventType() + "-app-listener-" + uid);
861 Bundle data = new Bundle();
862 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
863 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
864 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
865 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
866 Log.d(TAG_USER, "Notifying listener for uid " + uid);
867 }
868 try {
869 listener.send(userId, data);
870 } catch (RemoteException e) {
871 Log.e(TAG_USER, "Error calling lifecycle listener", e);
872 } finally {
873 t.traceEnd();
874 }
875 }
876 }, "SwitchUser-" + event.getUserId() + "-Listeners").start();
877 }
878
879 private void notifyUserLifecycleListeners(UserLifecycleEvent event) {
880 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
881 if (mUserLifecycleListeners.isEmpty()) {
882 Log.i(TAG_USER, "Not notifying internal UserLifecycleListeners");
883 return;
884 }
885 t.traceBegin("notifyInternalUserLifecycleListeners");
886 for (UserLifecycleListener listener : mUserLifecycleListeners) {
887 t.traceBegin("notify-" + event.getEventType() + "-listener-" + listener);
888 try {
889 listener.onEvent(event);
890 } catch (RuntimeException e) {
891 Log.e(TAG_USER,
892 "Exception raised when invoking onEvent for " + listener, e);
893 }
894 t.traceEnd();
895 }
896 t.traceEnd();
897 }
898
899 private void onSwitchUser(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -0800900 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
901 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garg31e73042020-01-23 00:10:38 -0800902 t.traceBegin("onSwitchUser-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -0800903
Felipe Lemef45ee502019-12-19 10:00:14 -0800904 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -0700905 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700906 }
Eric Jeongc91f9452019-08-30 15:04:21 -0700907 if (mLastPassengerId != UserHandle.USER_NULL) {
908 stopPassengerInternal(mLastPassengerId, false);
909 }
910 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
911 setupPassengerUser();
912 startFirstPassenger(userId);
913 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700914 }
915
916 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700917 * 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 -0800918 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700919 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800920 * @param r Runnable to run.
921 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700922 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000923 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800924 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -0700925 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800926 if (mUser0Unlocked) {
927 runNow = true;
928 } else {
929 mUser0UnlockTasks.add(r);
930 }
931 }
932 if (runNow) {
933 r.run();
934 }
935 }
936
Keun young Parkf3523cd2019-04-08 10:09:17 -0700937 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700938 @NonNull
939 ArrayList<Integer> getBackgroundUsersToRestart() {
940 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700941 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700942 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
943 }
944 return backgroundUsersToRestart;
945 }
946
Ying Zheng1ab32b62018-06-26 12:47:26 -0700947 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700948 // Disable Location service for system user.
949 LocationManager locationManager =
950 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -0800951 locationManager.setLocationEnabledForUser(
952 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -0700953 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700954
955 /**
956 * Creates a new user on the system, the created user would be granted admin role.
957 *
958 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700959 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700960 */
961 @Nullable
962 private UserInfo createNewAdminUser(String name) {
963 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
964 // Only admins or system user can create other privileged users.
965 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
966 return null;
967 }
968
969 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
970 if (user == null) {
971 // Couldn't create user, most likely because there are too many.
972 Log.w(TAG_USER, "can't create admin user.");
973 return null;
974 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700975 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700976
977 return user;
978 }
979
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700980 /**
981 * Assigns a default icon to a user according to the user's id.
982 *
983 * @param userInfo User whose avatar is set to default icon.
984 * @return Bitmap of the user icon.
985 */
986 private Bitmap assignDefaultIcon(UserInfo userInfo) {
987 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
988 Bitmap bitmap = UserIcons.convertToBitmap(
989 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
990 mUserManager.setUserIcon(userInfo.id, bitmap);
991 return bitmap;
992 }
993
Eric Jeong1545f3b2019-09-16 13:56:52 -0700994 private interface UserFilter {
995 boolean isEligibleUser(UserInfo user);
996 }
997
998 /** Returns all users who are matched by the given filter. */
999 private List<UserInfo> getUsers(UserFilter filter) {
1000 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1001
1002 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1003 UserInfo user = iterator.next();
1004 if (!filter.isEligibleUser(user)) {
1005 iterator.remove();
1006 }
1007 }
1008 return users;
1009 }
1010
1011 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001012 * Enforces that apps which have the
1013 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1014 * can make certain calls to the CarUserManager.
1015 *
1016 * @param message used as message if SecurityException is thrown.
1017 * @throws SecurityException if the caller is not system or root.
1018 */
1019 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001020 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1021 }
1022
1023 private static void checkManageUsersOrDumpPermission(String message) {
1024 checkAtLeastOnePermission(message,
1025 android.Manifest.permission.MANAGE_USERS,
1026 android.Manifest.permission.DUMP);
1027 }
1028
Felipe Leme5528ff72020-02-10 19:05:14 -08001029 private void checkInteractAcrossUsersPermission(String message) {
1030 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1031 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1032 }
1033
felipeal2d0483c2019-11-02 14:07:22 -07001034 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001035 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001036 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1037 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001038 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001039 }
1040 }
1041
felipeal2d0483c2019-11-02 14:07:22 -07001042 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1043 for (String permission : permissions) {
1044 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1045 /* exported = */ true)
1046 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1047 return true;
1048 }
1049 }
1050 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001051 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001052
1053 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1054 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1055 // Count all users that are managed profiles of the given user.
1056 int managedProfilesCount = 0;
1057 for (UserInfo user : users) {
1058 if (user.isManagedProfile() && user.profileGroupId == userId) {
1059 managedProfilesCount++;
1060 }
1061 }
1062 return managedProfilesCount;
1063 }
1064
1065 /**
1066 * Starts the first passenger of the given driver and assigns the passenger to the front
1067 * passenger zone.
1068 *
1069 * @param driverId User id of the driver.
1070 * @return whether it succeeds.
1071 */
1072 private boolean startFirstPassenger(@UserIdInt int driverId) {
1073 int zoneId = getAvailablePassengerZone();
1074 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1075 Log.w(TAG_USER, "passenger occupant zone is not found");
1076 return false;
1077 }
1078 List<UserInfo> passengers = getPassengers(driverId);
1079 if (passengers.size() < 1) {
1080 Log.w(TAG_USER, "passenger is not found");
1081 return false;
1082 }
1083 // Only one passenger is supported. If there are two or more passengers, the first passenger
1084 // is chosen.
1085 int passengerId = passengers.get(0).id;
1086 if (!startPassenger(passengerId, zoneId)) {
1087 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1088 return false;
1089 }
1090 return true;
1091 }
1092
1093 private int getAvailablePassengerZone() {
1094 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1095 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1096 for (int occupantType : occupantTypes) {
1097 int zoneId = getZoneId(occupantType);
1098 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1099 return zoneId;
1100 }
1101 }
1102 return OccupantZoneInfo.INVALID_ZONE_ID;
1103 }
1104
1105 /**
1106 * Creates a new passenger user when there is no passenger user.
1107 */
1108 private void setupPassengerUser() {
1109 int currentUser = ActivityManager.getCurrentUser();
1110 int profileCount = getNumberOfManagedProfiles(currentUser);
1111 if (profileCount > 0) {
1112 Log.w(TAG_USER, "max profile of user" + currentUser
1113 + " is exceeded: current profile count is " + profileCount);
1114 return;
1115 }
1116 // TODO(b/140311342): Use resource string for the default passenger name.
1117 UserInfo passenger = createPassenger("Passenger", currentUser);
1118 if (passenger == null) {
1119 // Couldn't create user, most likely because there are too many.
1120 Log.w(TAG_USER, "cannot create a passenger user");
1121 return;
1122 }
1123 }
1124
1125 @NonNull
1126 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1127 ZoneUserBindingHelper helper = null;
1128 synchronized (mLockHelper) {
1129 if (mZoneUserBindingHelper == null) {
1130 Log.w(TAG_USER, "implementation is not delegated");
1131 return new ArrayList<OccupantZoneInfo>();
1132 }
1133 helper = mZoneUserBindingHelper;
1134 }
1135 return helper.getOccupantZones(occupantType);
1136 }
1137
1138 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1139 ZoneUserBindingHelper helper = null;
1140 synchronized (mLockHelper) {
1141 if (mZoneUserBindingHelper == null) {
1142 Log.w(TAG_USER, "implementation is not delegated");
1143 return false;
1144 }
1145 helper = mZoneUserBindingHelper;
1146 }
1147 return helper.assignUserToOccupantZone(userId, zoneId);
1148 }
1149
1150 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1151 ZoneUserBindingHelper helper = null;
1152 synchronized (mLockHelper) {
1153 if (mZoneUserBindingHelper == null) {
1154 Log.w(TAG_USER, "implementation is not delegated");
1155 return false;
1156 }
1157 helper = mZoneUserBindingHelper;
1158 }
1159 return helper.unassignUserFromOccupantZone(userId);
1160 }
1161
1162 private boolean isPassengerDisplayAvailable() {
1163 ZoneUserBindingHelper helper = null;
1164 synchronized (mLockHelper) {
1165 if (mZoneUserBindingHelper == null) {
1166 Log.w(TAG_USER, "implementation is not delegated");
1167 return false;
1168 }
1169 helper = mZoneUserBindingHelper;
1170 }
1171 return helper.isPassengerDisplayAvailable();
1172 }
1173
1174 /**
1175 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1176 * zone is returned.
1177 *
1178 * @param occupantType The type of an occupant.
1179 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1180 * if not found.
1181 */
1182 private int getZoneId(@OccupantTypeEnum int occupantType) {
1183 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1184 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1185 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001186}