blob: 4e0a66ff7a79c8044eff65d6e7e42f067b327477 [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;
felipeale5bf0322020-04-16 15:10:57 -070036import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070037import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070038import android.car.userlib.HalCallback;
39import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070040import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070041import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070042import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070043import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070044import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080045import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg7a114c82020-04-08 21:25:06 -070046import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
Mayank Garg59f22192020-03-27 00:51:45 -070047import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080048import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070049import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070050import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080051import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070052import android.os.Handler;
53import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070054import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080055import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070056import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070057import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070058import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070059import android.sysprop.CarProperties;
felipeal312416a2020-04-14 12:28:24 -070060import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070061import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080062import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080063import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070064
65import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070066import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070067import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080068import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080069import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070070import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070071import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070072import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080073import com.android.internal.os.IResultReceiver;
felipeal2a84d512020-04-06 18:52:15 -070074import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070075import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070076import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070077
78import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080079import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070080import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070081import java.util.Iterator;
82import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000083import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070084import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070085import java.util.concurrent.CountDownLatch;
86import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070087
88/**
89 * User service for cars. Manages users at boot time. Including:
90 *
91 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070092 * <li> Creates a user used as driver.
93 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070094 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070095 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070096 * <ol/>
97 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070098public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080099
felipealf7368962020-04-16 12:55:19 -0700100 private static final String TAG = TAG_USER;
101
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800102 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800103 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800104 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800105 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800106 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800107 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800108 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
109 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800110
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700111 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700112 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700113 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700114 private final UserManager mUserManager;
115 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700116 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700117
Eric Jeongc91f9452019-08-30 15:04:21 -0700118 private final Object mLockUser = new Object();
119 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800120 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700121 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800122 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700123 // Only one passenger is supported.
124 @GuardedBy("mLockUser")
125 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700126 /**
127 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800128 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700129 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700130 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700131 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
132 /**
133 * Keep the list of background users started here. This is wholly for debugging purpose.
134 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700135 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700136 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
137
Felipe Leme58412202020-01-09 13:45:33 -0800138 private final UserHalService mHal;
139
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700140 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700141 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
142 getClass().getSimpleName());
143 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700144
Felipe Leme5528ff72020-02-10 19:05:14 -0800145 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800146 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800148 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700149 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800150
151 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800152 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700153 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800154 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700155 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800156
Mayank Garg7a114c82020-04-08 21:25:06 -0700157 /**
158 * User Id for the user switch in process, if any.
159 */
160 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700161 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700162 /**
163 * Request Id for the user switch in process, if any.
164 */
165 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700166 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700167 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
168
Eric Jeongc91f9452019-08-30 15:04:21 -0700169 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
170 new CopyOnWriteArrayList<>();
171
felipeal61ce3732020-04-03 11:01:00 -0700172 @Nullable
173 @GuardedBy("mLockUser")
174 private UserInfo mInitialUser;
175
felipeale8c5dce2020-04-15 11:27:06 -0700176 private final UserMetrics mUserMetrics = new UserMetrics();
177
Eric Jeongc91f9452019-08-30 15:04:21 -0700178 /** Interface for callbaks related to passenger activities. */
179 public interface PassengerCallback {
180 /** Called when passenger is started at a certain zone. */
181 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
182 /** Called when passenger is stopped. */
183 void onPassengerStopped(@UserIdInt int passengerId);
184 }
185
186 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
187 public interface ZoneUserBindingHelper {
188 /** Gets occupant zones corresponding to the occupant type. */
189 @NonNull
190 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
191 /** Assigns the user to the occupant zone. */
192 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
193 /** Makes the occupant zone unoccupied. */
194 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
195 /** Returns whether there is a passenger display. */
196 boolean isPassengerDisplayAvailable();
197 }
198
199 private final Object mLockHelper = new Object();
200 @GuardedBy("mLockHelper")
201 private ZoneUserBindingHelper mZoneUserBindingHelper;
202
Felipe Leme58412202020-01-09 13:45:33 -0800203 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
204 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700205 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700206 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
207 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700208 }
209 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800210 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700211 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700212 mAm = am;
213 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700214 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700215 mLastPassengerId = UserHandle.USER_NULL;
216 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700217 }
218
219 @Override
220 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700221 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
222 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700223 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700224 }
225
226 @Override
227 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700228 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
229 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700230 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700231 }
232
233 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700234 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700235 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700236 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800237 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700238 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700239 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700240 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700241 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
242 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700243 }
244 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
245 List<UserInfo> allDrivers = getAllDrivers();
246 int driversSize = allDrivers.size();
247 writer.println("NumberOfDrivers: " + driversSize);
248 for (int i = 0; i < driversSize; i++) {
249 int driverId = allDrivers.get(i).id;
250 writer.print(indent + "#" + i + ": id=" + driverId);
251 List<UserInfo> passengers = getPassengers(driverId);
252 int passengersSize = passengers.size();
253 writer.print(" NumberPassengers: " + passengersSize);
254 if (passengersSize > 0) {
255 writer.print(" [");
256 for (int j = 0; j < passengersSize; j++) {
257 writer.print(passengers.get(j).id);
258 if (j < passengersSize - 1) {
259 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700260 }
felipeal2d0483c2019-11-02 14:07:22 -0700261 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700262 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700263 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700264 writer.println();
265 }
266 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
267 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
268 writer.printf("Initial user: %s\n", mInitialUser);
269 writer.println("Relevant overlayable properties");
270 Resources res = mContext.getResources();
271 writer.printf("%sowner_name=%s\n", indent,
272 res.getString(com.android.internal.R.string.owner_name));
273 writer.printf("%sdefault_guest_name=%s\n", indent,
274 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700275 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700276 writer.printf("Request Id for the user switch in process=%d\n ",
277 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700278
279 dumpUserMetrics(writer);
280 }
281
282 /**
283 * Dumps user metrics.
284 */
285 public void dumpUserMetrics(@NonNull PrintWriter writer) {
286 mUserMetrics.dump(writer);
287 }
288
289 /**
290 * Dumps first user unlocking time.
291 */
292 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
293 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700294 }
295
296 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
297 CountDownLatch latch = new CountDownLatch(1);
298 mHandler.post(() -> {
299 handleDumpUserLifecycleListeners(writer);
300 handleDumpAppLifecycleListeners(writer, indent);
301 latch.countDown();
302 });
303 int timeout = 5;
304 try {
305 if (!latch.await(timeout, TimeUnit.SECONDS)) {
306 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
307 timeout);
308 }
309 } catch (InterruptedException e) {
310 Thread.currentThread().interrupt();
311 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
312 }
313 }
314
315 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
316 if (mUserLifecycleListeners.isEmpty()) {
317 writer.println("No user lifecycle listeners");
318 return;
319 }
320 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
321 for (UserLifecycleListener listener : mUserLifecycleListeners) {
322 writer.printf("Listener %s\n", listener);
323 }
324 }
325
326 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
327 int numberListeners = mAppLifecycleListeners.size();
328 if (numberListeners == 0) {
329 writer.println("No lifecycle listeners");
330 return;
331 }
332 writer.printf("%d lifecycle listeners\n", numberListeners);
333 for (int i = 0; i < numberListeners; i++) {
334 int uid = mAppLifecycleListeners.keyAt(i);
335 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
336 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800337 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700338 }
339
340 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800341 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
342 *
343 * @param name The name of the driver to be created.
344 * @param admin Whether the created driver will be an admin.
345 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
346 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700347 */
348 @Override
349 @Nullable
350 public UserInfo createDriver(@NonNull String name, boolean admin) {
351 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000352 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700353 if (admin) {
354 return createNewAdminUser(name);
355 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700356 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700357 }
358
359 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800360 * Creates a passenger who is a profile of the given driver.
361 *
362 * @param name The name of the passenger to be created.
363 * @param driverId User id of the driver under whom a passenger is created.
364 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
365 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700366 */
367 @Override
368 @Nullable
369 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
370 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000371 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700372 UserInfo driver = mUserManager.getUserInfo(driverId);
373 if (driver == null) {
374 Log.w(TAG_USER, "the driver is invalid");
375 return null;
376 }
377 if (driver.isGuest()) {
378 Log.w(TAG_USER, "a guest driver cannot create a passenger");
379 return null;
380 }
Bookatz42fb1a62019-10-30 11:45:01 -0700381 UserInfo user = mUserManager.createProfileForUser(name,
382 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700383 if (user == null) {
384 // Couldn't create user, most likely because there are too many.
385 Log.w(TAG_USER, "can't create a profile for user" + driverId);
386 return null;
387 }
388 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700389 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700390 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700391 return user;
392 }
393
394 /**
395 * @see CarUserManager.switchDriver
396 */
397 @Override
398 public boolean switchDriver(@UserIdInt int driverId) {
399 checkManageUsersPermission("switchDriver");
400 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
401 // System user doesn't associate with real person, can not be switched to.
402 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
403 return false;
404 }
405 int userSwitchable = mUserManager.getUserSwitchability();
406 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
407 Log.w(TAG_USER, "current process is not allowed to switch user");
408 return false;
409 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700410 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700411 // The current user is already the given user.
412 return true;
413 }
414 try {
415 return mAm.switchUser(driverId);
416 } catch (RemoteException e) {
417 // ignore
418 Log.w(TAG_USER, "error while switching user", e);
419 }
420 return false;
421 }
422
423 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800424 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
425 *
426 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700427 */
428 @Override
429 @NonNull
430 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700431 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700432 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
433 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700434 }
435
436 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800437 * Returns all passengers under the given driver.
438 *
439 * @param driverId User id of a driver.
440 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 */
442 @Override
443 @NonNull
444 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700445 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700446 return getUsers((user) -> {
447 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
448 && user.profileGroupId == driverId;
449 });
450 }
451
452 /**
453 * @see CarUserManager.startPassenger
454 */
455 @Override
456 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
457 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700458 synchronized (mLockUser) {
459 try {
460 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
461 Log.w(TAG_USER, "could not start passenger");
462 return false;
463 }
464 } catch (RemoteException e) {
465 // ignore
466 Log.w(TAG_USER, "error while starting passenger", e);
467 return false;
468 }
469 if (!assignUserToOccupantZone(passengerId, zoneId)) {
470 Log.w(TAG_USER, "could not assign passenger to zone");
471 return false;
472 }
473 mLastPassengerId = passengerId;
474 }
475 for (PassengerCallback callback : mPassengerCallbacks) {
476 callback.onPassengerStarted(passengerId, zoneId);
477 }
478 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700479 }
480
481 /**
482 * @see CarUserManager.stopPassenger
483 */
484 @Override
485 public boolean stopPassenger(@UserIdInt int passengerId) {
486 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700487 return stopPassengerInternal(passengerId, true);
488 }
489
490 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
491 synchronized (mLockUser) {
492 UserInfo passenger = mUserManager.getUserInfo(passengerId);
493 if (passenger == null) {
494 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
495 return false;
496 }
497 if (mLastPassengerId != passengerId) {
498 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
499 return true;
500 }
501 if (checkCurrentDriver) {
502 int currentUser = ActivityManager.getCurrentUser();
503 if (passenger.profileGroupId != currentUser) {
504 Log.w(TAG_USER, "passenger " + passengerId
505 + " is not a profile of the current user");
506 return false;
507 }
508 }
509 // Passenger is a profile, so cannot be stopped through activity manager.
510 // Instead, activities started by the passenger are stopped and the passenger is
511 // unassigned from the zone.
512 stopAllTasks(passengerId);
513 if (!unassignUserFromOccupantZone(passengerId)) {
514 Log.w(TAG_USER, "could not unassign user from occupant zone");
515 return false;
516 }
517 mLastPassengerId = UserHandle.USER_NULL;
518 }
519 for (PassengerCallback callback : mPassengerCallbacks) {
520 callback.onPassengerStopped(passengerId);
521 }
522 return true;
523 }
524
525 private void stopAllTasks(@UserIdInt int userId) {
526 try {
527 for (StackInfo info : mAm.getAllStackInfos()) {
528 for (int i = 0; i < info.taskIds.length; i++) {
529 if (info.taskUserIds[i] == userId) {
530 int taskId = info.taskIds[i];
531 if (!mAm.removeTask(taskId)) {
532 Log.w(TAG_USER, "could not remove task " + taskId);
533 }
534 }
535 }
536 }
537 } catch (RemoteException e) {
538 Log.e(TAG_USER, "could not get stack info", e);
539 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700540 }
541
Felipe Leme5528ff72020-02-10 19:05:14 -0800542 @Override
543 public void setLifecycleListenerForUid(IResultReceiver listener) {
544 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700545 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800546 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
547
548 try {
549 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
550 } catch (RemoteException e) {
551 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
552 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700553 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800554 }
555
556 private void onListenerDeath(int uid) {
557 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700558 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800559 }
560
561 @Override
562 public void resetLifecycleListenerForUid() {
563 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700564 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800565 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700566 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800567 }
568
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800569 @Override
570 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800571 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700572 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
573 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800574 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700575 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800576 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800577 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700578 Bundle resultData = null;
579 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700580 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
581 status, resp.action, resp.userToSwitchOrCreate.userId,
582 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700583 switch (resp.action) {
584 case InitialUserInfoResponseAction.SWITCH:
585 resultData = new Bundle();
586 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
587 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
588 break;
589 case InitialUserInfoResponseAction.CREATE:
590 resultData = new Bundle();
591 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
592 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
593 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
594 break;
595 case InitialUserInfoResponseAction.DEFAULT:
596 resultData = new Bundle();
597 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
598 break;
599 default:
600 // That's ok, it will be the same as DEFAULT...
601 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800602 }
felipeal312416a2020-04-14 12:28:24 -0700603 } else {
604 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800605 }
Mayank Garg0e239142020-04-14 19:16:31 -0700606 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800607 });
608 }
609
Felipe Lemee3cab982020-03-12 11:39:29 -0700610 /**
felipeal61ce3732020-04-03 11:01:00 -0700611 * Gets the initial foreground user after the device boots or resumes from suspension.
612 *
613 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
614 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
615 * method returns {@code null}.
616 *
617 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
618 * (like switching to the last active user), and this method will return the result of such
619 * operation.
620 *
621 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
622 * {@code null}.
623 *
624 * @hide
625 */
626 @Nullable
627 public UserInfo getInitialUser() {
628 checkInteractAcrossUsersPermission("getInitialUser");
629 synchronized (mLockUser) {
630 return mInitialUser;
631 }
632 }
633
634 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
635 // some reason passing the whole UserInfo through a raw binder transaction is not working.
636 /**
637 * Sets the initial foreground user after the device boots or resumes from suspension.
638 */
639 public void setInitialUser(@UserIdInt int userId) {
640 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
641 : mUserManager.getUserInfo(userId);
642 setInitialUser(initialUser);
643 }
644
645 /**
646 * Sets the initial foreground user after the device boots or resumes from suspension.
647 */
648 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700649 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
650 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700651 synchronized (mLockUser) {
652 mInitialUser = user;
653 }
654 if (user == null) {
655 // This mean InitialUserSetter failed and could not fallback, so the initial user was
656 // not switched (and most likely is SYSTEM_USER).
657 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
658 Log.wtf(TAG_USER, "Initial user set to null");
659 }
660 }
661
662 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700663 * Calls the User HAL to get the initial user info.
664 *
665 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
666 * @param callback callback to receive the results.
667 */
668 public void getInitialUserInfo(int requestType,
669 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700670 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
671 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700672 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700673 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700674 UsersInfo usersInfo = getUsersInfo();
675 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
676 }
677
678 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700679 * Calls the User HAL to switch user.
680 *
Mayank Garge19c2922020-03-30 18:05:53 -0700681 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700682 * @param timeoutMs - timeout for HAL to wait
683 * @param receiver - receiver for the results
684 */
Mayank Garge19c2922020-03-30 18:05:53 -0700685 @Override
686 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700687 @NonNull AndroidFuture<UserSwitchResult> receiver) {
felipeal312416a2020-04-14 12:28:24 -0700688 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId,
689 timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700690 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700691 Objects.requireNonNull(receiver);
692 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700693 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700694
felipealf7368962020-04-16 12:55:19 -0700695 int currentUser = ActivityManager.getCurrentUser();
696 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700697 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
698 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
699 }
felipeale5bf0322020-04-16 15:10:57 -0700700 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
701 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700702 return;
703 }
704
Mayank Garg7a114c82020-04-08 21:25:06 -0700705 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700706 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
707 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
708 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
709 }
710
711 if (mUserIdForUserSwitchInProcess == targetUserId) {
felipeale5bf0322020-04-16 15:10:57 -0700712 int resultStatus = UserSwitchResult.STATUS_ANOTHER_REQUEST_IN_PROCESS;
713 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700714 return;
715 }
716 }
717
Mayank Garg59f22192020-03-27 00:51:45 -0700718 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700719 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700720 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700721 halTargetUser.userId = targetUser.id;
722 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
723 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700724 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
725 Log.d(TAG, "switch response: status="
726 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
727 }
728
felipeale5bf0322020-04-16 15:10:57 -0700729 int resultStatus = UserSwitchResult.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);
felipeale5bf0322020-04-16 15:10:57 -0700736 sendResult(receiver, resultStatus);
felipealf7368962020-04-16 12:55:19 -0700737 return;
738 }
739 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status,
740 resp.status, resp.errorMessage);
741
felipealf7368962020-04-16 12:55:19 -0700742 switch (resp.status) {
743 case SwitchUserStatus.SUCCESS:
744 boolean result;
745 try {
746 result = mAm.switchUser(targetUserId);
747 if (result) {
felipeale5bf0322020-04-16 15:10:57 -0700748 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
felipealf7368962020-04-16 12:55:19 -0700749 updateUserSwitchInProcess(targetUserId, resp);
750 } else {
felipeale5bf0322020-04-16 15:10:57 -0700751 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700752 postSwitchHalResponse(resp.requestId, targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700753 }
felipealf7368962020-04-16 12:55:19 -0700754 } catch (RemoteException e) {
755 // ignore
756 Log.w(TAG_USER,
757 "error while switching user " + targetUser.toFullString(), e);
758 }
759 break;
760 case SwitchUserStatus.FAILURE:
761 // HAL failed to switch user
felipeale5bf0322020-04-16 15:10:57 -0700762 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700763 break;
Mayank Garg59f22192020-03-27 00:51:45 -0700764 }
felipeale5bf0322020-04-16 15:10:57 -0700765 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700766 });
767 }
768
Mayank Garg0e239142020-04-14 19:16:31 -0700769 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
770 @Nullable Bundle resultData) {
771 try {
772 receiver.send(resultCode, resultData);
773 } catch (RemoteException e) {
774 // ignore
775 Log.w(TAG_USER, "error while sending results", e);
776 }
777 }
778
felipeale5bf0322020-04-16 15:10:57 -0700779 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
780 @UserSwitchResult.Status int status) {
781 sendResult(receiver, status, /* errorMessage= */ null);
782 }
783
784 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
785 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
786 receiver.complete(new UserSwitchResult(status, errorMessage));
787 }
788
Mayank Garg7a114c82020-04-08 21:25:06 -0700789 private void updateUserSwitchInProcess(@UserIdInt int targetUserId,
790 @NonNull SwitchUserResponse resp) {
791 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700792 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700793 // Some other user switch is in process.
794 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
felipealf7368962020-04-16 12:55:19 -0700795 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
Mayank Garg7a114c82020-04-08 21:25:06 -0700796 + " is in process. Sending failed android post switch response for it "
797 + " as new user switch is requested for user: " + targetUserId);
798 }
felipealf7368962020-04-16 12:55:19 -0700799 postSwitchHalResponse(mRequestIdForUserSwitchInProcess,
800 mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700801 }
felipealf7368962020-04-16 12:55:19 -0700802 mUserIdForUserSwitchInProcess = targetUserId;
Mayank Garg7a114c82020-04-08 21:25:06 -0700803 mRequestIdForUserSwitchInProcess = resp.requestId;
804 }
805 }
806
807 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
808 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
809 UsersInfo usersInfo = getUsersInfo();
810 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
811 new android.hardware.automotive.vehicle.V2_0.UserInfo();
812 halTargetUser.userId = targetUser.id;
813 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700814 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
815 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700816 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
817 }
818
Mayank Garg59f22192020-03-27 00:51:45 -0700819 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700820 * Checks if the User HAL is supported.
821 */
822 public boolean isUserHalSupported() {
823 return mHal.isSupported();
824 }
825
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800826 // TODO(b/144120654): use helper to generate UsersInfo
827 private UsersInfo getUsersInfo() {
828 UserInfo currentUser;
829 try {
830 currentUser = mAm.getCurrentUser();
831 } catch (RemoteException e) {
832 // shouldn't happen
833 throw new IllegalStateException("Could not get current user: ", e);
834 }
835 List<UserInfo> existingUsers = mUserManager.getUsers();
836 int size = existingUsers.size();
837
838 UsersInfo usersInfo = new UsersInfo();
839 usersInfo.numberUsers = size;
840 usersInfo.currentUser.userId = currentUser.id;
841 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
842
843 for (int i = 0; i < size; i++) {
844 UserInfo androidUser = existingUsers.get(i);
845 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
846 new android.hardware.automotive.vehicle.V2_0.UserInfo();
847 halUser.userId = androidUser.id;
848 halUser.flags = UserHalHelper.convertFlags(androidUser);
849 usersInfo.existingUsers.add(halUser);
850 }
851
852 return usersInfo;
853 }
854
Eric Jeong1545f3b2019-09-16 13:56:52 -0700855 /** Returns whether the given user is a system user. */
856 private static boolean isSystemUser(@UserIdInt int userId) {
857 return userId == UserHandle.USER_SYSTEM;
858 }
859
Keun young Park13a7a822019-04-04 15:53:08 -0700860 private void updateDefaultUserRestriction() {
861 // We want to set restrictions on system and guest users only once. These are persisted
862 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
863 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700864 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
865 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700866 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700867 // Only apply the system user restrictions if the system user is headless.
868 if (UserManager.isHeadlessSystemUserMode()) {
869 setSystemUserRestrictions();
870 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700871 Settings.Global.putInt(mContext.getContentResolver(),
872 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700873 }
874
Eric Jeong1545f3b2019-09-16 13:56:52 -0700875 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700876 return !mUserManager.getUserInfo(userId).isEphemeral();
877 }
878
Antonio Kantekc8114752020-03-05 21:37:39 -0800879 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800880 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
881 */
882 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
883 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700884 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800885 }
886
887 /**
888 * Removes previously added {@link UserLifecycleListener}.
889 */
890 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
891 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700892 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800893 }
894
Eric Jeongc91f9452019-08-30 15:04:21 -0700895 /** Adds callback to listen to passenger activity events. */
896 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000897 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700898 mPassengerCallbacks.add(callback);
899 }
900
901 /** Removes previously added callback to listen passenger events. */
902 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000903 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700904 mPassengerCallbacks.remove(callback);
905 }
906
907 /** Sets the implementation of ZoneUserBindingHelper. */
908 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
909 synchronized (mLockHelper) {
910 mZoneUserBindingHelper = helper;
911 }
912 }
913
felipeal98900c82020-04-09 09:05:02 -0700914 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800915 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700916 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700917 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700918 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700919 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
920 updateDefaultUserRestriction();
921 tasks = new ArrayList<>(mUser0UnlockTasks);
922 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700923 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700924 }
925 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700926 Integer user = userId;
927 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700928 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700929 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700930 mBackgroundUsersToRestart.remove(user);
931 mBackgroundUsersToRestart.add(0, user);
932 }
933 // -1 for user 0
934 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700935 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700936 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700937 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700938 + ", dropping least recently user from restart list:" + userToDrop);
939 // Drop the least recently used user.
940 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
941 }
942 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800943 }
944 }
945 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700946 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800947 for (Runnable r : tasks) {
948 r.run();
949 }
950 }
951 }
952
953 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700954 * Starts all background users that were active in system.
955 *
Keun young Parkfb656372019-03-12 18:37:55 -0700956 * @return list of background users started successfully.
957 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700958 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700959 public ArrayList<Integer> startAllBackgroundUsers() {
960 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700961 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700962 users = new ArrayList<>(mBackgroundUsersToRestart);
963 mBackgroundUsersRestartedHere.clear();
964 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700965 }
966 ArrayList<Integer> startedUsers = new ArrayList<>();
967 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700968 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700969 continue;
970 }
971 try {
972 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700973 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
974 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700975 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700976 } else if (mAm.unlockUser(user, null, null, null)) {
977 startedUsers.add(user);
978 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700979 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700980 if (mUserManager.isUserRunning(user)) {
981 // add to started list so that it can be stopped later.
982 startedUsers.add(user);
983 }
Keun young Parkfb656372019-03-12 18:37:55 -0700984 }
985 }
986 } catch (RemoteException e) {
987 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700988 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700989 }
990 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700991 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700992 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700993 ArrayList<Integer> usersToRemove = new ArrayList<>();
994 for (Integer user : mBackgroundUsersToRestart) {
995 if (!startedUsers.contains(user)) {
996 usersToRemove.add(user);
997 }
998 }
999 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1000 }
Keun young Parkfb656372019-03-12 18:37:55 -07001001 return startedUsers;
1002 }
1003
1004 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001005 * Stops all background users that were active in system.
1006 *
1007 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001008 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001009 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001010 if (userId == UserHandle.USER_SYSTEM) {
1011 return false;
1012 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001013 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001014 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001015 return false;
1016 }
1017 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001018 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001019 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001020 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001021 Integer user = userId;
1022 mBackgroundUsersRestartedHere.remove(user);
1023 }
1024 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1025 return false;
1026 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001027 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001028 return false;
1029 }
1030 } catch (RemoteException e) {
1031 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001032 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001033 }
1034 return true;
1035 }
1036
1037 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001038 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001039 */
felipeale8c5dce2020-04-15 11:27:06 -07001040 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1041 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1042 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001043
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001044 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001045 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1046 onUserSwitching(userId);
1047 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1048 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001049 }
1050
felipeale8c5dce2020-04-15 11:27:06 -07001051 // ...then notify listeners.
1052 UserLifecycleEvent event = new UserLifecycleEvent(eventType, userId);
1053
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001054 mHandler.post(() -> {
1055 handleNotifyServiceUserLifecycleListeners(event);
1056 handleNotifyAppUserLifecycleListeners(event);
1057 });
felipeale8c5dce2020-04-15 11:27:06 -07001058
1059 // Finally, update metrics.
1060 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1061 }
1062
1063 /**
1064 * Sets the first user unlocking metrics.
1065 */
1066 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1067 int halResponseTime) {
1068 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001069 }
1070
Mayank Garg7a114c82020-04-08 21:25:06 -07001071 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001072 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
1073 || mUserIdForUserSwitchInProcess != userId) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001074 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1075 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1076 }
1077 return;
1078 }
felipealf7368962020-04-16 12:55:19 -07001079 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1080 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -07001081 mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
1082 }
1083
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001084 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1085 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001086 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001087 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1088 Log.d(TAG_USER, "No app listener to be notified of " + event);
1089 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001090 return;
1091 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001092 // Must use a different TimingsTraceLog because it's another thread
1093 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1094 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1095 }
felipeal2a84d512020-04-06 18:52:15 -07001096 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001097 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1098 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1099 for (int i = 0; i < listenersSize; i++) {
1100 int uid = mAppLifecycleListeners.keyAt(i);
1101 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1102 Bundle data = new Bundle();
1103 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
1104 // TODO(b/144120654): should pass currentId from CarServiceHelperService so it
1105 // can set BUNDLE_PARAM_PREVIOUS_USER_ID (and unit test it)
felipeal2a84d512020-04-06 18:52:15 -07001106 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001107 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001108 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001109 try {
felipeal2a84d512020-04-06 18:52:15 -07001110 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001111 listener.send(userId, data);
1112 } catch (RemoteException e) {
1113 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1114 } finally {
1115 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001116 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001117 }
1118 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001119 }
1120
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001121 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001122 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1123 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001124 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001125 return;
felipeal2a84d512020-04-06 18:52:15 -07001126 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1127 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1128 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001129 }
felipeal2a84d512020-04-06 18:52:15 -07001130
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001131 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1132 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001133 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001134 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001135 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001136 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001137 listener.onEvent(event);
1138 } catch (RuntimeException e) {
1139 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001140 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001141 } finally {
1142 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001143 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001144 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001145 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001146 }
1147
felipeal98900c82020-04-09 09:05:02 -07001148 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001149 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1150 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001151 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001152
Felipe Lemef45ee502019-12-19 10:00:14 -08001153 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001154 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001155 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001156 if (mLastPassengerId != UserHandle.USER_NULL) {
1157 stopPassengerInternal(mLastPassengerId, false);
1158 }
1159 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1160 setupPassengerUser();
1161 startFirstPassenger(userId);
1162 }
felipeal98900c82020-04-09 09:05:02 -07001163 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001164 }
1165
1166 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001167 * 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 -08001168 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001169 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001170 * @param r Runnable to run.
1171 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001172 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001173 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001174 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001175 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001176 if (mUser0Unlocked) {
1177 runNow = true;
1178 } else {
1179 mUser0UnlockTasks.add(r);
1180 }
1181 }
1182 if (runNow) {
1183 r.run();
1184 }
1185 }
1186
Keun young Parkf3523cd2019-04-08 10:09:17 -07001187 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001188 @NonNull
1189 ArrayList<Integer> getBackgroundUsersToRestart() {
1190 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001191 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001192 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1193 }
1194 return backgroundUsersToRestart;
1195 }
1196
Ying Zheng1ab32b62018-06-26 12:47:26 -07001197 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001198 // Disable Location service for system user.
1199 LocationManager locationManager =
1200 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001201 locationManager.setLocationEnabledForUser(
1202 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001203 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001204
1205 /**
1206 * Creates a new user on the system, the created user would be granted admin role.
1207 *
1208 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001209 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001210 */
1211 @Nullable
1212 private UserInfo createNewAdminUser(String name) {
1213 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1214 // Only admins or system user can create other privileged users.
1215 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1216 return null;
1217 }
1218
1219 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1220 if (user == null) {
1221 // Couldn't create user, most likely because there are too many.
1222 Log.w(TAG_USER, "can't create admin user.");
1223 return null;
1224 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001225 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001226
1227 return user;
1228 }
1229
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001230 /**
1231 * Assigns a default icon to a user according to the user's id.
1232 *
1233 * @param userInfo User whose avatar is set to default icon.
1234 * @return Bitmap of the user icon.
1235 */
1236 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1237 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1238 Bitmap bitmap = UserIcons.convertToBitmap(
1239 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1240 mUserManager.setUserIcon(userInfo.id, bitmap);
1241 return bitmap;
1242 }
1243
Eric Jeong1545f3b2019-09-16 13:56:52 -07001244 private interface UserFilter {
1245 boolean isEligibleUser(UserInfo user);
1246 }
1247
1248 /** Returns all users who are matched by the given filter. */
1249 private List<UserInfo> getUsers(UserFilter filter) {
1250 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1251
1252 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1253 UserInfo user = iterator.next();
1254 if (!filter.isEligibleUser(user)) {
1255 iterator.remove();
1256 }
1257 }
1258 return users;
1259 }
1260
1261 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001262 * Enforces that apps which have the
1263 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1264 * can make certain calls to the CarUserManager.
1265 *
1266 * @param message used as message if SecurityException is thrown.
1267 * @throws SecurityException if the caller is not system or root.
1268 */
1269 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001270 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1271 }
1272
1273 private static void checkManageUsersOrDumpPermission(String message) {
1274 checkAtLeastOnePermission(message,
1275 android.Manifest.permission.MANAGE_USERS,
1276 android.Manifest.permission.DUMP);
1277 }
1278
Felipe Leme5528ff72020-02-10 19:05:14 -08001279 private void checkInteractAcrossUsersPermission(String message) {
1280 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1281 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1282 }
1283
felipeal2d0483c2019-11-02 14:07:22 -07001284 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001285 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001286 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1287 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001288 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001289 }
1290 }
1291
felipeal2d0483c2019-11-02 14:07:22 -07001292 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1293 for (String permission : permissions) {
1294 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1295 /* exported = */ true)
1296 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1297 return true;
1298 }
1299 }
1300 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001301 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001302
1303 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1304 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1305 // Count all users that are managed profiles of the given user.
1306 int managedProfilesCount = 0;
1307 for (UserInfo user : users) {
1308 if (user.isManagedProfile() && user.profileGroupId == userId) {
1309 managedProfilesCount++;
1310 }
1311 }
1312 return managedProfilesCount;
1313 }
1314
1315 /**
1316 * Starts the first passenger of the given driver and assigns the passenger to the front
1317 * passenger zone.
1318 *
1319 * @param driverId User id of the driver.
1320 * @return whether it succeeds.
1321 */
1322 private boolean startFirstPassenger(@UserIdInt int driverId) {
1323 int zoneId = getAvailablePassengerZone();
1324 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1325 Log.w(TAG_USER, "passenger occupant zone is not found");
1326 return false;
1327 }
1328 List<UserInfo> passengers = getPassengers(driverId);
1329 if (passengers.size() < 1) {
1330 Log.w(TAG_USER, "passenger is not found");
1331 return false;
1332 }
1333 // Only one passenger is supported. If there are two or more passengers, the first passenger
1334 // is chosen.
1335 int passengerId = passengers.get(0).id;
1336 if (!startPassenger(passengerId, zoneId)) {
1337 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1338 return false;
1339 }
1340 return true;
1341 }
1342
1343 private int getAvailablePassengerZone() {
1344 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1345 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1346 for (int occupantType : occupantTypes) {
1347 int zoneId = getZoneId(occupantType);
1348 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1349 return zoneId;
1350 }
1351 }
1352 return OccupantZoneInfo.INVALID_ZONE_ID;
1353 }
1354
1355 /**
1356 * Creates a new passenger user when there is no passenger user.
1357 */
1358 private void setupPassengerUser() {
1359 int currentUser = ActivityManager.getCurrentUser();
1360 int profileCount = getNumberOfManagedProfiles(currentUser);
1361 if (profileCount > 0) {
1362 Log.w(TAG_USER, "max profile of user" + currentUser
1363 + " is exceeded: current profile count is " + profileCount);
1364 return;
1365 }
1366 // TODO(b/140311342): Use resource string for the default passenger name.
1367 UserInfo passenger = createPassenger("Passenger", currentUser);
1368 if (passenger == null) {
1369 // Couldn't create user, most likely because there are too many.
1370 Log.w(TAG_USER, "cannot create a passenger user");
1371 return;
1372 }
1373 }
1374
1375 @NonNull
1376 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1377 ZoneUserBindingHelper helper = null;
1378 synchronized (mLockHelper) {
1379 if (mZoneUserBindingHelper == null) {
1380 Log.w(TAG_USER, "implementation is not delegated");
1381 return new ArrayList<OccupantZoneInfo>();
1382 }
1383 helper = mZoneUserBindingHelper;
1384 }
1385 return helper.getOccupantZones(occupantType);
1386 }
1387
1388 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1389 ZoneUserBindingHelper helper = null;
1390 synchronized (mLockHelper) {
1391 if (mZoneUserBindingHelper == null) {
1392 Log.w(TAG_USER, "implementation is not delegated");
1393 return false;
1394 }
1395 helper = mZoneUserBindingHelper;
1396 }
1397 return helper.assignUserToOccupantZone(userId, zoneId);
1398 }
1399
1400 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1401 ZoneUserBindingHelper helper = null;
1402 synchronized (mLockHelper) {
1403 if (mZoneUserBindingHelper == null) {
1404 Log.w(TAG_USER, "implementation is not delegated");
1405 return false;
1406 }
1407 helper = mZoneUserBindingHelper;
1408 }
1409 return helper.unassignUserFromOccupantZone(userId);
1410 }
1411
1412 private boolean isPassengerDisplayAvailable() {
1413 ZoneUserBindingHelper helper = null;
1414 synchronized (mLockHelper) {
1415 if (mZoneUserBindingHelper == null) {
1416 Log.w(TAG_USER, "implementation is not delegated");
1417 return false;
1418 }
1419 helper = mZoneUserBindingHelper;
1420 }
1421 return helper.isPassengerDisplayAvailable();
1422 }
1423
1424 /**
1425 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1426 * zone is returned.
1427 *
1428 * @param occupantType The type of an occupant.
1429 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1430 * if not found.
1431 */
1432 private int getZoneId(@OccupantTypeEnum int occupantType) {
1433 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1434 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1435 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001436}