blob: 18e480d18c21dbc1338e37d3eb6cec4541bc5055 [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;
felipeal312416a2020-04-14 12:28:24 -070059import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070060import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080061import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080062import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070063
64import com.android.car.CarServiceBase;
Eric Jeongc91f9452019-08-30 15:04:21 -070065import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080066import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080067import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070068import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070069import com.android.internal.car.EventLogTags;
Felipe Leme5528ff72020-02-10 19:05:14 -080070import com.android.internal.os.IResultReceiver;
felipeal2a84d512020-04-06 18:52:15 -070071import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070072import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070073import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070074
75import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080076import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070077import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070078import java.util.Iterator;
79import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000080import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070081import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070082import java.util.concurrent.CountDownLatch;
83import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070084
85/**
86 * User service for cars. Manages users at boot time. Including:
87 *
88 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070089 * <li> Creates a user used as driver.
90 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070091 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070092 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070093 * <ol/>
94 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070095public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080096
felipealf7368962020-04-16 12:55:19 -070097 private static final String TAG = TAG_USER;
98
Felipe Lemeabbf2da2020-02-24 18:25:29 -080099 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800100 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800101 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800102 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800103 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800104 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800105 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
106 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800107
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700108 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700109 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700110 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700111 private final UserManager mUserManager;
112 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700113 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114
Eric Jeongc91f9452019-08-30 15:04:21 -0700115 private final Object mLockUser = new Object();
116 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800117 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700118 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800119 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700120 // Only one passenger is supported.
121 @GuardedBy("mLockUser")
122 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700123 /**
124 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800125 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700126 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700127 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700128 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
129 /**
130 * Keep the list of background users started here. This is wholly for debugging purpose.
131 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700132 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700133 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
134
Felipe Leme58412202020-01-09 13:45:33 -0800135 private final UserHalService mHal;
136
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700137 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
138 private final HandlerThread mHandlerThread;
139 private final Handler mHandler;
140
Felipe Leme5528ff72020-02-10 19:05:14 -0800141 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800142 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700143 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800144 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700145 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800146
147 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800148 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700149 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800150 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700151 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800152
Mayank Garg7a114c82020-04-08 21:25:06 -0700153 /**
154 * User Id for the user switch in process, if any.
155 */
156 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700157 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700158 /**
159 * Request Id for the user switch in process, if any.
160 */
161 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700162 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700163 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
164
Eric Jeongc91f9452019-08-30 15:04:21 -0700165 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
166 new CopyOnWriteArrayList<>();
167
felipeal61ce3732020-04-03 11:01:00 -0700168 @Nullable
169 @GuardedBy("mLockUser")
170 private UserInfo mInitialUser;
171
felipeale8c5dce2020-04-15 11:27:06 -0700172 private final UserMetrics mUserMetrics = new UserMetrics();
173
Eric Jeongc91f9452019-08-30 15:04:21 -0700174 /** Interface for callbaks related to passenger activities. */
175 public interface PassengerCallback {
176 /** Called when passenger is started at a certain zone. */
177 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
178 /** Called when passenger is stopped. */
179 void onPassengerStopped(@UserIdInt int passengerId);
180 }
181
182 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
183 public interface ZoneUserBindingHelper {
184 /** Gets occupant zones corresponding to the occupant type. */
185 @NonNull
186 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
187 /** Assigns the user to the occupant zone. */
188 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
189 /** Makes the occupant zone unoccupied. */
190 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
191 /** Returns whether there is a passenger display. */
192 boolean isPassengerDisplayAvailable();
193 }
194
195 private final Object mLockHelper = new Object();
196 @GuardedBy("mLockHelper")
197 private ZoneUserBindingHelper mZoneUserBindingHelper;
198
Felipe Leme58412202020-01-09 13:45:33 -0800199 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
200 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700201 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700202 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
203 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700204 }
205 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800206 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700207 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700208 mAm = am;
209 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700210 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700211 mLastPassengerId = UserHandle.USER_NULL;
212 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700213 mHandlerThread = new HandlerThread(CarUserService.class.getSimpleName());
214 mHandlerThread.start();
215 mHandler = new Handler(mHandlerThread.getLooper());
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700216 }
217
218 @Override
219 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700220 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
221 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700222 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700223 }
224
225 @Override
226 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700227 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
228 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700229 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700230 }
231
232 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700233 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700234 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700235 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800236 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700237 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700238 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700239 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700240 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
241 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700242 }
243 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
244 List<UserInfo> allDrivers = getAllDrivers();
245 int driversSize = allDrivers.size();
246 writer.println("NumberOfDrivers: " + driversSize);
247 for (int i = 0; i < driversSize; i++) {
248 int driverId = allDrivers.get(i).id;
249 writer.print(indent + "#" + i + ": id=" + driverId);
250 List<UserInfo> passengers = getPassengers(driverId);
251 int passengersSize = passengers.size();
252 writer.print(" NumberPassengers: " + passengersSize);
253 if (passengersSize > 0) {
254 writer.print(" [");
255 for (int j = 0; j < passengersSize; j++) {
256 writer.print(passengers.get(j).id);
257 if (j < passengersSize - 1) {
258 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700259 }
felipeal2d0483c2019-11-02 14:07:22 -0700260 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700261 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700262 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700263 writer.println();
264 }
265 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
266 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
267 writer.printf("Initial user: %s\n", mInitialUser);
268 writer.println("Relevant overlayable properties");
269 Resources res = mContext.getResources();
270 writer.printf("%sowner_name=%s\n", indent,
271 res.getString(com.android.internal.R.string.owner_name));
272 writer.printf("%sdefault_guest_name=%s\n", indent,
273 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700274 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700275 writer.printf("Request Id for the user switch in process=%d\n ",
276 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700277
278 dumpUserMetrics(writer);
279 }
280
281 /**
282 * Dumps user metrics.
283 */
284 public void dumpUserMetrics(@NonNull PrintWriter writer) {
285 mUserMetrics.dump(writer);
286 }
287
288 /**
289 * Dumps first user unlocking time.
290 */
291 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
292 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700293 }
294
295 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
296 CountDownLatch latch = new CountDownLatch(1);
297 mHandler.post(() -> {
298 handleDumpUserLifecycleListeners(writer);
299 handleDumpAppLifecycleListeners(writer, indent);
300 latch.countDown();
301 });
302 int timeout = 5;
303 try {
304 if (!latch.await(timeout, TimeUnit.SECONDS)) {
305 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
306 timeout);
307 }
308 } catch (InterruptedException e) {
309 Thread.currentThread().interrupt();
310 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
311 }
312 }
313
314 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
315 if (mUserLifecycleListeners.isEmpty()) {
316 writer.println("No user lifecycle listeners");
317 return;
318 }
319 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
320 for (UserLifecycleListener listener : mUserLifecycleListeners) {
321 writer.printf("Listener %s\n", listener);
322 }
323 }
324
325 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
326 int numberListeners = mAppLifecycleListeners.size();
327 if (numberListeners == 0) {
328 writer.println("No lifecycle listeners");
329 return;
330 }
331 writer.printf("%d lifecycle listeners\n", numberListeners);
332 for (int i = 0; i < numberListeners; i++) {
333 int uid = mAppLifecycleListeners.keyAt(i);
334 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
335 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800336 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700337 }
338
339 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800340 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
341 *
342 * @param name The name of the driver to be created.
343 * @param admin Whether the created driver will be an admin.
344 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
345 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700346 */
347 @Override
348 @Nullable
349 public UserInfo createDriver(@NonNull String name, boolean admin) {
350 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000351 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700352 if (admin) {
353 return createNewAdminUser(name);
354 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700355 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700356 }
357
358 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800359 * Creates a passenger who is a profile of the given driver.
360 *
361 * @param name The name of the passenger to be created.
362 * @param driverId User id of the driver under whom a passenger is created.
363 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
364 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700365 */
366 @Override
367 @Nullable
368 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
369 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000370 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700371 UserInfo driver = mUserManager.getUserInfo(driverId);
372 if (driver == null) {
373 Log.w(TAG_USER, "the driver is invalid");
374 return null;
375 }
376 if (driver.isGuest()) {
377 Log.w(TAG_USER, "a guest driver cannot create a passenger");
378 return null;
379 }
Bookatz42fb1a62019-10-30 11:45:01 -0700380 UserInfo user = mUserManager.createProfileForUser(name,
381 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700382 if (user == null) {
383 // Couldn't create user, most likely because there are too many.
384 Log.w(TAG_USER, "can't create a profile for user" + driverId);
385 return null;
386 }
387 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700388 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700389 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700390 return user;
391 }
392
393 /**
394 * @see CarUserManager.switchDriver
395 */
396 @Override
397 public boolean switchDriver(@UserIdInt int driverId) {
398 checkManageUsersPermission("switchDriver");
399 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
400 // System user doesn't associate with real person, can not be switched to.
401 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
402 return false;
403 }
404 int userSwitchable = mUserManager.getUserSwitchability();
405 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
406 Log.w(TAG_USER, "current process is not allowed to switch user");
407 return false;
408 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700409 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700410 // The current user is already the given user.
411 return true;
412 }
413 try {
414 return mAm.switchUser(driverId);
415 } catch (RemoteException e) {
416 // ignore
417 Log.w(TAG_USER, "error while switching user", e);
418 }
419 return false;
420 }
421
422 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800423 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
424 *
425 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700426 */
427 @Override
428 @NonNull
429 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700430 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700431 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
432 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700433 }
434
435 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800436 * Returns all passengers under the given driver.
437 *
438 * @param driverId User id of a driver.
439 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700440 */
441 @Override
442 @NonNull
443 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700444 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700445 return getUsers((user) -> {
446 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
447 && user.profileGroupId == driverId;
448 });
449 }
450
451 /**
452 * @see CarUserManager.startPassenger
453 */
454 @Override
455 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
456 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700457 synchronized (mLockUser) {
458 try {
459 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
460 Log.w(TAG_USER, "could not start passenger");
461 return false;
462 }
463 } catch (RemoteException e) {
464 // ignore
465 Log.w(TAG_USER, "error while starting passenger", e);
466 return false;
467 }
468 if (!assignUserToOccupantZone(passengerId, zoneId)) {
469 Log.w(TAG_USER, "could not assign passenger to zone");
470 return false;
471 }
472 mLastPassengerId = passengerId;
473 }
474 for (PassengerCallback callback : mPassengerCallbacks) {
475 callback.onPassengerStarted(passengerId, zoneId);
476 }
477 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700478 }
479
480 /**
481 * @see CarUserManager.stopPassenger
482 */
483 @Override
484 public boolean stopPassenger(@UserIdInt int passengerId) {
485 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700486 return stopPassengerInternal(passengerId, true);
487 }
488
489 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
490 synchronized (mLockUser) {
491 UserInfo passenger = mUserManager.getUserInfo(passengerId);
492 if (passenger == null) {
493 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
494 return false;
495 }
496 if (mLastPassengerId != passengerId) {
497 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
498 return true;
499 }
500 if (checkCurrentDriver) {
501 int currentUser = ActivityManager.getCurrentUser();
502 if (passenger.profileGroupId != currentUser) {
503 Log.w(TAG_USER, "passenger " + passengerId
504 + " is not a profile of the current user");
505 return false;
506 }
507 }
508 // Passenger is a profile, so cannot be stopped through activity manager.
509 // Instead, activities started by the passenger are stopped and the passenger is
510 // unassigned from the zone.
511 stopAllTasks(passengerId);
512 if (!unassignUserFromOccupantZone(passengerId)) {
513 Log.w(TAG_USER, "could not unassign user from occupant zone");
514 return false;
515 }
516 mLastPassengerId = UserHandle.USER_NULL;
517 }
518 for (PassengerCallback callback : mPassengerCallbacks) {
519 callback.onPassengerStopped(passengerId);
520 }
521 return true;
522 }
523
524 private void stopAllTasks(@UserIdInt int userId) {
525 try {
526 for (StackInfo info : mAm.getAllStackInfos()) {
527 for (int i = 0; i < info.taskIds.length; i++) {
528 if (info.taskUserIds[i] == userId) {
529 int taskId = info.taskIds[i];
530 if (!mAm.removeTask(taskId)) {
531 Log.w(TAG_USER, "could not remove task " + taskId);
532 }
533 }
534 }
535 }
536 } catch (RemoteException e) {
537 Log.e(TAG_USER, "could not get stack info", e);
538 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700539 }
540
Felipe Leme5528ff72020-02-10 19:05:14 -0800541 @Override
542 public void setLifecycleListenerForUid(IResultReceiver listener) {
543 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700544 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800545 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
546
547 try {
548 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
549 } catch (RemoteException e) {
550 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
551 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700552 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800553 }
554
555 private void onListenerDeath(int uid) {
556 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700557 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800558 }
559
560 @Override
561 public void resetLifecycleListenerForUid() {
562 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700563 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800564 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700565 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800566 }
567
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800568 @Override
569 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800570 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700571 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
572 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800573 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700574 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800575 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800576 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700577 Bundle resultData = null;
578 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700579 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
580 status, resp.action, resp.userToSwitchOrCreate.userId,
581 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700582 switch (resp.action) {
583 case InitialUserInfoResponseAction.SWITCH:
584 resultData = new Bundle();
585 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
586 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
587 break;
588 case InitialUserInfoResponseAction.CREATE:
589 resultData = new Bundle();
590 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
591 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
592 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
593 break;
594 case InitialUserInfoResponseAction.DEFAULT:
595 resultData = new Bundle();
596 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
597 break;
598 default:
599 // That's ok, it will be the same as DEFAULT...
600 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800601 }
felipeal312416a2020-04-14 12:28:24 -0700602 } else {
603 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800604 }
Mayank Garg0e239142020-04-14 19:16:31 -0700605 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800606 });
607 }
608
Felipe Lemee3cab982020-03-12 11:39:29 -0700609 /**
felipeal61ce3732020-04-03 11:01:00 -0700610 * Gets the initial foreground user after the device boots or resumes from suspension.
611 *
612 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
613 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
614 * method returns {@code null}.
615 *
616 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
617 * (like switching to the last active user), and this method will return the result of such
618 * operation.
619 *
620 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
621 * {@code null}.
622 *
623 * @hide
624 */
625 @Nullable
626 public UserInfo getInitialUser() {
627 checkInteractAcrossUsersPermission("getInitialUser");
628 synchronized (mLockUser) {
629 return mInitialUser;
630 }
631 }
632
633 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
634 // some reason passing the whole UserInfo through a raw binder transaction is not working.
635 /**
636 * Sets the initial foreground user after the device boots or resumes from suspension.
637 */
638 public void setInitialUser(@UserIdInt int userId) {
639 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
640 : mUserManager.getUserInfo(userId);
641 setInitialUser(initialUser);
642 }
643
644 /**
645 * Sets the initial foreground user after the device boots or resumes from suspension.
646 */
647 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700648 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
649 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700650 synchronized (mLockUser) {
651 mInitialUser = user;
652 }
653 if (user == null) {
654 // This mean InitialUserSetter failed and could not fallback, so the initial user was
655 // not switched (and most likely is SYSTEM_USER).
656 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
657 Log.wtf(TAG_USER, "Initial user set to null");
658 }
659 }
660
661 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700662 * Calls the User HAL to get the initial user info.
663 *
664 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
665 * @param callback callback to receive the results.
666 */
667 public void getInitialUserInfo(int requestType,
668 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700669 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
670 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700671 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700672 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700673 UsersInfo usersInfo = getUsersInfo();
674 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
675 }
676
677 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700678 * Calls the User HAL to switch user.
679 *
Mayank Garge19c2922020-03-30 18:05:53 -0700680 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700681 * @param timeoutMs - timeout for HAL to wait
682 * @param receiver - receiver for the results
683 */
Mayank Garge19c2922020-03-30 18:05:53 -0700684 @Override
685 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
Mayank Garg59f22192020-03-27 00:51:45 -0700686 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700687 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId,
688 timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700689 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700690 Objects.requireNonNull(receiver);
691 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700692 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700693
felipealf7368962020-04-16 12:55:19 -0700694 int currentUser = ActivityManager.getCurrentUser();
695 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700696 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
697 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
698 }
699 int resultStatus = CarUserManager.USER_SWITCH_STATUS_ALREADY_REQUESTED_USER;
700 sendResult(receiver, resultStatus, null);
701 return;
702 }
703
Mayank Garg7a114c82020-04-08 21:25:06 -0700704 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700705 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
706 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
707 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
708 }
709
710 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700711 int resultStatus = CarUserManager.USER_SWITCH_STATUS_ANOTHER_REQUEST_IN_PROCESS;
712 sendResult(receiver, resultStatus, null);
Mayank Garg7a114c82020-04-08 21:25:06 -0700713 return;
714 }
715 }
716
Mayank Garg59f22192020-03-27 00:51:45 -0700717 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700718 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700719 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700720 halTargetUser.userId = targetUser.id;
721 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
722 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700723 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
724 Log.d(TAG, "switch response: status="
725 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
726 }
727
Mayank Garg59f22192020-03-27 00:51:45 -0700728 Bundle resultData = null;
Mayank Garge19c2922020-03-30 18:05:53 -0700729 int resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700730
731 if (status != HalCallback.STATUS_OK) {
732 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
733 Log.w(TAG, "invalid callback status ("
734 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
735 + resp);
736 sendResult(receiver, resultStatus, resultData);
737 return;
738 }
739 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status,
740 resp.status, resp.errorMessage);
741
742 if (resp.errorMessage != null) {
743 resultData = new Bundle();
744 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
745 resp.errorMessage);
746 }
747 switch (resp.status) {
748 case SwitchUserStatus.SUCCESS:
749 boolean result;
750 try {
751 result = mAm.switchUser(targetUserId);
752 if (result) {
753 resultStatus = CarUserManager.USER_SWITCH_STATUS_SUCCESSFUL;
754 updateUserSwitchInProcess(targetUserId, resp);
755 } else {
756 resultStatus = CarUserManager.USER_SWITCH_STATUS_ANDROID_FAILURE;
757 postSwitchHalResponse(resp.requestId, targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700758 }
felipealf7368962020-04-16 12:55:19 -0700759 } catch (RemoteException e) {
760 // ignore
761 Log.w(TAG_USER,
762 "error while switching user " + targetUser.toFullString(), e);
763 }
764 break;
765 case SwitchUserStatus.FAILURE:
766 // HAL failed to switch user
767 resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_FAILURE;
768 break;
Mayank Garg59f22192020-03-27 00:51:45 -0700769 }
Mayank Garg0e239142020-04-14 19:16:31 -0700770 sendResult(receiver, resultStatus, resultData);
Mayank Garg59f22192020-03-27 00:51:45 -0700771 });
772 }
773
Mayank Garg0e239142020-04-14 19:16:31 -0700774 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
775 @Nullable Bundle resultData) {
776 try {
777 receiver.send(resultCode, resultData);
778 } catch (RemoteException e) {
779 // ignore
780 Log.w(TAG_USER, "error while sending results", e);
781 }
782 }
783
Mayank Garg7a114c82020-04-08 21:25:06 -0700784 private void updateUserSwitchInProcess(@UserIdInt int targetUserId,
785 @NonNull SwitchUserResponse resp) {
786 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700787 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700788 // Some other user switch is in process.
789 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
felipealf7368962020-04-16 12:55:19 -0700790 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
Mayank Garg7a114c82020-04-08 21:25:06 -0700791 + " is in process. Sending failed android post switch response for it "
792 + " as new user switch is requested for user: " + targetUserId);
793 }
felipealf7368962020-04-16 12:55:19 -0700794 postSwitchHalResponse(mRequestIdForUserSwitchInProcess,
795 mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700796 }
felipealf7368962020-04-16 12:55:19 -0700797 mUserIdForUserSwitchInProcess = targetUserId;
Mayank Garg7a114c82020-04-08 21:25:06 -0700798 mRequestIdForUserSwitchInProcess = resp.requestId;
799 }
800 }
801
802 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
803 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
804 UsersInfo usersInfo = getUsersInfo();
805 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
806 new android.hardware.automotive.vehicle.V2_0.UserInfo();
807 halTargetUser.userId = targetUser.id;
808 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700809 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
810 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700811 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
812 }
813
Mayank Garg59f22192020-03-27 00:51:45 -0700814 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700815 * Checks if the User HAL is supported.
816 */
817 public boolean isUserHalSupported() {
818 return mHal.isSupported();
819 }
820
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800821 // TODO(b/144120654): use helper to generate UsersInfo
822 private UsersInfo getUsersInfo() {
823 UserInfo currentUser;
824 try {
825 currentUser = mAm.getCurrentUser();
826 } catch (RemoteException e) {
827 // shouldn't happen
828 throw new IllegalStateException("Could not get current user: ", e);
829 }
830 List<UserInfo> existingUsers = mUserManager.getUsers();
831 int size = existingUsers.size();
832
833 UsersInfo usersInfo = new UsersInfo();
834 usersInfo.numberUsers = size;
835 usersInfo.currentUser.userId = currentUser.id;
836 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
837
838 for (int i = 0; i < size; i++) {
839 UserInfo androidUser = existingUsers.get(i);
840 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
841 new android.hardware.automotive.vehicle.V2_0.UserInfo();
842 halUser.userId = androidUser.id;
843 halUser.flags = UserHalHelper.convertFlags(androidUser);
844 usersInfo.existingUsers.add(halUser);
845 }
846
847 return usersInfo;
848 }
849
Eric Jeong1545f3b2019-09-16 13:56:52 -0700850 /** Returns whether the given user is a system user. */
851 private static boolean isSystemUser(@UserIdInt int userId) {
852 return userId == UserHandle.USER_SYSTEM;
853 }
854
Keun young Park13a7a822019-04-04 15:53:08 -0700855 private void updateDefaultUserRestriction() {
856 // We want to set restrictions on system and guest users only once. These are persisted
857 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
858 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700859 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
860 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700861 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700862 // Only apply the system user restrictions if the system user is headless.
863 if (UserManager.isHeadlessSystemUserMode()) {
864 setSystemUserRestrictions();
865 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700866 Settings.Global.putInt(mContext.getContentResolver(),
867 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700868 }
869
Eric Jeong1545f3b2019-09-16 13:56:52 -0700870 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700871 return !mUserManager.getUserInfo(userId).isEphemeral();
872 }
873
Antonio Kantekc8114752020-03-05 21:37:39 -0800874 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800875 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
876 */
877 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
878 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700879 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800880 }
881
882 /**
883 * Removes previously added {@link UserLifecycleListener}.
884 */
885 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
886 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700887 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800888 }
889
Eric Jeongc91f9452019-08-30 15:04:21 -0700890 /** Adds callback to listen to passenger activity events. */
891 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000892 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700893 mPassengerCallbacks.add(callback);
894 }
895
896 /** Removes previously added callback to listen passenger events. */
897 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000898 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700899 mPassengerCallbacks.remove(callback);
900 }
901
902 /** Sets the implementation of ZoneUserBindingHelper. */
903 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
904 synchronized (mLockHelper) {
905 mZoneUserBindingHelper = helper;
906 }
907 }
908
felipeal98900c82020-04-09 09:05:02 -0700909 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800910 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700911 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700912 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700913 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700914 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
915 updateDefaultUserRestriction();
916 tasks = new ArrayList<>(mUser0UnlockTasks);
917 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700918 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700919 }
920 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700921 Integer user = userId;
922 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700923 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700924 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700925 mBackgroundUsersToRestart.remove(user);
926 mBackgroundUsersToRestart.add(0, user);
927 }
928 // -1 for user 0
929 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700930 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700931 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700932 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700933 + ", dropping least recently user from restart list:" + userToDrop);
934 // Drop the least recently used user.
935 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
936 }
937 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800938 }
939 }
940 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700941 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800942 for (Runnable r : tasks) {
943 r.run();
944 }
945 }
946 }
947
948 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700949 * Starts all background users that were active in system.
950 *
Keun young Parkfb656372019-03-12 18:37:55 -0700951 * @return list of background users started successfully.
952 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700953 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700954 public ArrayList<Integer> startAllBackgroundUsers() {
955 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700956 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700957 users = new ArrayList<>(mBackgroundUsersToRestart);
958 mBackgroundUsersRestartedHere.clear();
959 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700960 }
961 ArrayList<Integer> startedUsers = new ArrayList<>();
962 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700963 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700964 continue;
965 }
966 try {
967 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700968 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
969 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700970 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700971 } else if (mAm.unlockUser(user, null, null, null)) {
972 startedUsers.add(user);
973 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700974 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700975 if (mUserManager.isUserRunning(user)) {
976 // add to started list so that it can be stopped later.
977 startedUsers.add(user);
978 }
Keun young Parkfb656372019-03-12 18:37:55 -0700979 }
980 }
981 } catch (RemoteException e) {
982 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700983 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700984 }
985 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700986 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700987 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700988 ArrayList<Integer> usersToRemove = new ArrayList<>();
989 for (Integer user : mBackgroundUsersToRestart) {
990 if (!startedUsers.contains(user)) {
991 usersToRemove.add(user);
992 }
993 }
994 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
995 }
Keun young Parkfb656372019-03-12 18:37:55 -0700996 return startedUsers;
997 }
998
999 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001000 * Stops all background users that were active in system.
1001 *
1002 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001003 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001004 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001005 if (userId == UserHandle.USER_SYSTEM) {
1006 return false;
1007 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001008 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001009 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001010 return false;
1011 }
1012 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001013 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001014 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001015 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001016 Integer user = userId;
1017 mBackgroundUsersRestartedHere.remove(user);
1018 }
1019 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1020 return false;
1021 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001022 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001023 return false;
1024 }
1025 } catch (RemoteException e) {
1026 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001027 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001028 }
1029 return true;
1030 }
1031
1032 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001033 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001034 */
felipeale8c5dce2020-04-15 11:27:06 -07001035 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1036 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1037 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001038
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001039 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001040 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1041 onUserSwitching(userId);
1042 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1043 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001044 }
1045
felipeale8c5dce2020-04-15 11:27:06 -07001046 // ...then notify listeners.
1047 UserLifecycleEvent event = new UserLifecycleEvent(eventType, userId);
1048
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001049 mHandler.post(() -> {
1050 handleNotifyServiceUserLifecycleListeners(event);
1051 handleNotifyAppUserLifecycleListeners(event);
1052 });
felipeale8c5dce2020-04-15 11:27:06 -07001053
1054 // Finally, update metrics.
1055 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1056 }
1057
1058 /**
1059 * Sets the first user unlocking metrics.
1060 */
1061 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1062 int halResponseTime) {
1063 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001064 }
1065
Mayank Garg7a114c82020-04-08 21:25:06 -07001066 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001067 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
1068 || mUserIdForUserSwitchInProcess != userId) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001069 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1070 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1071 }
1072 return;
1073 }
felipealf7368962020-04-16 12:55:19 -07001074 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1075 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -07001076 mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
1077 }
1078
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001079 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1080 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001081 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001082 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1083 Log.d(TAG_USER, "No app listener to be notified of " + event);
1084 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001085 return;
1086 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001087 // Must use a different TimingsTraceLog because it's another thread
1088 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1089 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1090 }
felipeal2a84d512020-04-06 18:52:15 -07001091 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001092 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1093 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1094 for (int i = 0; i < listenersSize; i++) {
1095 int uid = mAppLifecycleListeners.keyAt(i);
1096 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1097 Bundle data = new Bundle();
1098 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
1099 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
1100 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
felipeal2a84d512020-04-06 18:52:15 -07001101 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001102 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001103 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001104 try {
felipeal2a84d512020-04-06 18:52:15 -07001105 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001106 listener.send(userId, data);
1107 } catch (RemoteException e) {
1108 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1109 } finally {
1110 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001111 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001112 }
1113 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001114 }
1115
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001116 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001117 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1118 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001119 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001120 return;
felipeal2a84d512020-04-06 18:52:15 -07001121 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1122 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1123 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001124 }
felipeal2a84d512020-04-06 18:52:15 -07001125
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001126 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1127 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001128 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001129 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001130 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001131 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001132 listener.onEvent(event);
1133 } catch (RuntimeException e) {
1134 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001135 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001136 } finally {
1137 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001138 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001139 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001140 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001141 }
1142
felipeal98900c82020-04-09 09:05:02 -07001143 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001144 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1145 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001146 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001147
Felipe Lemef45ee502019-12-19 10:00:14 -08001148 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001149 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001150 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001151 if (mLastPassengerId != UserHandle.USER_NULL) {
1152 stopPassengerInternal(mLastPassengerId, false);
1153 }
1154 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1155 setupPassengerUser();
1156 startFirstPassenger(userId);
1157 }
felipeal98900c82020-04-09 09:05:02 -07001158 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001159 }
1160
1161 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001162 * 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 -08001163 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001164 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001165 * @param r Runnable to run.
1166 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001167 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001168 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001169 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001170 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001171 if (mUser0Unlocked) {
1172 runNow = true;
1173 } else {
1174 mUser0UnlockTasks.add(r);
1175 }
1176 }
1177 if (runNow) {
1178 r.run();
1179 }
1180 }
1181
Keun young Parkf3523cd2019-04-08 10:09:17 -07001182 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001183 @NonNull
1184 ArrayList<Integer> getBackgroundUsersToRestart() {
1185 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001186 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001187 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1188 }
1189 return backgroundUsersToRestart;
1190 }
1191
Ying Zheng1ab32b62018-06-26 12:47:26 -07001192 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001193 // Disable Location service for system user.
1194 LocationManager locationManager =
1195 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001196 locationManager.setLocationEnabledForUser(
1197 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001198 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001199
1200 /**
1201 * Creates a new user on the system, the created user would be granted admin role.
1202 *
1203 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001204 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001205 */
1206 @Nullable
1207 private UserInfo createNewAdminUser(String name) {
1208 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1209 // Only admins or system user can create other privileged users.
1210 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1211 return null;
1212 }
1213
1214 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1215 if (user == null) {
1216 // Couldn't create user, most likely because there are too many.
1217 Log.w(TAG_USER, "can't create admin user.");
1218 return null;
1219 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001220 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001221
1222 return user;
1223 }
1224
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001225 /**
1226 * Assigns a default icon to a user according to the user's id.
1227 *
1228 * @param userInfo User whose avatar is set to default icon.
1229 * @return Bitmap of the user icon.
1230 */
1231 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1232 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1233 Bitmap bitmap = UserIcons.convertToBitmap(
1234 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1235 mUserManager.setUserIcon(userInfo.id, bitmap);
1236 return bitmap;
1237 }
1238
Eric Jeong1545f3b2019-09-16 13:56:52 -07001239 private interface UserFilter {
1240 boolean isEligibleUser(UserInfo user);
1241 }
1242
1243 /** Returns all users who are matched by the given filter. */
1244 private List<UserInfo> getUsers(UserFilter filter) {
1245 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1246
1247 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1248 UserInfo user = iterator.next();
1249 if (!filter.isEligibleUser(user)) {
1250 iterator.remove();
1251 }
1252 }
1253 return users;
1254 }
1255
1256 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001257 * Enforces that apps which have the
1258 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1259 * can make certain calls to the CarUserManager.
1260 *
1261 * @param message used as message if SecurityException is thrown.
1262 * @throws SecurityException if the caller is not system or root.
1263 */
1264 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001265 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1266 }
1267
1268 private static void checkManageUsersOrDumpPermission(String message) {
1269 checkAtLeastOnePermission(message,
1270 android.Manifest.permission.MANAGE_USERS,
1271 android.Manifest.permission.DUMP);
1272 }
1273
Felipe Leme5528ff72020-02-10 19:05:14 -08001274 private void checkInteractAcrossUsersPermission(String message) {
1275 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1276 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1277 }
1278
felipeal2d0483c2019-11-02 14:07:22 -07001279 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001280 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001281 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1282 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001283 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001284 }
1285 }
1286
felipeal2d0483c2019-11-02 14:07:22 -07001287 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1288 for (String permission : permissions) {
1289 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1290 /* exported = */ true)
1291 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1292 return true;
1293 }
1294 }
1295 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001296 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001297
1298 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1299 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1300 // Count all users that are managed profiles of the given user.
1301 int managedProfilesCount = 0;
1302 for (UserInfo user : users) {
1303 if (user.isManagedProfile() && user.profileGroupId == userId) {
1304 managedProfilesCount++;
1305 }
1306 }
1307 return managedProfilesCount;
1308 }
1309
1310 /**
1311 * Starts the first passenger of the given driver and assigns the passenger to the front
1312 * passenger zone.
1313 *
1314 * @param driverId User id of the driver.
1315 * @return whether it succeeds.
1316 */
1317 private boolean startFirstPassenger(@UserIdInt int driverId) {
1318 int zoneId = getAvailablePassengerZone();
1319 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1320 Log.w(TAG_USER, "passenger occupant zone is not found");
1321 return false;
1322 }
1323 List<UserInfo> passengers = getPassengers(driverId);
1324 if (passengers.size() < 1) {
1325 Log.w(TAG_USER, "passenger is not found");
1326 return false;
1327 }
1328 // Only one passenger is supported. If there are two or more passengers, the first passenger
1329 // is chosen.
1330 int passengerId = passengers.get(0).id;
1331 if (!startPassenger(passengerId, zoneId)) {
1332 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1333 return false;
1334 }
1335 return true;
1336 }
1337
1338 private int getAvailablePassengerZone() {
1339 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1340 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1341 for (int occupantType : occupantTypes) {
1342 int zoneId = getZoneId(occupantType);
1343 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1344 return zoneId;
1345 }
1346 }
1347 return OccupantZoneInfo.INVALID_ZONE_ID;
1348 }
1349
1350 /**
1351 * Creates a new passenger user when there is no passenger user.
1352 */
1353 private void setupPassengerUser() {
1354 int currentUser = ActivityManager.getCurrentUser();
1355 int profileCount = getNumberOfManagedProfiles(currentUser);
1356 if (profileCount > 0) {
1357 Log.w(TAG_USER, "max profile of user" + currentUser
1358 + " is exceeded: current profile count is " + profileCount);
1359 return;
1360 }
1361 // TODO(b/140311342): Use resource string for the default passenger name.
1362 UserInfo passenger = createPassenger("Passenger", currentUser);
1363 if (passenger == null) {
1364 // Couldn't create user, most likely because there are too many.
1365 Log.w(TAG_USER, "cannot create a passenger user");
1366 return;
1367 }
1368 }
1369
1370 @NonNull
1371 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1372 ZoneUserBindingHelper helper = null;
1373 synchronized (mLockHelper) {
1374 if (mZoneUserBindingHelper == null) {
1375 Log.w(TAG_USER, "implementation is not delegated");
1376 return new ArrayList<OccupantZoneInfo>();
1377 }
1378 helper = mZoneUserBindingHelper;
1379 }
1380 return helper.getOccupantZones(occupantType);
1381 }
1382
1383 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1384 ZoneUserBindingHelper helper = null;
1385 synchronized (mLockHelper) {
1386 if (mZoneUserBindingHelper == null) {
1387 Log.w(TAG_USER, "implementation is not delegated");
1388 return false;
1389 }
1390 helper = mZoneUserBindingHelper;
1391 }
1392 return helper.assignUserToOccupantZone(userId, zoneId);
1393 }
1394
1395 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1396 ZoneUserBindingHelper helper = null;
1397 synchronized (mLockHelper) {
1398 if (mZoneUserBindingHelper == null) {
1399 Log.w(TAG_USER, "implementation is not delegated");
1400 return false;
1401 }
1402 helper = mZoneUserBindingHelper;
1403 }
1404 return helper.unassignUserFromOccupantZone(userId);
1405 }
1406
1407 private boolean isPassengerDisplayAvailable() {
1408 ZoneUserBindingHelper helper = null;
1409 synchronized (mLockHelper) {
1410 if (mZoneUserBindingHelper == null) {
1411 Log.w(TAG_USER, "implementation is not delegated");
1412 return false;
1413 }
1414 helper = mZoneUserBindingHelper;
1415 }
1416 return helper.isPassengerDisplayAvailable();
1417 }
1418
1419 /**
1420 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1421 * zone is returned.
1422 *
1423 * @param occupantType The type of an occupant.
1424 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1425 * if not found.
1426 */
1427 private int getZoneId(@OccupantTypeEnum int occupantType) {
1428 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1429 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1430 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001431}