blob: b38343c5496675ede894d625e3721c49d7ee6b7b [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
Felipe Lemeabbf2da2020-02-24 18:25:29 -080097 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080098 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -080099 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800100 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800101 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800102 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800103 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
104 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800105
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700106 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700107 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700108 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700109 private final UserManager mUserManager;
110 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700111 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700112
Eric Jeongc91f9452019-08-30 15:04:21 -0700113 private final Object mLockUser = new Object();
114 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800115 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700116 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800117 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700118 // Only one passenger is supported.
119 @GuardedBy("mLockUser")
120 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700121 /**
122 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800123 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700124 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700125 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700126 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
127 /**
128 * Keep the list of background users started here. This is wholly for debugging purpose.
129 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700130 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700131 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
132
Felipe Leme58412202020-01-09 13:45:33 -0800133 private final UserHalService mHal;
134
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700135 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
136 private final HandlerThread mHandlerThread;
137 private final Handler mHandler;
138
Felipe Leme5528ff72020-02-10 19:05:14 -0800139 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800140 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700141 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800142 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700143 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800144
145 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800146 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800148 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700149 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800150
Mayank Garg7a114c82020-04-08 21:25:06 -0700151 /**
152 * User Id for the user switch in process, if any.
153 */
154 @GuardedBy("mLockUser")
155 private int mUserSwitchInProcess = UserHandle.USER_NULL;
156 /**
157 * Request Id for the user switch in process, if any.
158 */
159 @GuardedBy("mLockUser")
160 private int mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
Felipe Lemee3cab982020-03-12 11:39:29 -0700161 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
162
Eric Jeongc91f9452019-08-30 15:04:21 -0700163 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
164 new CopyOnWriteArrayList<>();
165
felipeal61ce3732020-04-03 11:01:00 -0700166 @Nullable
167 @GuardedBy("mLockUser")
168 private UserInfo mInitialUser;
169
felipeale8c5dce2020-04-15 11:27:06 -0700170 private final UserMetrics mUserMetrics = new UserMetrics();
171
Eric Jeongc91f9452019-08-30 15:04:21 -0700172 /** Interface for callbaks related to passenger activities. */
173 public interface PassengerCallback {
174 /** Called when passenger is started at a certain zone. */
175 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
176 /** Called when passenger is stopped. */
177 void onPassengerStopped(@UserIdInt int passengerId);
178 }
179
180 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
181 public interface ZoneUserBindingHelper {
182 /** Gets occupant zones corresponding to the occupant type. */
183 @NonNull
184 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
185 /** Assigns the user to the occupant zone. */
186 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
187 /** Makes the occupant zone unoccupied. */
188 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
189 /** Returns whether there is a passenger display. */
190 boolean isPassengerDisplayAvailable();
191 }
192
193 private final Object mLockHelper = new Object();
194 @GuardedBy("mLockHelper")
195 private ZoneUserBindingHelper mZoneUserBindingHelper;
196
Felipe Leme58412202020-01-09 13:45:33 -0800197 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
198 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700199 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700200 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
201 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700202 }
203 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800204 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700205 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700206 mAm = am;
207 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700208 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700209 mLastPassengerId = UserHandle.USER_NULL;
210 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700211 mHandlerThread = new HandlerThread(CarUserService.class.getSimpleName());
212 mHandlerThread.start();
213 mHandler = new Handler(mHandlerThread.getLooper());
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700214 }
215
216 @Override
217 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700218 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
219 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700220 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700221 }
222
223 @Override
224 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700225 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
226 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700227 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700228 }
229
230 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700231 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700232 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700233 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800234 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700235 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700236 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700237 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700238 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
239 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700240 }
241 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
242 List<UserInfo> allDrivers = getAllDrivers();
243 int driversSize = allDrivers.size();
244 writer.println("NumberOfDrivers: " + driversSize);
245 for (int i = 0; i < driversSize; i++) {
246 int driverId = allDrivers.get(i).id;
247 writer.print(indent + "#" + i + ": id=" + driverId);
248 List<UserInfo> passengers = getPassengers(driverId);
249 int passengersSize = passengers.size();
250 writer.print(" NumberPassengers: " + passengersSize);
251 if (passengersSize > 0) {
252 writer.print(" [");
253 for (int j = 0; j < passengersSize; j++) {
254 writer.print(passengers.get(j).id);
255 if (j < passengersSize - 1) {
256 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700257 }
felipeal2d0483c2019-11-02 14:07:22 -0700258 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700259 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700260 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700261 writer.println();
262 }
263 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
264 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
265 writer.printf("Initial user: %s\n", mInitialUser);
266 writer.println("Relevant overlayable properties");
267 Resources res = mContext.getResources();
268 writer.printf("%sowner_name=%s\n", indent,
269 res.getString(com.android.internal.R.string.owner_name));
270 writer.printf("%sdefault_guest_name=%s\n", indent,
271 res.getString(R.string.default_guest_name));
Mayank Garg7a114c82020-04-08 21:25:06 -0700272 writer.printf("User switch in process=%d\n", mUserSwitchInProcess);
273 writer.printf("Request Id for the user switch in process=%d\n ",
274 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700275
276 dumpUserMetrics(writer);
277 }
278
279 /**
280 * Dumps user metrics.
281 */
282 public void dumpUserMetrics(@NonNull PrintWriter writer) {
283 mUserMetrics.dump(writer);
284 }
285
286 /**
287 * Dumps first user unlocking time.
288 */
289 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
290 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700291 }
292
293 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
294 CountDownLatch latch = new CountDownLatch(1);
295 mHandler.post(() -> {
296 handleDumpUserLifecycleListeners(writer);
297 handleDumpAppLifecycleListeners(writer, indent);
298 latch.countDown();
299 });
300 int timeout = 5;
301 try {
302 if (!latch.await(timeout, TimeUnit.SECONDS)) {
303 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
304 timeout);
305 }
306 } catch (InterruptedException e) {
307 Thread.currentThread().interrupt();
308 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
309 }
310 }
311
312 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
313 if (mUserLifecycleListeners.isEmpty()) {
314 writer.println("No user lifecycle listeners");
315 return;
316 }
317 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
318 for (UserLifecycleListener listener : mUserLifecycleListeners) {
319 writer.printf("Listener %s\n", listener);
320 }
321 }
322
323 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
324 int numberListeners = mAppLifecycleListeners.size();
325 if (numberListeners == 0) {
326 writer.println("No lifecycle listeners");
327 return;
328 }
329 writer.printf("%d lifecycle listeners\n", numberListeners);
330 for (int i = 0; i < numberListeners; i++) {
331 int uid = mAppLifecycleListeners.keyAt(i);
332 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
333 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800334 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700335 }
336
337 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800338 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
339 *
340 * @param name The name of the driver to be created.
341 * @param admin Whether the created driver will be an admin.
342 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
343 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700344 */
345 @Override
346 @Nullable
347 public UserInfo createDriver(@NonNull String name, boolean admin) {
348 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000349 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700350 if (admin) {
351 return createNewAdminUser(name);
352 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700353 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700354 }
355
356 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800357 * Creates a passenger who is a profile of the given driver.
358 *
359 * @param name The name of the passenger to be created.
360 * @param driverId User id of the driver under whom a passenger is created.
361 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
362 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700363 */
364 @Override
365 @Nullable
366 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
367 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000368 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700369 UserInfo driver = mUserManager.getUserInfo(driverId);
370 if (driver == null) {
371 Log.w(TAG_USER, "the driver is invalid");
372 return null;
373 }
374 if (driver.isGuest()) {
375 Log.w(TAG_USER, "a guest driver cannot create a passenger");
376 return null;
377 }
Bookatz42fb1a62019-10-30 11:45:01 -0700378 UserInfo user = mUserManager.createProfileForUser(name,
379 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700380 if (user == null) {
381 // Couldn't create user, most likely because there are too many.
382 Log.w(TAG_USER, "can't create a profile for user" + driverId);
383 return null;
384 }
385 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700386 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700387 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700388 return user;
389 }
390
391 /**
392 * @see CarUserManager.switchDriver
393 */
394 @Override
395 public boolean switchDriver(@UserIdInt int driverId) {
396 checkManageUsersPermission("switchDriver");
397 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
398 // System user doesn't associate with real person, can not be switched to.
399 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
400 return false;
401 }
402 int userSwitchable = mUserManager.getUserSwitchability();
403 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
404 Log.w(TAG_USER, "current process is not allowed to switch user");
405 return false;
406 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700407 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700408 // The current user is already the given user.
409 return true;
410 }
411 try {
412 return mAm.switchUser(driverId);
413 } catch (RemoteException e) {
414 // ignore
415 Log.w(TAG_USER, "error while switching user", e);
416 }
417 return false;
418 }
419
420 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800421 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
422 *
423 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700424 */
425 @Override
426 @NonNull
427 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700428 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700429 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
430 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700431 }
432
433 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800434 * Returns all passengers under the given driver.
435 *
436 * @param driverId User id of a driver.
437 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700438 */
439 @Override
440 @NonNull
441 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700442 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700443 return getUsers((user) -> {
444 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
445 && user.profileGroupId == driverId;
446 });
447 }
448
449 /**
450 * @see CarUserManager.startPassenger
451 */
452 @Override
453 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
454 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700455 synchronized (mLockUser) {
456 try {
457 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
458 Log.w(TAG_USER, "could not start passenger");
459 return false;
460 }
461 } catch (RemoteException e) {
462 // ignore
463 Log.w(TAG_USER, "error while starting passenger", e);
464 return false;
465 }
466 if (!assignUserToOccupantZone(passengerId, zoneId)) {
467 Log.w(TAG_USER, "could not assign passenger to zone");
468 return false;
469 }
470 mLastPassengerId = passengerId;
471 }
472 for (PassengerCallback callback : mPassengerCallbacks) {
473 callback.onPassengerStarted(passengerId, zoneId);
474 }
475 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700476 }
477
478 /**
479 * @see CarUserManager.stopPassenger
480 */
481 @Override
482 public boolean stopPassenger(@UserIdInt int passengerId) {
483 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700484 return stopPassengerInternal(passengerId, true);
485 }
486
487 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
488 synchronized (mLockUser) {
489 UserInfo passenger = mUserManager.getUserInfo(passengerId);
490 if (passenger == null) {
491 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
492 return false;
493 }
494 if (mLastPassengerId != passengerId) {
495 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
496 return true;
497 }
498 if (checkCurrentDriver) {
499 int currentUser = ActivityManager.getCurrentUser();
500 if (passenger.profileGroupId != currentUser) {
501 Log.w(TAG_USER, "passenger " + passengerId
502 + " is not a profile of the current user");
503 return false;
504 }
505 }
506 // Passenger is a profile, so cannot be stopped through activity manager.
507 // Instead, activities started by the passenger are stopped and the passenger is
508 // unassigned from the zone.
509 stopAllTasks(passengerId);
510 if (!unassignUserFromOccupantZone(passengerId)) {
511 Log.w(TAG_USER, "could not unassign user from occupant zone");
512 return false;
513 }
514 mLastPassengerId = UserHandle.USER_NULL;
515 }
516 for (PassengerCallback callback : mPassengerCallbacks) {
517 callback.onPassengerStopped(passengerId);
518 }
519 return true;
520 }
521
522 private void stopAllTasks(@UserIdInt int userId) {
523 try {
524 for (StackInfo info : mAm.getAllStackInfos()) {
525 for (int i = 0; i < info.taskIds.length; i++) {
526 if (info.taskUserIds[i] == userId) {
527 int taskId = info.taskIds[i];
528 if (!mAm.removeTask(taskId)) {
529 Log.w(TAG_USER, "could not remove task " + taskId);
530 }
531 }
532 }
533 }
534 } catch (RemoteException e) {
535 Log.e(TAG_USER, "could not get stack info", e);
536 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700537 }
538
Felipe Leme5528ff72020-02-10 19:05:14 -0800539 @Override
540 public void setLifecycleListenerForUid(IResultReceiver listener) {
541 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700542 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800543 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
544
545 try {
546 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
547 } catch (RemoteException e) {
548 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
549 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700550 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800551 }
552
553 private void onListenerDeath(int uid) {
554 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700555 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800556 }
557
558 @Override
559 public void resetLifecycleListenerForUid() {
560 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700561 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800562 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700563 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800564 }
565
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800566 @Override
567 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800568 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700569 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
570 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800571 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700572 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800573 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800574 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700575 Bundle resultData = null;
576 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700577 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
578 status, resp.action, resp.userToSwitchOrCreate.userId,
579 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700580 switch (resp.action) {
581 case InitialUserInfoResponseAction.SWITCH:
582 resultData = new Bundle();
583 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
584 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
585 break;
586 case InitialUserInfoResponseAction.CREATE:
587 resultData = new Bundle();
588 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
589 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
590 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
591 break;
592 case InitialUserInfoResponseAction.DEFAULT:
593 resultData = new Bundle();
594 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
595 break;
596 default:
597 // That's ok, it will be the same as DEFAULT...
598 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800599 }
felipeal312416a2020-04-14 12:28:24 -0700600 } else {
601 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800602 }
Mayank Garg0e239142020-04-14 19:16:31 -0700603 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800604 });
605 }
606
Felipe Lemee3cab982020-03-12 11:39:29 -0700607 /**
felipeal61ce3732020-04-03 11:01:00 -0700608 * Gets the initial foreground user after the device boots or resumes from suspension.
609 *
610 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
611 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
612 * method returns {@code null}.
613 *
614 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
615 * (like switching to the last active user), and this method will return the result of such
616 * operation.
617 *
618 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
619 * {@code null}.
620 *
621 * @hide
622 */
623 @Nullable
624 public UserInfo getInitialUser() {
625 checkInteractAcrossUsersPermission("getInitialUser");
626 synchronized (mLockUser) {
627 return mInitialUser;
628 }
629 }
630
631 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
632 // some reason passing the whole UserInfo through a raw binder transaction is not working.
633 /**
634 * Sets the initial foreground user after the device boots or resumes from suspension.
635 */
636 public void setInitialUser(@UserIdInt int userId) {
637 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
638 : mUserManager.getUserInfo(userId);
639 setInitialUser(initialUser);
640 }
641
642 /**
643 * Sets the initial foreground user after the device boots or resumes from suspension.
644 */
645 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700646 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
647 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700648 synchronized (mLockUser) {
649 mInitialUser = user;
650 }
651 if (user == null) {
652 // This mean InitialUserSetter failed and could not fallback, so the initial user was
653 // not switched (and most likely is SYSTEM_USER).
654 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
655 Log.wtf(TAG_USER, "Initial user set to null");
656 }
657 }
658
659 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700660 * Calls the User HAL to get the initial user info.
661 *
662 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
663 * @param callback callback to receive the results.
664 */
665 public void getInitialUserInfo(int requestType,
666 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700667 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
668 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700669 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700670 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700671 UsersInfo usersInfo = getUsersInfo();
672 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
673 }
674
675 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700676 * Calls the User HAL to switch user.
677 *
Mayank Garge19c2922020-03-30 18:05:53 -0700678 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700679 * @param timeoutMs - timeout for HAL to wait
680 * @param receiver - receiver for the results
681 */
Mayank Garge19c2922020-03-30 18:05:53 -0700682 @Override
683 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
Mayank Garg59f22192020-03-27 00:51:45 -0700684 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700685 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId,
686 timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700687 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700688 Objects.requireNonNull(receiver);
689 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
690 Preconditions.checkArgument(targetUser != null, "Invalid target user Id");
Mayank Garg7a114c82020-04-08 21:25:06 -0700691
Mayank Garg0e239142020-04-14 19:16:31 -0700692 if (ActivityManager.getCurrentUser() == targetUserId) {
693 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
694 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
695 }
696 int resultStatus = CarUserManager.USER_SWITCH_STATUS_ALREADY_REQUESTED_USER;
697 sendResult(receiver, resultStatus, null);
698 return;
699 }
700
Mayank Garg7a114c82020-04-08 21:25:06 -0700701 synchronized (mLockUser) {
702 if (mUserSwitchInProcess == targetUserId) {
703 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
704 Log.d(TAG_USER,
Mayank Garg0e239142020-04-14 19:16:31 -0700705 "A user switch request is already in process for the target user: "
706 + targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700707 }
Mayank Garg0e239142020-04-14 19:16:31 -0700708 int resultStatus = CarUserManager.USER_SWITCH_STATUS_ANOTHER_REQUEST_IN_PROCESS;
709 sendResult(receiver, resultStatus, null);
Mayank Garg7a114c82020-04-08 21:25:06 -0700710 return;
711 }
712 }
713
Mayank Garg59f22192020-03-27 00:51:45 -0700714 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700715 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700716 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700717 halTargetUser.userId = targetUser.id;
718 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
719 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg59f22192020-03-27 00:51:45 -0700720 Bundle resultData = null;
721 resultData = new Bundle();
Mayank Garge19c2922020-03-30 18:05:53 -0700722 int resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_INTERNAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700723 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700724 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, status,
725 resp.status, resp.messageType);
Mayank Garge19c2922020-03-30 18:05:53 -0700726 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_STATUS, resp.status);
727 resultData.putInt(CarUserManager.BUNDLE_USER_SWITCH_MSG_TYPE, resp.messageType);
728 if (resp.errorMessage != null) {
729 resultData.putString(CarUserManager.BUNDLE_USER_SWITCH_ERROR_MSG,
730 resp.errorMessage);
731 }
Mayank Garg59f22192020-03-27 00:51:45 -0700732 switch (resp.status) {
733 case SwitchUserStatus.SUCCESS:
734 boolean result;
735 try {
Mayank Garge19c2922020-03-30 18:05:53 -0700736 result = mAm.switchUser(targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700737 if (result) {
Mayank Garge19c2922020-03-30 18:05:53 -0700738 resultStatus = CarUserManager.USER_SWITCH_STATUS_SUCCESSFUL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700739 updateUserSwitchInProcess(targetUserId, resp);
Mayank Garg59f22192020-03-27 00:51:45 -0700740 } else {
Mayank Garge19c2922020-03-30 18:05:53 -0700741 resultStatus = CarUserManager.USER_SWITCH_STATUS_ANDROID_FAILURE;
Mayank Garg7a114c82020-04-08 21:25:06 -0700742 postSwitchHalResponse(resp.requestId, targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700743 }
744 } catch (RemoteException e) {
745 // ignore
746 Log.w(TAG_USER,
747 "error while switching user " + targetUser.toFullString(), e);
748 }
749 break;
750 case SwitchUserStatus.FAILURE:
751 // HAL failed to switch user
Mayank Garge19c2922020-03-30 18:05:53 -0700752 resultStatus = CarUserManager.USER_SWITCH_STATUS_HAL_FAILURE;
Mayank Garg59f22192020-03-27 00:51:45 -0700753 break;
754 }
felipeal312416a2020-04-14 12:28:24 -0700755 } else {
756 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, status);
Mayank Garg59f22192020-03-27 00:51:45 -0700757 }
Mayank Garg0e239142020-04-14 19:16:31 -0700758 sendResult(receiver, resultStatus, resultData);
Mayank Garg59f22192020-03-27 00:51:45 -0700759 });
760 }
761
Mayank Garg0e239142020-04-14 19:16:31 -0700762 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
763 @Nullable Bundle resultData) {
764 try {
765 receiver.send(resultCode, resultData);
766 } catch (RemoteException e) {
767 // ignore
768 Log.w(TAG_USER, "error while sending results", e);
769 }
770 }
771
Mayank Garg7a114c82020-04-08 21:25:06 -0700772 private void updateUserSwitchInProcess(@UserIdInt int targetUserId,
773 @NonNull SwitchUserResponse resp) {
774 synchronized (mLockUser) {
775 if (mUserSwitchInProcess != UserHandle.USER_NULL) {
776 // Some other user switch is in process.
777 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
778 Log.d(TAG_USER, "User switch for user: " + mUserSwitchInProcess
779 + " is in process. Sending failed android post switch response for it "
780 + " as new user switch is requested for user: " + targetUserId);
781 }
782 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserSwitchInProcess);
783 }
784 mUserSwitchInProcess = targetUserId;
785 mRequestIdForUserSwitchInProcess = resp.requestId;
786 }
787 }
788
789 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
790 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
791 UsersInfo usersInfo = getUsersInfo();
792 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
793 new android.hardware.automotive.vehicle.V2_0.UserInfo();
794 halTargetUser.userId = targetUser.id;
795 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700796 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
797 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700798 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
799 }
800
Mayank Garg59f22192020-03-27 00:51:45 -0700801 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700802 * Checks if the User HAL is supported.
803 */
804 public boolean isUserHalSupported() {
805 return mHal.isSupported();
806 }
807
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800808 // TODO(b/144120654): use helper to generate UsersInfo
809 private UsersInfo getUsersInfo() {
810 UserInfo currentUser;
811 try {
812 currentUser = mAm.getCurrentUser();
813 } catch (RemoteException e) {
814 // shouldn't happen
815 throw new IllegalStateException("Could not get current user: ", e);
816 }
817 List<UserInfo> existingUsers = mUserManager.getUsers();
818 int size = existingUsers.size();
819
820 UsersInfo usersInfo = new UsersInfo();
821 usersInfo.numberUsers = size;
822 usersInfo.currentUser.userId = currentUser.id;
823 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
824
825 for (int i = 0; i < size; i++) {
826 UserInfo androidUser = existingUsers.get(i);
827 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
828 new android.hardware.automotive.vehicle.V2_0.UserInfo();
829 halUser.userId = androidUser.id;
830 halUser.flags = UserHalHelper.convertFlags(androidUser);
831 usersInfo.existingUsers.add(halUser);
832 }
833
834 return usersInfo;
835 }
836
Eric Jeong1545f3b2019-09-16 13:56:52 -0700837 /** Returns whether the given user is a system user. */
838 private static boolean isSystemUser(@UserIdInt int userId) {
839 return userId == UserHandle.USER_SYSTEM;
840 }
841
Keun young Park13a7a822019-04-04 15:53:08 -0700842 private void updateDefaultUserRestriction() {
843 // We want to set restrictions on system and guest users only once. These are persisted
844 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
845 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700846 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
847 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700848 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700849 // Only apply the system user restrictions if the system user is headless.
850 if (UserManager.isHeadlessSystemUserMode()) {
851 setSystemUserRestrictions();
852 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700853 Settings.Global.putInt(mContext.getContentResolver(),
854 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700855 }
856
Eric Jeong1545f3b2019-09-16 13:56:52 -0700857 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700858 return !mUserManager.getUserInfo(userId).isEphemeral();
859 }
860
Antonio Kantekc8114752020-03-05 21:37:39 -0800861 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800862 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
863 */
864 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
865 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700866 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800867 }
868
869 /**
870 * Removes previously added {@link UserLifecycleListener}.
871 */
872 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
873 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700874 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800875 }
876
Eric Jeongc91f9452019-08-30 15:04:21 -0700877 /** Adds callback to listen to passenger activity events. */
878 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000879 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700880 mPassengerCallbacks.add(callback);
881 }
882
883 /** Removes previously added callback to listen passenger events. */
884 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000885 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700886 mPassengerCallbacks.remove(callback);
887 }
888
889 /** Sets the implementation of ZoneUserBindingHelper. */
890 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
891 synchronized (mLockHelper) {
892 mZoneUserBindingHelper = helper;
893 }
894 }
895
felipeal98900c82020-04-09 09:05:02 -0700896 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800897 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700898 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700899 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700900 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700901 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
902 updateDefaultUserRestriction();
903 tasks = new ArrayList<>(mUser0UnlockTasks);
904 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700905 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700906 }
907 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700908 Integer user = userId;
909 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700910 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700911 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700912 mBackgroundUsersToRestart.remove(user);
913 mBackgroundUsersToRestart.add(0, user);
914 }
915 // -1 for user 0
916 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700917 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700918 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700919 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700920 + ", dropping least recently user from restart list:" + userToDrop);
921 // Drop the least recently used user.
922 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
923 }
924 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800925 }
926 }
927 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700928 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800929 for (Runnable r : tasks) {
930 r.run();
931 }
932 }
933 }
934
935 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700936 * Starts all background users that were active in system.
937 *
Keun young Parkfb656372019-03-12 18:37:55 -0700938 * @return list of background users started successfully.
939 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700940 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700941 public ArrayList<Integer> startAllBackgroundUsers() {
942 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700943 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700944 users = new ArrayList<>(mBackgroundUsersToRestart);
945 mBackgroundUsersRestartedHere.clear();
946 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700947 }
948 ArrayList<Integer> startedUsers = new ArrayList<>();
949 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700950 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700951 continue;
952 }
953 try {
954 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700955 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
956 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700957 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700958 } else if (mAm.unlockUser(user, null, null, null)) {
959 startedUsers.add(user);
960 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700961 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700962 if (mUserManager.isUserRunning(user)) {
963 // add to started list so that it can be stopped later.
964 startedUsers.add(user);
965 }
Keun young Parkfb656372019-03-12 18:37:55 -0700966 }
967 }
968 } catch (RemoteException e) {
969 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700970 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700971 }
972 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700973 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700974 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700975 ArrayList<Integer> usersToRemove = new ArrayList<>();
976 for (Integer user : mBackgroundUsersToRestart) {
977 if (!startedUsers.contains(user)) {
978 usersToRemove.add(user);
979 }
980 }
981 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
982 }
Keun young Parkfb656372019-03-12 18:37:55 -0700983 return startedUsers;
984 }
985
986 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700987 * Stops all background users that were active in system.
988 *
989 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700990 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700991 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700992 if (userId == UserHandle.USER_SYSTEM) {
993 return false;
994 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700995 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700996 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700997 return false;
998 }
999 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001000 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001001 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001002 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001003 Integer user = userId;
1004 mBackgroundUsersRestartedHere.remove(user);
1005 }
1006 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1007 return false;
1008 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001009 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001010 return false;
1011 }
1012 } catch (RemoteException e) {
1013 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001014 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001015 }
1016 return true;
1017 }
1018
1019 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001020 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001021 */
felipeale8c5dce2020-04-15 11:27:06 -07001022 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1023 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1024 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001025
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001026 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001027 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1028 onUserSwitching(userId);
1029 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1030 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001031 }
1032
felipeale8c5dce2020-04-15 11:27:06 -07001033 // ...then notify listeners.
1034 UserLifecycleEvent event = new UserLifecycleEvent(eventType, userId);
1035
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001036 mHandler.post(() -> {
1037 handleNotifyServiceUserLifecycleListeners(event);
1038 handleNotifyAppUserLifecycleListeners(event);
1039 });
felipeale8c5dce2020-04-15 11:27:06 -07001040
1041 // Finally, update metrics.
1042 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1043 }
1044
1045 /**
1046 * Sets the first user unlocking metrics.
1047 */
1048 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1049 int halResponseTime) {
1050 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001051 }
1052
Mayank Garg7a114c82020-04-08 21:25:06 -07001053 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
1054 if (mUserSwitchInProcess == UserHandle.USER_NULL || mUserSwitchInProcess != userId) {
1055 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1056 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1057 }
1058 return;
1059 }
1060 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserSwitchInProcess);
1061 mUserSwitchInProcess = UserHandle.USER_NULL;
1062 mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
1063 }
1064
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001065 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1066 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001067 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001068 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1069 Log.d(TAG_USER, "No app listener to be notified of " + event);
1070 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001071 return;
1072 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001073 // Must use a different TimingsTraceLog because it's another thread
1074 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1075 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1076 }
felipeal2a84d512020-04-06 18:52:15 -07001077 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001078 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1079 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1080 for (int i = 0; i < listenersSize; i++) {
1081 int uid = mAppLifecycleListeners.keyAt(i);
1082 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1083 Bundle data = new Bundle();
1084 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
1085 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
1086 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
felipeal2a84d512020-04-06 18:52:15 -07001087 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001088 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001089 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001090 try {
felipeal2a84d512020-04-06 18:52:15 -07001091 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001092 listener.send(userId, data);
1093 } catch (RemoteException e) {
1094 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1095 } finally {
1096 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001097 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001098 }
1099 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001100 }
1101
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001102 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001103 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1104 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001105 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001106 return;
felipeal2a84d512020-04-06 18:52:15 -07001107 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1108 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1109 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001110 }
felipeal2a84d512020-04-06 18:52:15 -07001111
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001112 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1113 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001114 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001115 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001116 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001117 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001118 listener.onEvent(event);
1119 } catch (RuntimeException e) {
1120 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001121 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001122 } finally {
1123 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001124 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001125 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001126 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001127 }
1128
felipeal98900c82020-04-09 09:05:02 -07001129 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001130 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1131 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001132 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001133
Felipe Lemef45ee502019-12-19 10:00:14 -08001134 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001135 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001136 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001137 if (mLastPassengerId != UserHandle.USER_NULL) {
1138 stopPassengerInternal(mLastPassengerId, false);
1139 }
1140 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1141 setupPassengerUser();
1142 startFirstPassenger(userId);
1143 }
felipeal98900c82020-04-09 09:05:02 -07001144 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001145 }
1146
1147 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001148 * 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 -08001149 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001150 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001151 * @param r Runnable to run.
1152 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001153 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001154 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001155 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001156 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001157 if (mUser0Unlocked) {
1158 runNow = true;
1159 } else {
1160 mUser0UnlockTasks.add(r);
1161 }
1162 }
1163 if (runNow) {
1164 r.run();
1165 }
1166 }
1167
Keun young Parkf3523cd2019-04-08 10:09:17 -07001168 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001169 @NonNull
1170 ArrayList<Integer> getBackgroundUsersToRestart() {
1171 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001172 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001173 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1174 }
1175 return backgroundUsersToRestart;
1176 }
1177
Ying Zheng1ab32b62018-06-26 12:47:26 -07001178 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001179 // Disable Location service for system user.
1180 LocationManager locationManager =
1181 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001182 locationManager.setLocationEnabledForUser(
1183 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001184 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001185
1186 /**
1187 * Creates a new user on the system, the created user would be granted admin role.
1188 *
1189 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001190 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001191 */
1192 @Nullable
1193 private UserInfo createNewAdminUser(String name) {
1194 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1195 // Only admins or system user can create other privileged users.
1196 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1197 return null;
1198 }
1199
1200 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1201 if (user == null) {
1202 // Couldn't create user, most likely because there are too many.
1203 Log.w(TAG_USER, "can't create admin user.");
1204 return null;
1205 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001206 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001207
1208 return user;
1209 }
1210
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001211 /**
1212 * Assigns a default icon to a user according to the user's id.
1213 *
1214 * @param userInfo User whose avatar is set to default icon.
1215 * @return Bitmap of the user icon.
1216 */
1217 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1218 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1219 Bitmap bitmap = UserIcons.convertToBitmap(
1220 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1221 mUserManager.setUserIcon(userInfo.id, bitmap);
1222 return bitmap;
1223 }
1224
Eric Jeong1545f3b2019-09-16 13:56:52 -07001225 private interface UserFilter {
1226 boolean isEligibleUser(UserInfo user);
1227 }
1228
1229 /** Returns all users who are matched by the given filter. */
1230 private List<UserInfo> getUsers(UserFilter filter) {
1231 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1232
1233 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1234 UserInfo user = iterator.next();
1235 if (!filter.isEligibleUser(user)) {
1236 iterator.remove();
1237 }
1238 }
1239 return users;
1240 }
1241
1242 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001243 * Enforces that apps which have the
1244 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1245 * can make certain calls to the CarUserManager.
1246 *
1247 * @param message used as message if SecurityException is thrown.
1248 * @throws SecurityException if the caller is not system or root.
1249 */
1250 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001251 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1252 }
1253
1254 private static void checkManageUsersOrDumpPermission(String message) {
1255 checkAtLeastOnePermission(message,
1256 android.Manifest.permission.MANAGE_USERS,
1257 android.Manifest.permission.DUMP);
1258 }
1259
Felipe Leme5528ff72020-02-10 19:05:14 -08001260 private void checkInteractAcrossUsersPermission(String message) {
1261 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1262 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1263 }
1264
felipeal2d0483c2019-11-02 14:07:22 -07001265 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001266 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001267 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1268 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001269 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001270 }
1271 }
1272
felipeal2d0483c2019-11-02 14:07:22 -07001273 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1274 for (String permission : permissions) {
1275 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1276 /* exported = */ true)
1277 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1278 return true;
1279 }
1280 }
1281 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001282 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001283
1284 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1285 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1286 // Count all users that are managed profiles of the given user.
1287 int managedProfilesCount = 0;
1288 for (UserInfo user : users) {
1289 if (user.isManagedProfile() && user.profileGroupId == userId) {
1290 managedProfilesCount++;
1291 }
1292 }
1293 return managedProfilesCount;
1294 }
1295
1296 /**
1297 * Starts the first passenger of the given driver and assigns the passenger to the front
1298 * passenger zone.
1299 *
1300 * @param driverId User id of the driver.
1301 * @return whether it succeeds.
1302 */
1303 private boolean startFirstPassenger(@UserIdInt int driverId) {
1304 int zoneId = getAvailablePassengerZone();
1305 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1306 Log.w(TAG_USER, "passenger occupant zone is not found");
1307 return false;
1308 }
1309 List<UserInfo> passengers = getPassengers(driverId);
1310 if (passengers.size() < 1) {
1311 Log.w(TAG_USER, "passenger is not found");
1312 return false;
1313 }
1314 // Only one passenger is supported. If there are two or more passengers, the first passenger
1315 // is chosen.
1316 int passengerId = passengers.get(0).id;
1317 if (!startPassenger(passengerId, zoneId)) {
1318 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1319 return false;
1320 }
1321 return true;
1322 }
1323
1324 private int getAvailablePassengerZone() {
1325 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1326 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1327 for (int occupantType : occupantTypes) {
1328 int zoneId = getZoneId(occupantType);
1329 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1330 return zoneId;
1331 }
1332 }
1333 return OccupantZoneInfo.INVALID_ZONE_ID;
1334 }
1335
1336 /**
1337 * Creates a new passenger user when there is no passenger user.
1338 */
1339 private void setupPassengerUser() {
1340 int currentUser = ActivityManager.getCurrentUser();
1341 int profileCount = getNumberOfManagedProfiles(currentUser);
1342 if (profileCount > 0) {
1343 Log.w(TAG_USER, "max profile of user" + currentUser
1344 + " is exceeded: current profile count is " + profileCount);
1345 return;
1346 }
1347 // TODO(b/140311342): Use resource string for the default passenger name.
1348 UserInfo passenger = createPassenger("Passenger", currentUser);
1349 if (passenger == null) {
1350 // Couldn't create user, most likely because there are too many.
1351 Log.w(TAG_USER, "cannot create a passenger user");
1352 return;
1353 }
1354 }
1355
1356 @NonNull
1357 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1358 ZoneUserBindingHelper helper = null;
1359 synchronized (mLockHelper) {
1360 if (mZoneUserBindingHelper == null) {
1361 Log.w(TAG_USER, "implementation is not delegated");
1362 return new ArrayList<OccupantZoneInfo>();
1363 }
1364 helper = mZoneUserBindingHelper;
1365 }
1366 return helper.getOccupantZones(occupantType);
1367 }
1368
1369 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1370 ZoneUserBindingHelper helper = null;
1371 synchronized (mLockHelper) {
1372 if (mZoneUserBindingHelper == null) {
1373 Log.w(TAG_USER, "implementation is not delegated");
1374 return false;
1375 }
1376 helper = mZoneUserBindingHelper;
1377 }
1378 return helper.assignUserToOccupantZone(userId, zoneId);
1379 }
1380
1381 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1382 ZoneUserBindingHelper helper = null;
1383 synchronized (mLockHelper) {
1384 if (mZoneUserBindingHelper == null) {
1385 Log.w(TAG_USER, "implementation is not delegated");
1386 return false;
1387 }
1388 helper = mZoneUserBindingHelper;
1389 }
1390 return helper.unassignUserFromOccupantZone(userId);
1391 }
1392
1393 private boolean isPassengerDisplayAvailable() {
1394 ZoneUserBindingHelper helper = null;
1395 synchronized (mLockHelper) {
1396 if (mZoneUserBindingHelper == null) {
1397 Log.w(TAG_USER, "implementation is not delegated");
1398 return false;
1399 }
1400 helper = mZoneUserBindingHelper;
1401 }
1402 return helper.isPassengerDisplayAvailable();
1403 }
1404
1405 /**
1406 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1407 * zone is returned.
1408 *
1409 * @param occupantType The type of an occupant.
1410 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1411 * if not found.
1412 */
1413 private int getZoneId(@OccupantTypeEnum int occupantType) {
1414 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1415 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1416 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001417}