blob: 578e5c907a1f22544e9fd9df25b0909e9951dab1 [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;
felipeale8c5dce2020-04-15 11:27:06 -070034import android.car.user.CarUserManager.UserLifecycleEventType;
Antonio Kantekc8114752020-03-05 21:37:39 -080035import android.car.user.CarUserManager.UserLifecycleListener;
Eric Jeong3a793b02019-09-30 16:12:53 -070036import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070037import android.car.userlib.HalCallback;
38import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070039import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070040import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070041import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070042import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070043import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080044import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg7a114c82020-04-08 21:25:06 -070045import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
Mayank Garg59f22192020-03-27 00:51:45 -070046import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080047import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070048import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070049import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080050import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070051import android.os.Handler;
52import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070053import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080054import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070055import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070056import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070057import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070058import android.sysprop.CarProperties;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070059import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080060import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080061import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070062
63import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070064import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080065import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080066import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070067import com.android.internal.annotations.VisibleForTesting;
Felipe Leme5528ff72020-02-10 19:05:14 -080068import com.android.internal.os.IResultReceiver;
felipeal2a84d512020-04-06 18:52:15 -070069import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070070import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070071import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070072
73import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080074import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070075import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070076import java.util.Iterator;
77import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000078import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070079import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070080import java.util.concurrent.CountDownLatch;
81import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070082
83/**
84 * User service for cars. Manages users at boot time. Including:
85 *
86 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070087 * <li> Creates a user used as driver.
88 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070089 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070090 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070091 * <ol/>
92 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070093public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080094
Felipe Lemeabbf2da2020-02-24 18:25:29 -080095 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080096 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080097 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080098 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080099 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800100 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800101 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
102 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800103
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700104 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700105 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700106 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700107 private final UserManager mUserManager;
108 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700109 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700110
Eric Jeongc91f9452019-08-30 15:04:21 -0700111 private final Object mLockUser = new Object();
112 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800113 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700114 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800115 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700116 // Only one passenger is supported.
117 @GuardedBy("mLockUser")
118 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700119 /**
120 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800121 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700122 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700123 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700124 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
125 /**
126 * Keep the list of background users started here. This is wholly for debugging purpose.
127 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700128 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700129 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
130
Felipe Leme58412202020-01-09 13:45:33 -0800131 private final UserHalService mHal;
132
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700133 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
134 private final HandlerThread mHandlerThread;
135 private final Handler mHandler;
136
Felipe Leme5528ff72020-02-10 19:05:14 -0800137 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800138 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700139 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800140 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700141 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800142
143 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800144 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700145 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800146 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800148
Mayank Garg7a114c82020-04-08 21:25:06 -0700149 /**
150 * User Id for the user switch in process, if any.
151 */
152 @GuardedBy("mLockUser")
153 private int mUserSwitchInProcess = UserHandle.USER_NULL;
154 /**
155 * Request Id for the user switch in process, if any.
156 */
157 @GuardedBy("mLockUser")
158 private int mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
Felipe Lemee3cab982020-03-12 11:39:29 -0700159 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
160
Eric Jeongc91f9452019-08-30 15:04:21 -0700161 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
162 new CopyOnWriteArrayList<>();
163
felipeal61ce3732020-04-03 11:01:00 -0700164 @Nullable
165 @GuardedBy("mLockUser")
166 private UserInfo mInitialUser;
167
felipeale8c5dce2020-04-15 11:27:06 -0700168 private final UserMetrics mUserMetrics = new UserMetrics();
169
Eric Jeongc91f9452019-08-30 15:04:21 -0700170 /** Interface for callbaks related to passenger activities. */
171 public interface PassengerCallback {
172 /** Called when passenger is started at a certain zone. */
173 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
174 /** Called when passenger is stopped. */
175 void onPassengerStopped(@UserIdInt int passengerId);
176 }
177
178 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
179 public interface ZoneUserBindingHelper {
180 /** Gets occupant zones corresponding to the occupant type. */
181 @NonNull
182 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
183 /** Assigns the user to the occupant zone. */
184 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
185 /** Makes the occupant zone unoccupied. */
186 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
187 /** Returns whether there is a passenger display. */
188 boolean isPassengerDisplayAvailable();
189 }
190
191 private final Object mLockHelper = new Object();
192 @GuardedBy("mLockHelper")
193 private ZoneUserBindingHelper mZoneUserBindingHelper;
194
Felipe Leme58412202020-01-09 13:45:33 -0800195 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
196 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700197 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700198 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
199 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700200 }
201 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800202 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700203 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700204 mAm = am;
205 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700206 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700207 mLastPassengerId = UserHandle.USER_NULL;
208 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700209 mHandlerThread = new HandlerThread(CarUserService.class.getSimpleName());
210 mHandlerThread.start();
211 mHandler = new Handler(mHandlerThread.getLooper());
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700212 }
213
214 @Override
215 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700216 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
217 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700218 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700219 }
220
221 @Override
222 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700223 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
224 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700225 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700226 }
227
228 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700229 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700230 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700231 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800232 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700233 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700234 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700235 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700236 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
237 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700238 }
239 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
240 List<UserInfo> allDrivers = getAllDrivers();
241 int driversSize = allDrivers.size();
242 writer.println("NumberOfDrivers: " + driversSize);
243 for (int i = 0; i < driversSize; i++) {
244 int driverId = allDrivers.get(i).id;
245 writer.print(indent + "#" + i + ": id=" + driverId);
246 List<UserInfo> passengers = getPassengers(driverId);
247 int passengersSize = passengers.size();
248 writer.print(" NumberPassengers: " + passengersSize);
249 if (passengersSize > 0) {
250 writer.print(" [");
251 for (int j = 0; j < passengersSize; j++) {
252 writer.print(passengers.get(j).id);
253 if (j < passengersSize - 1) {
254 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700255 }
felipeal2d0483c2019-11-02 14:07:22 -0700256 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700257 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700258 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700259 writer.println();
260 }
261 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
262 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
263 writer.printf("Initial user: %s\n", mInitialUser);
264 writer.println("Relevant overlayable properties");
265 Resources res = mContext.getResources();
266 writer.printf("%sowner_name=%s\n", indent,
267 res.getString(com.android.internal.R.string.owner_name));
268 writer.printf("%sdefault_guest_name=%s\n", indent,
269 res.getString(R.string.default_guest_name));
Mayank Garg7a114c82020-04-08 21:25:06 -0700270 writer.printf("User switch in process=%d\n", mUserSwitchInProcess);
271 writer.printf("Request Id for the user switch in process=%d\n ",
272 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700273
274 dumpUserMetrics(writer);
275 }
276
277 /**
278 * Dumps user metrics.
279 */
280 public void dumpUserMetrics(@NonNull PrintWriter writer) {
281 mUserMetrics.dump(writer);
282 }
283
284 /**
285 * Dumps first user unlocking time.
286 */
287 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
288 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700289 }
290
291 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
292 CountDownLatch latch = new CountDownLatch(1);
293 mHandler.post(() -> {
294 handleDumpUserLifecycleListeners(writer);
295 handleDumpAppLifecycleListeners(writer, indent);
296 latch.countDown();
297 });
298 int timeout = 5;
299 try {
300 if (!latch.await(timeout, TimeUnit.SECONDS)) {
301 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
302 timeout);
303 }
304 } catch (InterruptedException e) {
305 Thread.currentThread().interrupt();
306 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
307 }
308 }
309
310 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
311 if (mUserLifecycleListeners.isEmpty()) {
312 writer.println("No user lifecycle listeners");
313 return;
314 }
315 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
316 for (UserLifecycleListener listener : mUserLifecycleListeners) {
317 writer.printf("Listener %s\n", listener);
318 }
319 }
320
321 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
322 int numberListeners = mAppLifecycleListeners.size();
323 if (numberListeners == 0) {
324 writer.println("No lifecycle listeners");
325 return;
326 }
327 writer.printf("%d lifecycle listeners\n", numberListeners);
328 for (int i = 0; i < numberListeners; i++) {
329 int uid = mAppLifecycleListeners.keyAt(i);
330 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
331 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800332 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700333 }
334
335 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800336 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
337 *
338 * @param name The name of the driver to be created.
339 * @param admin Whether the created driver will be an admin.
340 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
341 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700342 */
343 @Override
344 @Nullable
345 public UserInfo createDriver(@NonNull String name, boolean admin) {
346 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000347 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700348 if (admin) {
349 return createNewAdminUser(name);
350 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700351 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700352 }
353
354 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800355 * Creates a passenger who is a profile of the given driver.
356 *
357 * @param name The name of the passenger to be created.
358 * @param driverId User id of the driver under whom a passenger is created.
359 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
360 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700361 */
362 @Override
363 @Nullable
364 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
365 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000366 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700367 UserInfo driver = mUserManager.getUserInfo(driverId);
368 if (driver == null) {
369 Log.w(TAG_USER, "the driver is invalid");
370 return null;
371 }
372 if (driver.isGuest()) {
373 Log.w(TAG_USER, "a guest driver cannot create a passenger");
374 return null;
375 }
Bookatz42fb1a62019-10-30 11:45:01 -0700376 UserInfo user = mUserManager.createProfileForUser(name,
377 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700378 if (user == null) {
379 // Couldn't create user, most likely because there are too many.
380 Log.w(TAG_USER, "can't create a profile for user" + driverId);
381 return null;
382 }
383 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700384 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700385 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700386 return user;
387 }
388
389 /**
390 * @see CarUserManager.switchDriver
391 */
392 @Override
393 public boolean switchDriver(@UserIdInt int driverId) {
394 checkManageUsersPermission("switchDriver");
395 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
396 // System user doesn't associate with real person, can not be switched to.
397 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
398 return false;
399 }
400 int userSwitchable = mUserManager.getUserSwitchability();
401 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
402 Log.w(TAG_USER, "current process is not allowed to switch user");
403 return false;
404 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700405 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700406 // The current user is already the given user.
407 return true;
408 }
409 try {
410 return mAm.switchUser(driverId);
411 } catch (RemoteException e) {
412 // ignore
413 Log.w(TAG_USER, "error while switching user", e);
414 }
415 return false;
416 }
417
418 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800419 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
420 *
421 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700422 */
423 @Override
424 @NonNull
425 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700426 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700427 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
428 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700429 }
430
431 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800432 * Returns all passengers under the given driver.
433 *
434 * @param driverId User id of a driver.
435 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700436 */
437 @Override
438 @NonNull
439 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700440 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 return getUsers((user) -> {
442 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
443 && user.profileGroupId == driverId;
444 });
445 }
446
447 /**
448 * @see CarUserManager.startPassenger
449 */
450 @Override
451 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
452 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700453 synchronized (mLockUser) {
454 try {
455 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
456 Log.w(TAG_USER, "could not start passenger");
457 return false;
458 }
459 } catch (RemoteException e) {
460 // ignore
461 Log.w(TAG_USER, "error while starting passenger", e);
462 return false;
463 }
464 if (!assignUserToOccupantZone(passengerId, zoneId)) {
465 Log.w(TAG_USER, "could not assign passenger to zone");
466 return false;
467 }
468 mLastPassengerId = passengerId;
469 }
470 for (PassengerCallback callback : mPassengerCallbacks) {
471 callback.onPassengerStarted(passengerId, zoneId);
472 }
473 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 }
475
476 /**
477 * @see CarUserManager.stopPassenger
478 */
479 @Override
480 public boolean stopPassenger(@UserIdInt int passengerId) {
481 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700482 return stopPassengerInternal(passengerId, true);
483 }
484
485 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
486 synchronized (mLockUser) {
487 UserInfo passenger = mUserManager.getUserInfo(passengerId);
488 if (passenger == null) {
489 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
490 return false;
491 }
492 if (mLastPassengerId != passengerId) {
493 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
494 return true;
495 }
496 if (checkCurrentDriver) {
497 int currentUser = ActivityManager.getCurrentUser();
498 if (passenger.profileGroupId != currentUser) {
499 Log.w(TAG_USER, "passenger " + passengerId
500 + " is not a profile of the current user");
501 return false;
502 }
503 }
504 // Passenger is a profile, so cannot be stopped through activity manager.
505 // Instead, activities started by the passenger are stopped and the passenger is
506 // unassigned from the zone.
507 stopAllTasks(passengerId);
508 if (!unassignUserFromOccupantZone(passengerId)) {
509 Log.w(TAG_USER, "could not unassign user from occupant zone");
510 return false;
511 }
512 mLastPassengerId = UserHandle.USER_NULL;
513 }
514 for (PassengerCallback callback : mPassengerCallbacks) {
515 callback.onPassengerStopped(passengerId);
516 }
517 return true;
518 }
519
520 private void stopAllTasks(@UserIdInt int userId) {
521 try {
522 for (StackInfo info : mAm.getAllStackInfos()) {
523 for (int i = 0; i < info.taskIds.length; i++) {
524 if (info.taskUserIds[i] == userId) {
525 int taskId = info.taskIds[i];
526 if (!mAm.removeTask(taskId)) {
527 Log.w(TAG_USER, "could not remove task " + taskId);
528 }
529 }
530 }
531 }
532 } catch (RemoteException e) {
533 Log.e(TAG_USER, "could not get stack info", e);
534 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700535 }
536
Felipe Leme5528ff72020-02-10 19:05:14 -0800537 @Override
538 public void setLifecycleListenerForUid(IResultReceiver listener) {
539 int uid = Binder.getCallingUid();
540 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
541
542 try {
543 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
544 } catch (RemoteException e) {
545 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
546 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700547 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800548 }
549
550 private void onListenerDeath(int uid) {
551 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700552 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800553 }
554
555 @Override
556 public void resetLifecycleListenerForUid() {
557 int uid = Binder.getCallingUid();
558 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700559 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800560 }
561
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800562 @Override
563 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800564 @NonNull IResultReceiver receiver) {
Felipe Lemee2600fc2020-02-26 11:06:04 -0800565 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700566 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800567 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800568 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
569 try {
570 Bundle resultData = null;
571 if (resp != null) {
572 switch (resp.action) {
573 case InitialUserInfoResponseAction.SWITCH:
574 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800575 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800576 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
577 break;
578 case InitialUserInfoResponseAction.CREATE:
579 resultData = new Bundle();
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800580 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800581 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
582 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
583 break;
584 case InitialUserInfoResponseAction.DEFAULT:
Felipe Leme8f30b312020-02-28 18:01:25 -0800585 resultData = new Bundle();
586 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800587 break;
588 default:
589 // That's ok, it will be the same as DEFAULT...
590 Log.w(TAG_USER, "invalid response action on " + resp);
591 }
592 }
593 receiver.send(status, resultData);
594 } catch (RemoteException e) {
595 Log.w(TAG_USER, "Could not send result back to receiver", e);
596 }
597 });
598 }
599
Felipe Lemee3cab982020-03-12 11:39:29 -0700600 /**
felipeal61ce3732020-04-03 11:01:00 -0700601 * Gets the initial foreground user after the device boots or resumes from suspension.
602 *
603 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
604 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
605 * method returns {@code null}.
606 *
607 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
608 * (like switching to the last active user), and this method will return the result of such
609 * operation.
610 *
611 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
612 * {@code null}.
613 *
614 * @hide
615 */
616 @Nullable
617 public UserInfo getInitialUser() {
618 checkInteractAcrossUsersPermission("getInitialUser");
619 synchronized (mLockUser) {
620 return mInitialUser;
621 }
622 }
623
624 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
625 // some reason passing the whole UserInfo through a raw binder transaction is not working.
626 /**
627 * Sets the initial foreground user after the device boots or resumes from suspension.
628 */
629 public void setInitialUser(@UserIdInt int userId) {
630 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
631 : mUserManager.getUserInfo(userId);
632 setInitialUser(initialUser);
633 }
634
635 /**
636 * Sets the initial foreground user after the device boots or resumes from suspension.
637 */
638 public void setInitialUser(@Nullable UserInfo user) {
639 Log.i(TAG_USER, "setInitialUser: " + user);
640 synchronized (mLockUser) {
641 mInitialUser = user;
642 }
643 if (user == null) {
644 // This mean InitialUserSetter failed and could not fallback, so the initial user was
645 // not switched (and most likely is SYSTEM_USER).
646 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
647 Log.wtf(TAG_USER, "Initial user set to null");
648 }
649 }
650
651 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700652 * Calls the User HAL to get the initial user info.
653 *
654 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
655 * @param callback callback to receive the results.
656 */
657 public void getInitialUserInfo(int requestType,
658 HalCallback<InitialUserInfoResponse> callback) {
659 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700660 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700661 UsersInfo usersInfo = getUsersInfo();
662 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
663 }
664
665 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700666 * Calls the User HAL to switch user.
667 *
Mayank Garge19c2922020-03-30 18:05:53 -0700668 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700669 * @param timeoutMs - timeout for HAL to wait
670 * @param receiver - receiver for the results
671 */
Mayank Garge19c2922020-03-30 18:05:53 -0700672 @Override
673 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
Mayank Garg59f22192020-03-27 00:51:45 -0700674 @NonNull IResultReceiver receiver) {
675 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700676 Objects.requireNonNull(receiver);
677 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
678 Preconditions.checkArgument(targetUser != null, "Invalid target user Id");
Mayank Garg7a114c82020-04-08 21:25:06 -0700679
680 synchronized (mLockUser) {
681 if (mUserSwitchInProcess == targetUserId) {
682 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
683 Log.d(TAG_USER,
684 "User switch for user: " + targetUserId + " is already in process.");
685 }
686 // TODO(b/150409110): Add concurrent User Switch status and tests
687 return;
688 }
689 }
690
Mayank Garg59f22192020-03-27 00:51:45 -0700691 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700692 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700693 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700694 halTargetUser.userId = targetUser.id;
695 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
696 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg59f22192020-03-27 00:51:45 -0700697 Bundle resultData = null;
698 resultData = new Bundle();
Mayank Garge19c2922020-03-30 18:05:53 -0700699 int resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_INTERNAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700700 if (resp != null) {
Mayank Garge19c2922020-03-30 18:05:53 -0700701 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
702 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
703 if (resp.errorMessage != null) {
704 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
705 resp.errorMessage);
706 }
Mayank Garg59f22192020-03-27 00:51:45 -0700707 switch (resp.status) {
708 case SwitchUserStatus.SUCCESS:
709 boolean result;
710 try {
Mayank Garge19c2922020-03-30 18:05:53 -0700711 result = mAm.switchUser(targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700712 if (result) {
Mayank Garge19c2922020-03-30 18:05:53 -0700713 resultStatus = CarUserManager.USER_SWITCH_STATUS_SUCCESSFUL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700714 updateUserSwitchInProcess(targetUserId, resp);
Mayank Garg59f22192020-03-27 00:51:45 -0700715 } else {
Mayank Garge19c2922020-03-30 18:05:53 -0700716 resultStatus = CarUserManager.USER_SWITCH_STATUS_ANDROID_FAILURE;
Mayank Garg7a114c82020-04-08 21:25:06 -0700717 postSwitchHalResponse(resp.requestId, targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700718 }
719 } catch (RemoteException e) {
720 // ignore
721 Log.w(TAG_USER,
722 "error while switching user " + targetUser.toFullString(), e);
723 }
724 break;
725 case SwitchUserStatus.FAILURE:
726 // HAL failed to switch user
Mayank Garge19c2922020-03-30 18:05:53 -0700727 resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700728 break;
729 }
Mayank Garg59f22192020-03-27 00:51:45 -0700730 }
Mayank Garge19c2922020-03-30 18:05:53 -0700731 try {
732 receiver.send(resultStatus, resultData);
733 } catch (RemoteException e) {
734 // ignore
735 Log.w(TAG_USER, "error while sending results", e);
736 }
737
Mayank Garg59f22192020-03-27 00:51:45 -0700738 });
739 }
740
Mayank Garg7a114c82020-04-08 21:25:06 -0700741 private void updateUserSwitchInProcess(@UserIdInt int targetUserId,
742 @NonNull SwitchUserResponse resp) {
743 synchronized (mLockUser) {
744 if (mUserSwitchInProcess != UserHandle.USER_NULL) {
745 // Some other user switch is in process.
746 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
747 Log.d(TAG_USER, "User switch for user: " + mUserSwitchInProcess
748 + " is in process. Sending failed android post switch response for it "
749 + " as new user switch is requested for user: " + targetUserId);
750 }
751 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserSwitchInProcess);
752 }
753 mUserSwitchInProcess = targetUserId;
754 mRequestIdForUserSwitchInProcess = resp.requestId;
755 }
756 }
757
758 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
759 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
760 UsersInfo usersInfo = getUsersInfo();
761 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
762 new android.hardware.automotive.vehicle.V2_0.UserInfo();
763 halTargetUser.userId = targetUser.id;
764 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
765 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
766 }
767
Mayank Garg59f22192020-03-27 00:51:45 -0700768 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700769 * Checks if the User HAL is supported.
770 */
771 public boolean isUserHalSupported() {
772 return mHal.isSupported();
773 }
774
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800775 // TODO(b/144120654): use helper to generate UsersInfo
776 private UsersInfo getUsersInfo() {
777 UserInfo currentUser;
778 try {
779 currentUser = mAm.getCurrentUser();
780 } catch (RemoteException e) {
781 // shouldn't happen
782 throw new IllegalStateException("Could not get current user: ", e);
783 }
784 List<UserInfo> existingUsers = mUserManager.getUsers();
785 int size = existingUsers.size();
786
787 UsersInfo usersInfo = new UsersInfo();
788 usersInfo.numberUsers = size;
789 usersInfo.currentUser.userId = currentUser.id;
790 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
791
792 for (int i = 0; i < size; i++) {
793 UserInfo androidUser = existingUsers.get(i);
794 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
795 new android.hardware.automotive.vehicle.V2_0.UserInfo();
796 halUser.userId = androidUser.id;
797 halUser.flags = UserHalHelper.convertFlags(androidUser);
798 usersInfo.existingUsers.add(halUser);
799 }
800
801 return usersInfo;
802 }
803
Eric Jeong1545f3b2019-09-16 13:56:52 -0700804 /** Returns whether the given user is a system user. */
805 private static boolean isSystemUser(@UserIdInt int userId) {
806 return userId == UserHandle.USER_SYSTEM;
807 }
808
Keun young Park13a7a822019-04-04 15:53:08 -0700809 private void updateDefaultUserRestriction() {
810 // We want to set restrictions on system and guest users only once. These are persisted
811 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
812 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700813 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
814 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700815 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700816 // Only apply the system user restrictions if the system user is headless.
817 if (UserManager.isHeadlessSystemUserMode()) {
818 setSystemUserRestrictions();
819 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700820 Settings.Global.putInt(mContext.getContentResolver(),
821 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700822 }
823
Eric Jeong1545f3b2019-09-16 13:56:52 -0700824 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700825 return !mUserManager.getUserInfo(userId).isEphemeral();
826 }
827
Antonio Kantekc8114752020-03-05 21:37:39 -0800828 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800829 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
830 */
831 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
832 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700833 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800834 }
835
836 /**
837 * Removes previously added {@link UserLifecycleListener}.
838 */
839 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
840 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700841 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800842 }
843
Eric Jeongc91f9452019-08-30 15:04:21 -0700844 /** Adds callback to listen to passenger activity events. */
845 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000846 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700847 mPassengerCallbacks.add(callback);
848 }
849
850 /** Removes previously added callback to listen passenger events. */
851 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000852 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700853 mPassengerCallbacks.remove(callback);
854 }
855
856 /** Sets the implementation of ZoneUserBindingHelper. */
857 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
858 synchronized (mLockHelper) {
859 mZoneUserBindingHelper = helper;
860 }
861 }
862
felipeal98900c82020-04-09 09:05:02 -0700863 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800864 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700865 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700866 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700867 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700868 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
869 updateDefaultUserRestriction();
870 tasks = new ArrayList<>(mUser0UnlockTasks);
871 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700872 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700873 }
874 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700875 Integer user = userId;
876 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700877 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700878 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700879 mBackgroundUsersToRestart.remove(user);
880 mBackgroundUsersToRestart.add(0, user);
881 }
882 // -1 for user 0
883 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700884 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700885 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700886 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700887 + ", dropping least recently user from restart list:" + userToDrop);
888 // Drop the least recently used user.
889 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
890 }
891 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800892 }
893 }
894 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700895 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800896 for (Runnable r : tasks) {
897 r.run();
898 }
899 }
900 }
901
902 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700903 * Starts all background users that were active in system.
904 *
Keun young Parkfb656372019-03-12 18:37:55 -0700905 * @return list of background users started successfully.
906 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700907 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700908 public ArrayList<Integer> startAllBackgroundUsers() {
909 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700910 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700911 users = new ArrayList<>(mBackgroundUsersToRestart);
912 mBackgroundUsersRestartedHere.clear();
913 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700914 }
915 ArrayList<Integer> startedUsers = new ArrayList<>();
916 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700917 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700918 continue;
919 }
920 try {
921 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700922 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
923 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700924 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700925 } else if (mAm.unlockUser(user, null, null, null)) {
926 startedUsers.add(user);
927 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700928 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700929 if (mUserManager.isUserRunning(user)) {
930 // add to started list so that it can be stopped later.
931 startedUsers.add(user);
932 }
Keun young Parkfb656372019-03-12 18:37:55 -0700933 }
934 }
935 } catch (RemoteException e) {
936 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700937 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700938 }
939 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700940 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700941 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700942 ArrayList<Integer> usersToRemove = new ArrayList<>();
943 for (Integer user : mBackgroundUsersToRestart) {
944 if (!startedUsers.contains(user)) {
945 usersToRemove.add(user);
946 }
947 }
948 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
949 }
Keun young Parkfb656372019-03-12 18:37:55 -0700950 return startedUsers;
951 }
952
953 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700954 * Stops all background users that were active in system.
955 *
956 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700957 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700958 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700959 if (userId == UserHandle.USER_SYSTEM) {
960 return false;
961 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700962 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700963 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700964 return false;
965 }
966 try {
Keun young Parked9e6282019-09-19 17:38:26 -0700967 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700968 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -0700969 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700970 Integer user = userId;
971 mBackgroundUsersRestartedHere.remove(user);
972 }
973 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
974 return false;
975 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700976 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700977 return false;
978 }
979 } catch (RemoteException e) {
980 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700981 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700982 }
983 return true;
984 }
985
986 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700987 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700988 */
felipeale8c5dce2020-04-15 11:27:06 -0700989 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
990 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
991 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -0700992
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700993 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -0700994 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
995 onUserSwitching(userId);
996 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
997 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700998 }
999
felipeale8c5dce2020-04-15 11:27:06 -07001000 // ...then notify listeners.
1001 UserLifecycleEvent event = new UserLifecycleEvent(eventType, userId);
1002
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001003 mHandler.post(() -> {
1004 handleNotifyServiceUserLifecycleListeners(event);
1005 handleNotifyAppUserLifecycleListeners(event);
1006 });
felipeale8c5dce2020-04-15 11:27:06 -07001007
1008 // Finally, update metrics.
1009 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1010 }
1011
1012 /**
1013 * Sets the first user unlocking metrics.
1014 */
1015 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1016 int halResponseTime) {
1017 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001018 }
1019
Mayank Garg7a114c82020-04-08 21:25:06 -07001020 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
1021 if (mUserSwitchInProcess == UserHandle.USER_NULL || mUserSwitchInProcess != userId) {
1022 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1023 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1024 }
1025 return;
1026 }
1027 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserSwitchInProcess);
1028 mUserSwitchInProcess = UserHandle.USER_NULL;
1029 mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
1030 }
1031
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001032 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1033 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001034 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001035 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1036 Log.d(TAG_USER, "No app listener to be notified of " + event);
1037 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001038 return;
1039 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001040 // Must use a different TimingsTraceLog because it's another thread
1041 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1042 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1043 }
felipeal2a84d512020-04-06 18:52:15 -07001044 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001045 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1046 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1047 for (int i = 0; i < listenersSize; i++) {
1048 int uid = mAppLifecycleListeners.keyAt(i);
1049 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1050 Bundle data = new Bundle();
1051 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
1052 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
1053 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
felipeal2a84d512020-04-06 18:52:15 -07001054 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001055 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001056 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001057 try {
felipeal2a84d512020-04-06 18:52:15 -07001058 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001059 listener.send(userId, data);
1060 } catch (RemoteException e) {
1061 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1062 } finally {
1063 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001064 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001065 }
1066 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001067 }
1068
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001069 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001070 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1071 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001072 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001073 return;
felipeal2a84d512020-04-06 18:52:15 -07001074 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1075 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1076 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001077 }
felipeal2a84d512020-04-06 18:52:15 -07001078
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001079 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1080 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001081 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001082 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001083 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001084 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001085 listener.onEvent(event);
1086 } catch (RuntimeException e) {
1087 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001088 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001089 } finally {
1090 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001091 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001092 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001093 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001094 }
1095
felipeal98900c82020-04-09 09:05:02 -07001096 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001097 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1098 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001099 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001100
Felipe Lemef45ee502019-12-19 10:00:14 -08001101 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001102 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001103 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001104 if (mLastPassengerId != UserHandle.USER_NULL) {
1105 stopPassengerInternal(mLastPassengerId, false);
1106 }
1107 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1108 setupPassengerUser();
1109 startFirstPassenger(userId);
1110 }
felipeal98900c82020-04-09 09:05:02 -07001111 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001112 }
1113
1114 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001115 * 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 -08001116 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001117 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001118 * @param r Runnable to run.
1119 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001120 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001121 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001122 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001123 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001124 if (mUser0Unlocked) {
1125 runNow = true;
1126 } else {
1127 mUser0UnlockTasks.add(r);
1128 }
1129 }
1130 if (runNow) {
1131 r.run();
1132 }
1133 }
1134
Keun young Parkf3523cd2019-04-08 10:09:17 -07001135 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001136 @NonNull
1137 ArrayList<Integer> getBackgroundUsersToRestart() {
1138 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001139 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001140 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1141 }
1142 return backgroundUsersToRestart;
1143 }
1144
Ying Zheng1ab32b62018-06-26 12:47:26 -07001145 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001146 // Disable Location service for system user.
1147 LocationManager locationManager =
1148 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001149 locationManager.setLocationEnabledForUser(
1150 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001151 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001152
1153 /**
1154 * Creates a new user on the system, the created user would be granted admin role.
1155 *
1156 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001157 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001158 */
1159 @Nullable
1160 private UserInfo createNewAdminUser(String name) {
1161 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1162 // Only admins or system user can create other privileged users.
1163 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1164 return null;
1165 }
1166
1167 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1168 if (user == null) {
1169 // Couldn't create user, most likely because there are too many.
1170 Log.w(TAG_USER, "can't create admin user.");
1171 return null;
1172 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001173 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001174
1175 return user;
1176 }
1177
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001178 /**
1179 * Assigns a default icon to a user according to the user's id.
1180 *
1181 * @param userInfo User whose avatar is set to default icon.
1182 * @return Bitmap of the user icon.
1183 */
1184 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1185 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1186 Bitmap bitmap = UserIcons.convertToBitmap(
1187 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1188 mUserManager.setUserIcon(userInfo.id, bitmap);
1189 return bitmap;
1190 }
1191
Eric Jeong1545f3b2019-09-16 13:56:52 -07001192 private interface UserFilter {
1193 boolean isEligibleUser(UserInfo user);
1194 }
1195
1196 /** Returns all users who are matched by the given filter. */
1197 private List<UserInfo> getUsers(UserFilter filter) {
1198 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1199
1200 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1201 UserInfo user = iterator.next();
1202 if (!filter.isEligibleUser(user)) {
1203 iterator.remove();
1204 }
1205 }
1206 return users;
1207 }
1208
1209 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001210 * Enforces that apps which have the
1211 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1212 * can make certain calls to the CarUserManager.
1213 *
1214 * @param message used as message if SecurityException is thrown.
1215 * @throws SecurityException if the caller is not system or root.
1216 */
1217 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001218 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1219 }
1220
1221 private static void checkManageUsersOrDumpPermission(String message) {
1222 checkAtLeastOnePermission(message,
1223 android.Manifest.permission.MANAGE_USERS,
1224 android.Manifest.permission.DUMP);
1225 }
1226
Felipe Leme5528ff72020-02-10 19:05:14 -08001227 private void checkInteractAcrossUsersPermission(String message) {
1228 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1229 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1230 }
1231
felipeal2d0483c2019-11-02 14:07:22 -07001232 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001233 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001234 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1235 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001236 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001237 }
1238 }
1239
felipeal2d0483c2019-11-02 14:07:22 -07001240 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1241 for (String permission : permissions) {
1242 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1243 /* exported = */ true)
1244 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1245 return true;
1246 }
1247 }
1248 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001249 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001250
1251 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1252 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1253 // Count all users that are managed profiles of the given user.
1254 int managedProfilesCount = 0;
1255 for (UserInfo user : users) {
1256 if (user.isManagedProfile() && user.profileGroupId == userId) {
1257 managedProfilesCount++;
1258 }
1259 }
1260 return managedProfilesCount;
1261 }
1262
1263 /**
1264 * Starts the first passenger of the given driver and assigns the passenger to the front
1265 * passenger zone.
1266 *
1267 * @param driverId User id of the driver.
1268 * @return whether it succeeds.
1269 */
1270 private boolean startFirstPassenger(@UserIdInt int driverId) {
1271 int zoneId = getAvailablePassengerZone();
1272 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1273 Log.w(TAG_USER, "passenger occupant zone is not found");
1274 return false;
1275 }
1276 List<UserInfo> passengers = getPassengers(driverId);
1277 if (passengers.size() < 1) {
1278 Log.w(TAG_USER, "passenger is not found");
1279 return false;
1280 }
1281 // Only one passenger is supported. If there are two or more passengers, the first passenger
1282 // is chosen.
1283 int passengerId = passengers.get(0).id;
1284 if (!startPassenger(passengerId, zoneId)) {
1285 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1286 return false;
1287 }
1288 return true;
1289 }
1290
1291 private int getAvailablePassengerZone() {
1292 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1293 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1294 for (int occupantType : occupantTypes) {
1295 int zoneId = getZoneId(occupantType);
1296 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1297 return zoneId;
1298 }
1299 }
1300 return OccupantZoneInfo.INVALID_ZONE_ID;
1301 }
1302
1303 /**
1304 * Creates a new passenger user when there is no passenger user.
1305 */
1306 private void setupPassengerUser() {
1307 int currentUser = ActivityManager.getCurrentUser();
1308 int profileCount = getNumberOfManagedProfiles(currentUser);
1309 if (profileCount > 0) {
1310 Log.w(TAG_USER, "max profile of user" + currentUser
1311 + " is exceeded: current profile count is " + profileCount);
1312 return;
1313 }
1314 // TODO(b/140311342): Use resource string for the default passenger name.
1315 UserInfo passenger = createPassenger("Passenger", currentUser);
1316 if (passenger == null) {
1317 // Couldn't create user, most likely because there are too many.
1318 Log.w(TAG_USER, "cannot create a passenger user");
1319 return;
1320 }
1321 }
1322
1323 @NonNull
1324 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1325 ZoneUserBindingHelper helper = null;
1326 synchronized (mLockHelper) {
1327 if (mZoneUserBindingHelper == null) {
1328 Log.w(TAG_USER, "implementation is not delegated");
1329 return new ArrayList<OccupantZoneInfo>();
1330 }
1331 helper = mZoneUserBindingHelper;
1332 }
1333 return helper.getOccupantZones(occupantType);
1334 }
1335
1336 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1337 ZoneUserBindingHelper helper = null;
1338 synchronized (mLockHelper) {
1339 if (mZoneUserBindingHelper == null) {
1340 Log.w(TAG_USER, "implementation is not delegated");
1341 return false;
1342 }
1343 helper = mZoneUserBindingHelper;
1344 }
1345 return helper.assignUserToOccupantZone(userId, zoneId);
1346 }
1347
1348 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1349 ZoneUserBindingHelper helper = null;
1350 synchronized (mLockHelper) {
1351 if (mZoneUserBindingHelper == null) {
1352 Log.w(TAG_USER, "implementation is not delegated");
1353 return false;
1354 }
1355 helper = mZoneUserBindingHelper;
1356 }
1357 return helper.unassignUserFromOccupantZone(userId);
1358 }
1359
1360 private boolean isPassengerDisplayAvailable() {
1361 ZoneUserBindingHelper helper = null;
1362 synchronized (mLockHelper) {
1363 if (mZoneUserBindingHelper == null) {
1364 Log.w(TAG_USER, "implementation is not delegated");
1365 return false;
1366 }
1367 helper = mZoneUserBindingHelper;
1368 }
1369 return helper.isPassengerDisplayAvailable();
1370 }
1371
1372 /**
1373 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1374 * zone is returned.
1375 *
1376 * @param occupantType The type of an occupant.
1377 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1378 * if not found.
1379 */
1380 private int getZoneId(@OccupantTypeEnum int occupantType) {
1381 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1382 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1383 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001384}