blob: b950369d84ae8d4b2efd25de9a86cd38f6f65031 [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;
Eric Jeongc91f9452019-08-30 15:04:21 -070066import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080067import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080068import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070069import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070070import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070071import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080072import com.android.internal.os.IResultReceiver;
felipeal2a84d512020-04-06 18:52:15 -070073import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070074import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070075import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076
77import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080078import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070079import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070080import java.util.Iterator;
81import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000082import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070083import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070084import java.util.concurrent.CountDownLatch;
85import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070086
87/**
88 * User service for cars. Manages users at boot time. Including:
89 *
90 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070091 * <li> Creates a user used as driver.
92 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070093 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070094 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070095 * <ol/>
96 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070097public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -080098
felipealf7368962020-04-16 12:55:19 -070099 private static final String TAG = TAG_USER;
100
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800101 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800102 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800103 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800104 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800105 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800106 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800107 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
108 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800109
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700110 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700111 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700112 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700113 private final UserManager mUserManager;
114 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700115 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700116
Eric Jeongc91f9452019-08-30 15:04:21 -0700117 private final Object mLockUser = new Object();
118 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800119 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700120 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800121 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700122 // Only one passenger is supported.
123 @GuardedBy("mLockUser")
124 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700125 /**
126 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800127 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700128 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700129 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700130 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
131 /**
132 * Keep the list of background users started here. This is wholly for debugging purpose.
133 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700134 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700135 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
136
Felipe Leme58412202020-01-09 13:45:33 -0800137 private final UserHalService mHal;
138
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700139 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
140 private final HandlerThread mHandlerThread;
141 private final Handler mHandler;
142
Felipe Leme5528ff72020-02-10 19:05:14 -0800143 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800144 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700145 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800146 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800148
149 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800150 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700151 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800152 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700153 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800154
Mayank Garg7a114c82020-04-08 21:25:06 -0700155 /**
156 * User Id for the user switch in process, if any.
157 */
158 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700159 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700160 /**
161 * Request Id for the user switch in process, if any.
162 */
163 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700164 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700165 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
166
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
168 new CopyOnWriteArrayList<>();
169
felipeal61ce3732020-04-03 11:01:00 -0700170 @Nullable
171 @GuardedBy("mLockUser")
172 private UserInfo mInitialUser;
173
felipeale8c5dce2020-04-15 11:27:06 -0700174 private final UserMetrics mUserMetrics = new UserMetrics();
175
Eric Jeongc91f9452019-08-30 15:04:21 -0700176 /** Interface for callbaks related to passenger activities. */
177 public interface PassengerCallback {
178 /** Called when passenger is started at a certain zone. */
179 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
180 /** Called when passenger is stopped. */
181 void onPassengerStopped(@UserIdInt int passengerId);
182 }
183
184 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
185 public interface ZoneUserBindingHelper {
186 /** Gets occupant zones corresponding to the occupant type. */
187 @NonNull
188 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
189 /** Assigns the user to the occupant zone. */
190 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
191 /** Makes the occupant zone unoccupied. */
192 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
193 /** Returns whether there is a passenger display. */
194 boolean isPassengerDisplayAvailable();
195 }
196
197 private final Object mLockHelper = new Object();
198 @GuardedBy("mLockHelper")
199 private ZoneUserBindingHelper mZoneUserBindingHelper;
200
Felipe Leme58412202020-01-09 13:45:33 -0800201 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
202 @NonNull CarUserManagerHelper carUserManagerHelper,
Eric Jeong3a793b02019-09-30 16:12:53 -0700203 @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700204 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
205 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700206 }
207 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800208 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700209 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700210 mAm = am;
211 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700212 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700213 mLastPassengerId = UserHandle.USER_NULL;
214 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700215 mHandlerThread = new HandlerThread(CarUserService.class.getSimpleName());
216 mHandlerThread.start();
217 mHandler = new Handler(mHandlerThread.getLooper());
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700218 }
219
220 @Override
221 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700222 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
223 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700224 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700225 }
226
227 @Override
228 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700229 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
230 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700231 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700232 }
233
234 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700235 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700236 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700237 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800238 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700239 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700240 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700241 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700242 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
243 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700244 }
245 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
246 List<UserInfo> allDrivers = getAllDrivers();
247 int driversSize = allDrivers.size();
248 writer.println("NumberOfDrivers: " + driversSize);
249 for (int i = 0; i < driversSize; i++) {
250 int driverId = allDrivers.get(i).id;
251 writer.print(indent + "#" + i + ": id=" + driverId);
252 List<UserInfo> passengers = getPassengers(driverId);
253 int passengersSize = passengers.size();
254 writer.print(" NumberPassengers: " + passengersSize);
255 if (passengersSize > 0) {
256 writer.print(" [");
257 for (int j = 0; j < passengersSize; j++) {
258 writer.print(passengers.get(j).id);
259 if (j < passengersSize - 1) {
260 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700261 }
felipeal2d0483c2019-11-02 14:07:22 -0700262 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700263 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700264 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700265 writer.println();
266 }
267 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
268 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
269 writer.printf("Initial user: %s\n", mInitialUser);
270 writer.println("Relevant overlayable properties");
271 Resources res = mContext.getResources();
272 writer.printf("%sowner_name=%s\n", indent,
273 res.getString(com.android.internal.R.string.owner_name));
274 writer.printf("%sdefault_guest_name=%s\n", indent,
275 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700276 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700277 writer.printf("Request Id for the user switch in process=%d\n ",
278 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700279
280 dumpUserMetrics(writer);
281 }
282
283 /**
284 * Dumps user metrics.
285 */
286 public void dumpUserMetrics(@NonNull PrintWriter writer) {
287 mUserMetrics.dump(writer);
288 }
289
290 /**
291 * Dumps first user unlocking time.
292 */
293 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
294 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700295 }
296
297 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
298 CountDownLatch latch = new CountDownLatch(1);
299 mHandler.post(() -> {
300 handleDumpUserLifecycleListeners(writer);
301 handleDumpAppLifecycleListeners(writer, indent);
302 latch.countDown();
303 });
304 int timeout = 5;
305 try {
306 if (!latch.await(timeout, TimeUnit.SECONDS)) {
307 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
308 timeout);
309 }
310 } catch (InterruptedException e) {
311 Thread.currentThread().interrupt();
312 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
313 }
314 }
315
316 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
317 if (mUserLifecycleListeners.isEmpty()) {
318 writer.println("No user lifecycle listeners");
319 return;
320 }
321 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
322 for (UserLifecycleListener listener : mUserLifecycleListeners) {
323 writer.printf("Listener %s\n", listener);
324 }
325 }
326
327 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
328 int numberListeners = mAppLifecycleListeners.size();
329 if (numberListeners == 0) {
330 writer.println("No lifecycle listeners");
331 return;
332 }
333 writer.printf("%d lifecycle listeners\n", numberListeners);
334 for (int i = 0; i < numberListeners; i++) {
335 int uid = mAppLifecycleListeners.keyAt(i);
336 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
337 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800338 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700339 }
340
341 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800342 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
343 *
344 * @param name The name of the driver to be created.
345 * @param admin Whether the created driver will be an admin.
346 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
347 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700348 */
349 @Override
350 @Nullable
351 public UserInfo createDriver(@NonNull String name, boolean admin) {
352 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000353 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700354 if (admin) {
355 return createNewAdminUser(name);
356 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700357 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700358 }
359
360 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800361 * Creates a passenger who is a profile of the given driver.
362 *
363 * @param name The name of the passenger to be created.
364 * @param driverId User id of the driver under whom a passenger is created.
365 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
366 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700367 */
368 @Override
369 @Nullable
370 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
371 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000372 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700373 UserInfo driver = mUserManager.getUserInfo(driverId);
374 if (driver == null) {
375 Log.w(TAG_USER, "the driver is invalid");
376 return null;
377 }
378 if (driver.isGuest()) {
379 Log.w(TAG_USER, "a guest driver cannot create a passenger");
380 return null;
381 }
Bookatz42fb1a62019-10-30 11:45:01 -0700382 UserInfo user = mUserManager.createProfileForUser(name,
383 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700384 if (user == null) {
385 // Couldn't create user, most likely because there are too many.
386 Log.w(TAG_USER, "can't create a profile for user" + driverId);
387 return null;
388 }
389 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700390 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700391 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700392 return user;
393 }
394
395 /**
396 * @see CarUserManager.switchDriver
397 */
398 @Override
399 public boolean switchDriver(@UserIdInt int driverId) {
400 checkManageUsersPermission("switchDriver");
401 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
402 // System user doesn't associate with real person, can not be switched to.
403 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
404 return false;
405 }
406 int userSwitchable = mUserManager.getUserSwitchability();
407 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
408 Log.w(TAG_USER, "current process is not allowed to switch user");
409 return false;
410 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700411 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700412 // The current user is already the given user.
413 return true;
414 }
415 try {
416 return mAm.switchUser(driverId);
417 } catch (RemoteException e) {
418 // ignore
419 Log.w(TAG_USER, "error while switching user", e);
420 }
421 return false;
422 }
423
424 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800425 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
426 *
427 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700428 */
429 @Override
430 @NonNull
431 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700432 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700433 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
434 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700435 }
436
437 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800438 * Returns all passengers under the given driver.
439 *
440 * @param driverId User id of a driver.
441 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700442 */
443 @Override
444 @NonNull
445 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700446 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 return getUsers((user) -> {
448 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
449 && user.profileGroupId == driverId;
450 });
451 }
452
453 /**
454 * @see CarUserManager.startPassenger
455 */
456 @Override
457 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
458 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700459 synchronized (mLockUser) {
460 try {
461 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
462 Log.w(TAG_USER, "could not start passenger");
463 return false;
464 }
465 } catch (RemoteException e) {
466 // ignore
467 Log.w(TAG_USER, "error while starting passenger", e);
468 return false;
469 }
470 if (!assignUserToOccupantZone(passengerId, zoneId)) {
471 Log.w(TAG_USER, "could not assign passenger to zone");
472 return false;
473 }
474 mLastPassengerId = passengerId;
475 }
476 for (PassengerCallback callback : mPassengerCallbacks) {
477 callback.onPassengerStarted(passengerId, zoneId);
478 }
479 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700480 }
481
482 /**
483 * @see CarUserManager.stopPassenger
484 */
485 @Override
486 public boolean stopPassenger(@UserIdInt int passengerId) {
487 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700488 return stopPassengerInternal(passengerId, true);
489 }
490
491 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
492 synchronized (mLockUser) {
493 UserInfo passenger = mUserManager.getUserInfo(passengerId);
494 if (passenger == null) {
495 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
496 return false;
497 }
498 if (mLastPassengerId != passengerId) {
499 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
500 return true;
501 }
502 if (checkCurrentDriver) {
503 int currentUser = ActivityManager.getCurrentUser();
504 if (passenger.profileGroupId != currentUser) {
505 Log.w(TAG_USER, "passenger " + passengerId
506 + " is not a profile of the current user");
507 return false;
508 }
509 }
510 // Passenger is a profile, so cannot be stopped through activity manager.
511 // Instead, activities started by the passenger are stopped and the passenger is
512 // unassigned from the zone.
513 stopAllTasks(passengerId);
514 if (!unassignUserFromOccupantZone(passengerId)) {
515 Log.w(TAG_USER, "could not unassign user from occupant zone");
516 return false;
517 }
518 mLastPassengerId = UserHandle.USER_NULL;
519 }
520 for (PassengerCallback callback : mPassengerCallbacks) {
521 callback.onPassengerStopped(passengerId);
522 }
523 return true;
524 }
525
526 private void stopAllTasks(@UserIdInt int userId) {
527 try {
528 for (StackInfo info : mAm.getAllStackInfos()) {
529 for (int i = 0; i < info.taskIds.length; i++) {
530 if (info.taskUserIds[i] == userId) {
531 int taskId = info.taskIds[i];
532 if (!mAm.removeTask(taskId)) {
533 Log.w(TAG_USER, "could not remove task " + taskId);
534 }
535 }
536 }
537 }
538 } catch (RemoteException e) {
539 Log.e(TAG_USER, "could not get stack info", e);
540 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700541 }
542
Felipe Leme5528ff72020-02-10 19:05:14 -0800543 @Override
544 public void setLifecycleListenerForUid(IResultReceiver listener) {
545 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700546 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800547 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
548
549 try {
550 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
551 } catch (RemoteException e) {
552 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
553 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700554 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800555 }
556
557 private void onListenerDeath(int uid) {
558 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700559 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800560 }
561
562 @Override
563 public void resetLifecycleListenerForUid() {
564 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700565 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800566 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700567 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800568 }
569
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800570 @Override
571 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800572 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700573 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
574 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800575 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700576 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800577 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800578 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700579 Bundle resultData = null;
580 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700581 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
582 status, resp.action, resp.userToSwitchOrCreate.userId,
583 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700584 switch (resp.action) {
585 case InitialUserInfoResponseAction.SWITCH:
586 resultData = new Bundle();
587 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
588 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
589 break;
590 case InitialUserInfoResponseAction.CREATE:
591 resultData = new Bundle();
592 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
593 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
594 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
595 break;
596 case InitialUserInfoResponseAction.DEFAULT:
597 resultData = new Bundle();
598 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
599 break;
600 default:
601 // That's ok, it will be the same as DEFAULT...
602 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800603 }
felipeal312416a2020-04-14 12:28:24 -0700604 } else {
605 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800606 }
Mayank Garg0e239142020-04-14 19:16:31 -0700607 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800608 });
609 }
610
Felipe Lemee3cab982020-03-12 11:39:29 -0700611 /**
felipeal61ce3732020-04-03 11:01:00 -0700612 * Gets the initial foreground user after the device boots or resumes from suspension.
613 *
614 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
615 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
616 * method returns {@code null}.
617 *
618 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
619 * (like switching to the last active user), and this method will return the result of such
620 * operation.
621 *
622 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
623 * {@code null}.
624 *
625 * @hide
626 */
627 @Nullable
628 public UserInfo getInitialUser() {
629 checkInteractAcrossUsersPermission("getInitialUser");
630 synchronized (mLockUser) {
631 return mInitialUser;
632 }
633 }
634
635 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
636 // some reason passing the whole UserInfo through a raw binder transaction is not working.
637 /**
638 * Sets the initial foreground user after the device boots or resumes from suspension.
639 */
640 public void setInitialUser(@UserIdInt int userId) {
641 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
642 : mUserManager.getUserInfo(userId);
643 setInitialUser(initialUser);
644 }
645
646 /**
647 * Sets the initial foreground user after the device boots or resumes from suspension.
648 */
649 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700650 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
651 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700652 synchronized (mLockUser) {
653 mInitialUser = user;
654 }
655 if (user == null) {
656 // This mean InitialUserSetter failed and could not fallback, so the initial user was
657 // not switched (and most likely is SYSTEM_USER).
658 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
659 Log.wtf(TAG_USER, "Initial user set to null");
660 }
661 }
662
663 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700664 * Calls the User HAL to get the initial user info.
665 *
666 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
667 * @param callback callback to receive the results.
668 */
669 public void getInitialUserInfo(int requestType,
670 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700671 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
672 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700673 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700674 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700675 UsersInfo usersInfo = getUsersInfo();
676 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
677 }
678
679 /**
Mayank Garg59f22192020-03-27 00:51:45 -0700680 * Calls the User HAL to switch user.
681 *
Mayank Garge19c2922020-03-30 18:05:53 -0700682 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700683 * @param timeoutMs - timeout for HAL to wait
684 * @param receiver - receiver for the results
685 */
Mayank Garge19c2922020-03-30 18:05:53 -0700686 @Override
687 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700688 @NonNull AndroidFuture<UserSwitchResult> receiver) {
felipeal312416a2020-04-14 12:28:24 -0700689 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId,
690 timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700691 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700692 Objects.requireNonNull(receiver);
693 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700694 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700695
felipealf7368962020-04-16 12:55:19 -0700696 int currentUser = ActivityManager.getCurrentUser();
697 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700698 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
699 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
700 }
felipeale5bf0322020-04-16 15:10:57 -0700701 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
702 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700703 return;
704 }
705
Mayank Garg7a114c82020-04-08 21:25:06 -0700706 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700707 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
708 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
709 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
710 }
711
712 if (mUserIdForUserSwitchInProcess == targetUserId) {
felipeale5bf0322020-04-16 15:10:57 -0700713 int resultStatus = UserSwitchResult.STATUS_ANOTHER_REQUEST_IN_PROCESS;
714 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700715 return;
716 }
717 }
718
Mayank Garg59f22192020-03-27 00:51:45 -0700719 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700720 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700721 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700722 halTargetUser.userId = targetUser.id;
723 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
724 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700725 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
726 Log.d(TAG, "switch response: status="
727 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
728 }
729
felipeale5bf0322020-04-16 15:10:57 -0700730 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700731
732 if (status != HalCallback.STATUS_OK) {
733 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
734 Log.w(TAG, "invalid callback status ("
735 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
736 + resp);
felipeale5bf0322020-04-16 15:10:57 -0700737 sendResult(receiver, resultStatus);
felipealf7368962020-04-16 12:55:19 -0700738 return;
739 }
740 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status,
741 resp.status, resp.errorMessage);
742
felipealf7368962020-04-16 12:55:19 -0700743 switch (resp.status) {
744 case SwitchUserStatus.SUCCESS:
745 boolean result;
746 try {
747 result = mAm.switchUser(targetUserId);
748 if (result) {
felipeale5bf0322020-04-16 15:10:57 -0700749 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
felipealf7368962020-04-16 12:55:19 -0700750 updateUserSwitchInProcess(targetUserId, resp);
751 } else {
felipeale5bf0322020-04-16 15:10:57 -0700752 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700753 postSwitchHalResponse(resp.requestId, targetUserId);
Mayank Garg59f22192020-03-27 00:51:45 -0700754 }
felipealf7368962020-04-16 12:55:19 -0700755 } catch (RemoteException e) {
756 // ignore
757 Log.w(TAG_USER,
758 "error while switching user " + targetUser.toFullString(), e);
759 }
760 break;
761 case SwitchUserStatus.FAILURE:
762 // HAL failed to switch user
felipeale5bf0322020-04-16 15:10:57 -0700763 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700764 break;
Mayank Garg59f22192020-03-27 00:51:45 -0700765 }
felipeale5bf0322020-04-16 15:10:57 -0700766 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700767 });
768 }
769
Mayank Garg0e239142020-04-14 19:16:31 -0700770 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
771 @Nullable Bundle resultData) {
772 try {
773 receiver.send(resultCode, resultData);
774 } catch (RemoteException e) {
775 // ignore
776 Log.w(TAG_USER, "error while sending results", e);
777 }
778 }
779
felipeale5bf0322020-04-16 15:10:57 -0700780 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
781 @UserSwitchResult.Status int status) {
782 sendResult(receiver, status, /* errorMessage= */ null);
783 }
784
785 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
786 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
787 receiver.complete(new UserSwitchResult(status, errorMessage));
788 }
789
Mayank Garg7a114c82020-04-08 21:25:06 -0700790 private void updateUserSwitchInProcess(@UserIdInt int targetUserId,
791 @NonNull SwitchUserResponse resp) {
792 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700793 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700794 // Some other user switch is in process.
795 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
felipealf7368962020-04-16 12:55:19 -0700796 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
Mayank Garg7a114c82020-04-08 21:25:06 -0700797 + " is in process. Sending failed android post switch response for it "
798 + " as new user switch is requested for user: " + targetUserId);
799 }
felipealf7368962020-04-16 12:55:19 -0700800 postSwitchHalResponse(mRequestIdForUserSwitchInProcess,
801 mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700802 }
felipealf7368962020-04-16 12:55:19 -0700803 mUserIdForUserSwitchInProcess = targetUserId;
Mayank Garg7a114c82020-04-08 21:25:06 -0700804 mRequestIdForUserSwitchInProcess = resp.requestId;
805 }
806 }
807
808 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
809 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
810 UsersInfo usersInfo = getUsersInfo();
811 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
812 new android.hardware.automotive.vehicle.V2_0.UserInfo();
813 halTargetUser.userId = targetUser.id;
814 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700815 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
816 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700817 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
818 }
819
Mayank Garg59f22192020-03-27 00:51:45 -0700820 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700821 * Checks if the User HAL is supported.
822 */
823 public boolean isUserHalSupported() {
824 return mHal.isSupported();
825 }
826
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800827 // TODO(b/144120654): use helper to generate UsersInfo
828 private UsersInfo getUsersInfo() {
829 UserInfo currentUser;
830 try {
831 currentUser = mAm.getCurrentUser();
832 } catch (RemoteException e) {
833 // shouldn't happen
834 throw new IllegalStateException("Could not get current user: ", e);
835 }
836 List<UserInfo> existingUsers = mUserManager.getUsers();
837 int size = existingUsers.size();
838
839 UsersInfo usersInfo = new UsersInfo();
840 usersInfo.numberUsers = size;
841 usersInfo.currentUser.userId = currentUser.id;
842 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
843
844 for (int i = 0; i < size; i++) {
845 UserInfo androidUser = existingUsers.get(i);
846 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
847 new android.hardware.automotive.vehicle.V2_0.UserInfo();
848 halUser.userId = androidUser.id;
849 halUser.flags = UserHalHelper.convertFlags(androidUser);
850 usersInfo.existingUsers.add(halUser);
851 }
852
853 return usersInfo;
854 }
855
Eric Jeong1545f3b2019-09-16 13:56:52 -0700856 /** Returns whether the given user is a system user. */
857 private static boolean isSystemUser(@UserIdInt int userId) {
858 return userId == UserHandle.USER_SYSTEM;
859 }
860
Keun young Park13a7a822019-04-04 15:53:08 -0700861 private void updateDefaultUserRestriction() {
862 // We want to set restrictions on system and guest users only once. These are persisted
863 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
864 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700865 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
866 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700867 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700868 // Only apply the system user restrictions if the system user is headless.
869 if (UserManager.isHeadlessSystemUserMode()) {
870 setSystemUserRestrictions();
871 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700872 Settings.Global.putInt(mContext.getContentResolver(),
873 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700874 }
875
Eric Jeong1545f3b2019-09-16 13:56:52 -0700876 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700877 return !mUserManager.getUserInfo(userId).isEphemeral();
878 }
879
Antonio Kantekc8114752020-03-05 21:37:39 -0800880 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800881 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
882 */
883 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
884 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700885 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800886 }
887
888 /**
889 * Removes previously added {@link UserLifecycleListener}.
890 */
891 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
892 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700893 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800894 }
895
Eric Jeongc91f9452019-08-30 15:04:21 -0700896 /** Adds callback to listen to passenger activity events. */
897 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000898 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700899 mPassengerCallbacks.add(callback);
900 }
901
902 /** Removes previously added callback to listen passenger events. */
903 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000904 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700905 mPassengerCallbacks.remove(callback);
906 }
907
908 /** Sets the implementation of ZoneUserBindingHelper. */
909 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
910 synchronized (mLockHelper) {
911 mZoneUserBindingHelper = helper;
912 }
913 }
914
felipeal98900c82020-04-09 09:05:02 -0700915 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -0800916 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -0700917 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -0700918 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700919 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700920 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
921 updateDefaultUserRestriction();
922 tasks = new ArrayList<>(mUser0UnlockTasks);
923 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -0700924 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700925 }
926 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700927 Integer user = userId;
928 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700929 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -0700930 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700931 mBackgroundUsersToRestart.remove(user);
932 mBackgroundUsersToRestart.add(0, user);
933 }
934 // -1 for user 0
935 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700936 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700937 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700938 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700939 + ", dropping least recently user from restart list:" + userToDrop);
940 // Drop the least recently used user.
941 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
942 }
943 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800944 }
945 }
946 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700947 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800948 for (Runnable r : tasks) {
949 r.run();
950 }
951 }
952 }
953
954 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700955 * Starts all background users that were active in system.
956 *
Keun young Parkfb656372019-03-12 18:37:55 -0700957 * @return list of background users started successfully.
958 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700959 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700960 public ArrayList<Integer> startAllBackgroundUsers() {
961 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -0700962 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700963 users = new ArrayList<>(mBackgroundUsersToRestart);
964 mBackgroundUsersRestartedHere.clear();
965 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700966 }
967 ArrayList<Integer> startedUsers = new ArrayList<>();
968 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -0700969 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700970 continue;
971 }
972 try {
973 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700974 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
975 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700976 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700977 } else if (mAm.unlockUser(user, null, null, null)) {
978 startedUsers.add(user);
979 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700980 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700981 if (mUserManager.isUserRunning(user)) {
982 // add to started list so that it can be stopped later.
983 startedUsers.add(user);
984 }
Keun young Parkfb656372019-03-12 18:37:55 -0700985 }
986 }
987 } catch (RemoteException e) {
988 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700989 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700990 }
991 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700992 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -0700993 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700994 ArrayList<Integer> usersToRemove = new ArrayList<>();
995 for (Integer user : mBackgroundUsersToRestart) {
996 if (!startedUsers.contains(user)) {
997 usersToRemove.add(user);
998 }
999 }
1000 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1001 }
Keun young Parkfb656372019-03-12 18:37:55 -07001002 return startedUsers;
1003 }
1004
1005 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001006 * Stops all background users that were active in system.
1007 *
1008 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001009 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001010 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001011 if (userId == UserHandle.USER_SYSTEM) {
1012 return false;
1013 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001014 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001015 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001016 return false;
1017 }
1018 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001019 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001020 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001021 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001022 Integer user = userId;
1023 mBackgroundUsersRestartedHere.remove(user);
1024 }
1025 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1026 return false;
1027 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001028 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001029 return false;
1030 }
1031 } catch (RemoteException e) {
1032 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001033 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001034 }
1035 return true;
1036 }
1037
1038 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001039 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001040 */
felipeale8c5dce2020-04-15 11:27:06 -07001041 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1042 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1043 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001044
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001045 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001046 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1047 onUserSwitching(userId);
1048 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1049 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001050 }
1051
felipeale8c5dce2020-04-15 11:27:06 -07001052 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001053 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001054
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001055 mHandler.post(() -> {
1056 handleNotifyServiceUserLifecycleListeners(event);
1057 handleNotifyAppUserLifecycleListeners(event);
1058 });
felipeale8c5dce2020-04-15 11:27:06 -07001059
1060 // Finally, update metrics.
1061 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1062 }
1063
1064 /**
1065 * Sets the first user unlocking metrics.
1066 */
1067 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1068 int halResponseTime) {
1069 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001070 }
1071
Mayank Garg7a114c82020-04-08 21:25:06 -07001072 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001073 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
1074 || mUserIdForUserSwitchInProcess != userId) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001075 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1076 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1077 }
1078 return;
1079 }
felipealf7368962020-04-16 12:55:19 -07001080 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1081 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -07001082 mRequestIdForUserSwitchInProcess = UserHandle.USER_NULL;
1083 }
1084
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001085 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1086 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001087 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001088 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1089 Log.d(TAG_USER, "No app listener to be notified of " + event);
1090 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001091 return;
1092 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001093 // Must use a different TimingsTraceLog because it's another thread
1094 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1095 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1096 }
felipeal2a84d512020-04-06 18:52:15 -07001097 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001098 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1099 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1100 for (int i = 0; i < listenersSize; i++) {
1101 int uid = mAppLifecycleListeners.keyAt(i);
1102 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1103 Bundle data = new Bundle();
1104 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001105
1106 int fromUid = event.getPreviousUserId();
1107 if (fromUid != UserHandle.USER_NULL) {
1108 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1109 }
1110
felipeal2a84d512020-04-06 18:52:15 -07001111 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001112 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001113 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001114 try {
felipeal2a84d512020-04-06 18:52:15 -07001115 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001116 listener.send(userId, data);
1117 } catch (RemoteException e) {
1118 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1119 } finally {
1120 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001121 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001122 }
1123 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001124 }
1125
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001126 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001127 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1128 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001129 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001130 return;
felipeal2a84d512020-04-06 18:52:15 -07001131 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1132 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1133 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001134 }
felipeal2a84d512020-04-06 18:52:15 -07001135
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001136 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1137 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001138 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001139 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001140 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001141 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001142 listener.onEvent(event);
1143 } catch (RuntimeException e) {
1144 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001145 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001146 } finally {
1147 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001148 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001149 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001150 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001151 }
1152
felipeal98900c82020-04-09 09:05:02 -07001153 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001154 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1155 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001156 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001157
Felipe Lemef45ee502019-12-19 10:00:14 -08001158 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001159 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001160 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001161 if (mLastPassengerId != UserHandle.USER_NULL) {
1162 stopPassengerInternal(mLastPassengerId, false);
1163 }
1164 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1165 setupPassengerUser();
1166 startFirstPassenger(userId);
1167 }
felipeal98900c82020-04-09 09:05:02 -07001168 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001169 }
1170
1171 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001172 * 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 -08001173 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001174 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001175 * @param r Runnable to run.
1176 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001177 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001178 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001179 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001180 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001181 if (mUser0Unlocked) {
1182 runNow = true;
1183 } else {
1184 mUser0UnlockTasks.add(r);
1185 }
1186 }
1187 if (runNow) {
1188 r.run();
1189 }
1190 }
1191
Keun young Parkf3523cd2019-04-08 10:09:17 -07001192 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001193 @NonNull
1194 ArrayList<Integer> getBackgroundUsersToRestart() {
1195 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001196 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001197 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1198 }
1199 return backgroundUsersToRestart;
1200 }
1201
Ying Zheng1ab32b62018-06-26 12:47:26 -07001202 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001203 // Disable Location service for system user.
1204 LocationManager locationManager =
1205 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001206 locationManager.setLocationEnabledForUser(
1207 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001208 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001209
1210 /**
1211 * Creates a new user on the system, the created user would be granted admin role.
1212 *
1213 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001214 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001215 */
1216 @Nullable
1217 private UserInfo createNewAdminUser(String name) {
1218 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1219 // Only admins or system user can create other privileged users.
1220 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1221 return null;
1222 }
1223
1224 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1225 if (user == null) {
1226 // Couldn't create user, most likely because there are too many.
1227 Log.w(TAG_USER, "can't create admin user.");
1228 return null;
1229 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001230 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001231
1232 return user;
1233 }
1234
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001235 /**
1236 * Assigns a default icon to a user according to the user's id.
1237 *
1238 * @param userInfo User whose avatar is set to default icon.
1239 * @return Bitmap of the user icon.
1240 */
1241 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1242 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1243 Bitmap bitmap = UserIcons.convertToBitmap(
1244 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1245 mUserManager.setUserIcon(userInfo.id, bitmap);
1246 return bitmap;
1247 }
1248
Eric Jeong1545f3b2019-09-16 13:56:52 -07001249 private interface UserFilter {
1250 boolean isEligibleUser(UserInfo user);
1251 }
1252
1253 /** Returns all users who are matched by the given filter. */
1254 private List<UserInfo> getUsers(UserFilter filter) {
1255 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1256
1257 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1258 UserInfo user = iterator.next();
1259 if (!filter.isEligibleUser(user)) {
1260 iterator.remove();
1261 }
1262 }
1263 return users;
1264 }
1265
1266 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001267 * Enforces that apps which have the
1268 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1269 * can make certain calls to the CarUserManager.
1270 *
1271 * @param message used as message if SecurityException is thrown.
1272 * @throws SecurityException if the caller is not system or root.
1273 */
1274 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001275 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1276 }
1277
1278 private static void checkManageUsersOrDumpPermission(String message) {
1279 checkAtLeastOnePermission(message,
1280 android.Manifest.permission.MANAGE_USERS,
1281 android.Manifest.permission.DUMP);
1282 }
1283
Felipe Leme5528ff72020-02-10 19:05:14 -08001284 private void checkInteractAcrossUsersPermission(String message) {
1285 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1286 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1287 }
1288
felipeal2d0483c2019-11-02 14:07:22 -07001289 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001290 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001291 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1292 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001293 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001294 }
1295 }
1296
felipeal2d0483c2019-11-02 14:07:22 -07001297 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1298 for (String permission : permissions) {
1299 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1300 /* exported = */ true)
1301 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1302 return true;
1303 }
1304 }
1305 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001306 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001307
1308 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1309 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1310 // Count all users that are managed profiles of the given user.
1311 int managedProfilesCount = 0;
1312 for (UserInfo user : users) {
1313 if (user.isManagedProfile() && user.profileGroupId == userId) {
1314 managedProfilesCount++;
1315 }
1316 }
1317 return managedProfilesCount;
1318 }
1319
1320 /**
1321 * Starts the first passenger of the given driver and assigns the passenger to the front
1322 * passenger zone.
1323 *
1324 * @param driverId User id of the driver.
1325 * @return whether it succeeds.
1326 */
1327 private boolean startFirstPassenger(@UserIdInt int driverId) {
1328 int zoneId = getAvailablePassengerZone();
1329 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1330 Log.w(TAG_USER, "passenger occupant zone is not found");
1331 return false;
1332 }
1333 List<UserInfo> passengers = getPassengers(driverId);
1334 if (passengers.size() < 1) {
1335 Log.w(TAG_USER, "passenger is not found");
1336 return false;
1337 }
1338 // Only one passenger is supported. If there are two or more passengers, the first passenger
1339 // is chosen.
1340 int passengerId = passengers.get(0).id;
1341 if (!startPassenger(passengerId, zoneId)) {
1342 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1343 return false;
1344 }
1345 return true;
1346 }
1347
1348 private int getAvailablePassengerZone() {
1349 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1350 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1351 for (int occupantType : occupantTypes) {
1352 int zoneId = getZoneId(occupantType);
1353 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1354 return zoneId;
1355 }
1356 }
1357 return OccupantZoneInfo.INVALID_ZONE_ID;
1358 }
1359
1360 /**
1361 * Creates a new passenger user when there is no passenger user.
1362 */
1363 private void setupPassengerUser() {
1364 int currentUser = ActivityManager.getCurrentUser();
1365 int profileCount = getNumberOfManagedProfiles(currentUser);
1366 if (profileCount > 0) {
1367 Log.w(TAG_USER, "max profile of user" + currentUser
1368 + " is exceeded: current profile count is " + profileCount);
1369 return;
1370 }
1371 // TODO(b/140311342): Use resource string for the default passenger name.
1372 UserInfo passenger = createPassenger("Passenger", currentUser);
1373 if (passenger == null) {
1374 // Couldn't create user, most likely because there are too many.
1375 Log.w(TAG_USER, "cannot create a passenger user");
1376 return;
1377 }
1378 }
1379
1380 @NonNull
1381 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1382 ZoneUserBindingHelper helper = null;
1383 synchronized (mLockHelper) {
1384 if (mZoneUserBindingHelper == null) {
1385 Log.w(TAG_USER, "implementation is not delegated");
1386 return new ArrayList<OccupantZoneInfo>();
1387 }
1388 helper = mZoneUserBindingHelper;
1389 }
1390 return helper.getOccupantZones(occupantType);
1391 }
1392
1393 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
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.assignUserToOccupantZone(userId, zoneId);
1403 }
1404
1405 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1406 ZoneUserBindingHelper helper = null;
1407 synchronized (mLockHelper) {
1408 if (mZoneUserBindingHelper == null) {
1409 Log.w(TAG_USER, "implementation is not delegated");
1410 return false;
1411 }
1412 helper = mZoneUserBindingHelper;
1413 }
1414 return helper.unassignUserFromOccupantZone(userId);
1415 }
1416
1417 private boolean isPassengerDisplayAvailable() {
1418 ZoneUserBindingHelper helper = null;
1419 synchronized (mLockHelper) {
1420 if (mZoneUserBindingHelper == null) {
1421 Log.w(TAG_USER, "implementation is not delegated");
1422 return false;
1423 }
1424 helper = mZoneUserBindingHelper;
1425 }
1426 return helper.isPassengerDisplayAvailable();
1427 }
1428
1429 /**
1430 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1431 * zone is returned.
1432 *
1433 * @param occupantType The type of an occupant.
1434 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1435 * if not found.
1436 */
1437 private int getZoneId(@OccupantTypeEnum int occupantType) {
1438 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1439 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1440 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001441}