blob: b901ec2e0ef5094b112b92c6258088229d818e9c [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;
felipeal5e3ede42020-04-23 18:04:07 -070036import android.car.user.GetUserIdentificationAssociationResponse;
felipeale5bf0322020-04-16 15:10:57 -070037import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070038import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070039import android.car.userlib.HalCallback;
40import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070041import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070042import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070043import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070044import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070045import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080046import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070047import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070048import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
49import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080050import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070051import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070052import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080053import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070054import android.os.Handler;
55import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070056import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080057import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070058import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070059import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070060import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070061import android.sysprop.CarProperties;
felipeal312416a2020-04-14 12:28:24 -070062import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070063import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080064import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080065import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070066
67import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070068import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070069import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080070import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080071import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070072import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070073import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070074import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080075import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070076import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070077import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070078import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070079import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070080
81import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080082import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070083import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070084import java.util.Iterator;
85import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000086import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070087import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070088import java.util.concurrent.CountDownLatch;
89import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070090
91/**
92 * User service for cars. Manages users at boot time. Including:
93 *
94 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070095 * <li> Creates a user used as driver.
96 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070098 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070099 * <ol/>
100 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700101public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800102
felipealf7368962020-04-16 12:55:19 -0700103 private static final String TAG = TAG_USER;
104
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800105 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800106 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800107 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800108 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800109 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800110 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800111 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
112 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800113
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700115 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700116 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700117 private final UserManager mUserManager;
118 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700119 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700120
Eric Jeongc91f9452019-08-30 15:04:21 -0700121 private final Object mLockUser = new Object();
122 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800123 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700124 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800125 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700126 // Only one passenger is supported.
127 @GuardedBy("mLockUser")
128 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700129 /**
130 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800131 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700132 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700133 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700134 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
135 /**
136 * Keep the list of background users started here. This is wholly for debugging purpose.
137 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700138 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700139 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
140
Felipe Leme58412202020-01-09 13:45:33 -0800141 private final UserHalService mHal;
142
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700143 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700144 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
145 getClass().getSimpleName());
146 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147
Felipe Leme5528ff72020-02-10 19:05:14 -0800148 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800149 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700150 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800151 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700152 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800153
154 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800155 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700156 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800157 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700158 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800159
Mayank Garg7a114c82020-04-08 21:25:06 -0700160 /**
161 * User Id for the user switch in process, if any.
162 */
163 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700164 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700165 /**
166 * Request Id for the user switch in process, if any.
167 */
168 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700169 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700170 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
171
Eric Jeongc91f9452019-08-30 15:04:21 -0700172 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
173 new CopyOnWriteArrayList<>();
174
felipeal61ce3732020-04-03 11:01:00 -0700175 @Nullable
176 @GuardedBy("mLockUser")
177 private UserInfo mInitialUser;
178
Mayank Garg71661ea2020-04-29 01:25:03 -0700179 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700180
Mayank Garg587f1942020-05-06 01:41:34 -0700181 private IResultReceiver mUserSwitchUiReceiver;
182
Eric Jeongc91f9452019-08-30 15:04:21 -0700183 /** Interface for callbaks related to passenger activities. */
184 public interface PassengerCallback {
185 /** Called when passenger is started at a certain zone. */
186 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
187 /** Called when passenger is stopped. */
188 void onPassengerStopped(@UserIdInt int passengerId);
189 }
190
191 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
192 public interface ZoneUserBindingHelper {
193 /** Gets occupant zones corresponding to the occupant type. */
194 @NonNull
195 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
196 /** Assigns the user to the occupant zone. */
197 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
198 /** Makes the occupant zone unoccupied. */
199 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
200 /** Returns whether there is a passenger display. */
201 boolean isPassengerDisplayAvailable();
202 }
203
204 private final Object mLockHelper = new Object();
205 @GuardedBy("mLockHelper")
206 private ZoneUserBindingHelper mZoneUserBindingHelper;
207
Felipe Leme58412202020-01-09 13:45:33 -0800208 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700209 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
210 @NonNull IActivityManager am, int maxRunningUsers) {
211 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
212 new UserMetrics());
213 }
214
215 @VisibleForTesting
216 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
217 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
218 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700219 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
220 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700221 }
222 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800223 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700224 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700225 mAm = am;
226 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700227 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700228 mLastPassengerId = UserHandle.USER_NULL;
229 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700230 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700231 }
232
233 @Override
234 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700235 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
236 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700237 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700238 }
239
240 @Override
241 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700242 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
243 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700244 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700245 }
246
247 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700249 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700250 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800251 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700252 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700253 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700254 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700255 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700256 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
257 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700258 }
259 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
260 List<UserInfo> allDrivers = getAllDrivers();
261 int driversSize = allDrivers.size();
262 writer.println("NumberOfDrivers: " + driversSize);
263 for (int i = 0; i < driversSize; i++) {
264 int driverId = allDrivers.get(i).id;
265 writer.print(indent + "#" + i + ": id=" + driverId);
266 List<UserInfo> passengers = getPassengers(driverId);
267 int passengersSize = passengers.size();
268 writer.print(" NumberPassengers: " + passengersSize);
269 if (passengersSize > 0) {
270 writer.print(" [");
271 for (int j = 0; j < passengersSize; j++) {
272 writer.print(passengers.get(j).id);
273 if (j < passengersSize - 1) {
274 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700275 }
felipeal2d0483c2019-11-02 14:07:22 -0700276 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700277 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700278 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700279 writer.println();
280 }
281 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
282 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
283 writer.printf("Initial user: %s\n", mInitialUser);
284 writer.println("Relevant overlayable properties");
285 Resources res = mContext.getResources();
286 writer.printf("%sowner_name=%s\n", indent,
287 res.getString(com.android.internal.R.string.owner_name));
288 writer.printf("%sdefault_guest_name=%s\n", indent,
289 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700290 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700291 writer.printf("Request Id for the user switch in process=%d\n ",
292 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700293
294 dumpUserMetrics(writer);
295 }
296
297 /**
298 * Dumps user metrics.
299 */
300 public void dumpUserMetrics(@NonNull PrintWriter writer) {
301 mUserMetrics.dump(writer);
302 }
303
304 /**
305 * Dumps first user unlocking time.
306 */
307 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
308 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700309 }
310
311 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
312 CountDownLatch latch = new CountDownLatch(1);
313 mHandler.post(() -> {
314 handleDumpUserLifecycleListeners(writer);
315 handleDumpAppLifecycleListeners(writer, indent);
316 latch.countDown();
317 });
318 int timeout = 5;
319 try {
320 if (!latch.await(timeout, TimeUnit.SECONDS)) {
321 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
322 timeout);
323 }
324 } catch (InterruptedException e) {
325 Thread.currentThread().interrupt();
326 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
327 }
328 }
329
330 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
331 if (mUserLifecycleListeners.isEmpty()) {
332 writer.println("No user lifecycle listeners");
333 return;
334 }
335 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
336 for (UserLifecycleListener listener : mUserLifecycleListeners) {
337 writer.printf("Listener %s\n", listener);
338 }
339 }
340
341 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
342 int numberListeners = mAppLifecycleListeners.size();
343 if (numberListeners == 0) {
344 writer.println("No lifecycle listeners");
345 return;
346 }
347 writer.printf("%d lifecycle listeners\n", numberListeners);
348 for (int i = 0; i < numberListeners; i++) {
349 int uid = mAppLifecycleListeners.keyAt(i);
350 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
351 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800352 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700353 }
354
355 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800356 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
357 *
358 * @param name The name of the driver to be created.
359 * @param admin Whether the created driver will be an admin.
360 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
361 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700362 */
363 @Override
364 @Nullable
365 public UserInfo createDriver(@NonNull String name, boolean admin) {
366 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000367 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700368 if (admin) {
369 return createNewAdminUser(name);
370 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700371 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700372 }
373
374 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800375 * Creates a passenger who is a profile of the given driver.
376 *
377 * @param name The name of the passenger to be created.
378 * @param driverId User id of the driver under whom a passenger is created.
379 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
380 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700381 */
382 @Override
383 @Nullable
384 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
385 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000386 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700387 UserInfo driver = mUserManager.getUserInfo(driverId);
388 if (driver == null) {
389 Log.w(TAG_USER, "the driver is invalid");
390 return null;
391 }
392 if (driver.isGuest()) {
393 Log.w(TAG_USER, "a guest driver cannot create a passenger");
394 return null;
395 }
Bookatz42fb1a62019-10-30 11:45:01 -0700396 UserInfo user = mUserManager.createProfileForUser(name,
397 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700398 if (user == null) {
399 // Couldn't create user, most likely because there are too many.
400 Log.w(TAG_USER, "can't create a profile for user" + driverId);
401 return null;
402 }
403 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700404 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700405 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700406 return user;
407 }
408
409 /**
410 * @see CarUserManager.switchDriver
411 */
412 @Override
413 public boolean switchDriver(@UserIdInt int driverId) {
414 checkManageUsersPermission("switchDriver");
415 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
416 // System user doesn't associate with real person, can not be switched to.
417 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
418 return false;
419 }
420 int userSwitchable = mUserManager.getUserSwitchability();
421 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
422 Log.w(TAG_USER, "current process is not allowed to switch user");
423 return false;
424 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700425 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700426 // The current user is already the given user.
427 return true;
428 }
429 try {
430 return mAm.switchUser(driverId);
431 } catch (RemoteException e) {
432 // ignore
433 Log.w(TAG_USER, "error while switching user", e);
434 }
435 return false;
436 }
437
438 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800439 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
440 *
441 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700442 */
443 @Override
444 @NonNull
445 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700446 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700447 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
448 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700449 }
450
451 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800452 * Returns all passengers under the given driver.
453 *
454 * @param driverId User id of a driver.
455 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700456 */
457 @Override
458 @NonNull
459 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700460 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700461 return getUsers((user) -> {
462 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
463 && user.profileGroupId == driverId;
464 });
465 }
466
467 /**
468 * @see CarUserManager.startPassenger
469 */
470 @Override
471 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
472 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700473 synchronized (mLockUser) {
474 try {
475 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
476 Log.w(TAG_USER, "could not start passenger");
477 return false;
478 }
479 } catch (RemoteException e) {
480 // ignore
481 Log.w(TAG_USER, "error while starting passenger", e);
482 return false;
483 }
484 if (!assignUserToOccupantZone(passengerId, zoneId)) {
485 Log.w(TAG_USER, "could not assign passenger to zone");
486 return false;
487 }
488 mLastPassengerId = passengerId;
489 }
490 for (PassengerCallback callback : mPassengerCallbacks) {
491 callback.onPassengerStarted(passengerId, zoneId);
492 }
493 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700494 }
495
496 /**
497 * @see CarUserManager.stopPassenger
498 */
499 @Override
500 public boolean stopPassenger(@UserIdInt int passengerId) {
501 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700502 return stopPassengerInternal(passengerId, true);
503 }
504
505 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
506 synchronized (mLockUser) {
507 UserInfo passenger = mUserManager.getUserInfo(passengerId);
508 if (passenger == null) {
509 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
510 return false;
511 }
512 if (mLastPassengerId != passengerId) {
513 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
514 return true;
515 }
516 if (checkCurrentDriver) {
517 int currentUser = ActivityManager.getCurrentUser();
518 if (passenger.profileGroupId != currentUser) {
519 Log.w(TAG_USER, "passenger " + passengerId
520 + " is not a profile of the current user");
521 return false;
522 }
523 }
524 // Passenger is a profile, so cannot be stopped through activity manager.
525 // Instead, activities started by the passenger are stopped and the passenger is
526 // unassigned from the zone.
527 stopAllTasks(passengerId);
528 if (!unassignUserFromOccupantZone(passengerId)) {
529 Log.w(TAG_USER, "could not unassign user from occupant zone");
530 return false;
531 }
532 mLastPassengerId = UserHandle.USER_NULL;
533 }
534 for (PassengerCallback callback : mPassengerCallbacks) {
535 callback.onPassengerStopped(passengerId);
536 }
537 return true;
538 }
539
540 private void stopAllTasks(@UserIdInt int userId) {
541 try {
542 for (StackInfo info : mAm.getAllStackInfos()) {
543 for (int i = 0; i < info.taskIds.length; i++) {
544 if (info.taskUserIds[i] == userId) {
545 int taskId = info.taskIds[i];
546 if (!mAm.removeTask(taskId)) {
547 Log.w(TAG_USER, "could not remove task " + taskId);
548 }
549 }
550 }
551 }
552 } catch (RemoteException e) {
553 Log.e(TAG_USER, "could not get stack info", e);
554 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700555 }
556
Felipe Leme5528ff72020-02-10 19:05:14 -0800557 @Override
558 public void setLifecycleListenerForUid(IResultReceiver listener) {
559 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700560 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800561 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
562
563 try {
564 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
565 } catch (RemoteException e) {
566 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
567 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700568 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800569 }
570
571 private void onListenerDeath(int uid) {
572 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700573 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800574 }
575
576 @Override
577 public void resetLifecycleListenerForUid() {
578 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700579 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800580 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700581 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800582 }
583
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800584 @Override
585 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800586 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700587 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
588 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800589 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700590 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800591 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800592 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700593 Bundle resultData = null;
594 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700595 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
596 status, resp.action, resp.userToSwitchOrCreate.userId,
597 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700598 switch (resp.action) {
599 case InitialUserInfoResponseAction.SWITCH:
600 resultData = new Bundle();
601 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
602 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
603 break;
604 case InitialUserInfoResponseAction.CREATE:
605 resultData = new Bundle();
606 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
607 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
608 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
609 break;
610 case InitialUserInfoResponseAction.DEFAULT:
611 resultData = new Bundle();
612 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
613 break;
614 default:
615 // That's ok, it will be the same as DEFAULT...
616 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800617 }
felipeal312416a2020-04-14 12:28:24 -0700618 } else {
619 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800620 }
Mayank Garg0e239142020-04-14 19:16:31 -0700621 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800622 });
623 }
624
Felipe Lemee3cab982020-03-12 11:39:29 -0700625 /**
felipeal61ce3732020-04-03 11:01:00 -0700626 * Gets the initial foreground user after the device boots or resumes from suspension.
627 *
628 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
629 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
630 * method returns {@code null}.
631 *
632 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
633 * (like switching to the last active user), and this method will return the result of such
634 * operation.
635 *
636 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
637 * {@code null}.
638 *
639 * @hide
640 */
641 @Nullable
642 public UserInfo getInitialUser() {
643 checkInteractAcrossUsersPermission("getInitialUser");
644 synchronized (mLockUser) {
645 return mInitialUser;
646 }
647 }
648
649 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
650 // some reason passing the whole UserInfo through a raw binder transaction is not working.
651 /**
652 * Sets the initial foreground user after the device boots or resumes from suspension.
653 */
654 public void setInitialUser(@UserIdInt int userId) {
655 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
656 : mUserManager.getUserInfo(userId);
657 setInitialUser(initialUser);
658 }
659
660 /**
661 * Sets the initial foreground user after the device boots or resumes from suspension.
662 */
663 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700664 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
665 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700666 synchronized (mLockUser) {
667 mInitialUser = user;
668 }
669 if (user == null) {
670 // This mean InitialUserSetter failed and could not fallback, so the initial user was
671 // not switched (and most likely is SYSTEM_USER).
672 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
673 Log.wtf(TAG_USER, "Initial user set to null");
674 }
675 }
676
677 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700678 * Calls the User HAL to get the initial user info.
679 *
680 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
681 * @param callback callback to receive the results.
682 */
683 public void getInitialUserInfo(int requestType,
684 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700685 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
686 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700687 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700688 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700689 UsersInfo usersInfo = getUsersInfo();
690 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
691 }
692
693 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700694 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
695 *
696 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700697 * When everything works well, the workflow is:
698 * <ol>
699 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
700 * type, current user id, target user id, and a callback.
701 * <li> HAL called back with SUCCESS.
702 * <li> {@link IActivityManager} is called for Android user switch.
703 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
704 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
705 * request type, current user id, and target user id. In this case, the current and target
706 * user IDs would be same.
707 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700708 *
709 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700710 * Corner cases:
711 * <ul>
712 * <li> If target user is already the current user, no user switch is performed and receiver
713 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
714 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
715 * {@code STATUS_HAL_INTERNAL_FAILURE}.
716 * <li> If HAL user switch call is successful, but android user switch call fails,
717 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
718 * target user id, but in this case the current and target user IDs would be different.
719 * <li> If another user switch request for the same target user is received while previous
720 * request is in process, receiver would receive
721 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
722 * <li> If a user switch request is received while another user switch request for different
723 * target user is in process, the previous request would be abandoned and new request will be
724 * processed. No POST_SWITCH would be sent for the previous request.
725 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700726 *
Mayank Garge19c2922020-03-30 18:05:53 -0700727 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700728 * @param timeoutMs - timeout for HAL to wait
729 * @param receiver - receiver for the results
730 */
Mayank Garge19c2922020-03-30 18:05:53 -0700731 @Override
732 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700733 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700734 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700735 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700736 Objects.requireNonNull(receiver);
737 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700738 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700739
felipealf7368962020-04-16 12:55:19 -0700740 int currentUser = ActivityManager.getCurrentUser();
741 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700742 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
743 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
744 }
felipeale5bf0322020-04-16 15:10:57 -0700745 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
746 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700747 return;
748 }
749
Mayank Garg7a114c82020-04-08 21:25:06 -0700750 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700751 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
752 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
753 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
754 }
755
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700756 // If there is another request for the same target user, return another request in
757 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
758 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
759 // user switch request in process for different target user, but that request is now
760 // ignored.
felipealf7368962020-04-16 12:55:19 -0700761 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700762 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
763 Log.d(TAG_USER,
764 "Another user switch request in process for the requested target user: "
765 + targetUserId);
766 }
767
768 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700769 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700770 return;
771 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700772 else {
773 mUserIdForUserSwitchInProcess = targetUserId;
774 mRequestIdForUserSwitchInProcess = 0;
775 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700776 }
777
Mayank Garg59f22192020-03-27 00:51:45 -0700778 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700779 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700780 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700781 halTargetUser.userId = targetUser.id;
782 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
783 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700784 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
785 Log.d(TAG, "switch response: status="
786 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
787 }
788
felipeale5bf0322020-04-16 15:10:57 -0700789 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700790
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700791 synchronized (mLockUser) {
792 if (status != HalCallback.STATUS_OK) {
793 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
794 Log.w(TAG, "invalid callback status ("
795 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
796 + resp);
797 sendResult(receiver, resultStatus);
798 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
799 return;
800 }
felipealf7368962020-04-16 12:55:19 -0700801
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700802 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
803 resp.errorMessage);
804
805 if (mUserIdForUserSwitchInProcess != targetUserId) {
806 // Another user switch request received while HAL responded. No need to process
807 // this request further
808 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
809 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
810 + "abondoned for : " + targetUserId + ". Current user in process: "
811 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700812 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700813 resultStatus =
814 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
815 sendResult(receiver, resultStatus);
816 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
817 return;
818 }
819
820 switch (resp.status) {
821 case SwitchUserStatus.SUCCESS:
822 boolean switched;
823 try {
824 switched = mAm.switchUser(targetUserId);
825 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700826 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700827 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
828 mRequestIdForUserSwitchInProcess = resp.requestId;
829 } else {
830 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
831 postSwitchHalResponse(resp.requestId, targetUserId);
832 }
833 } catch (RemoteException e) {
834 // ignore
835 Log.w(TAG_USER,
836 "error while switching user " + targetUser.toFullString(), e);
837 }
838 break;
839 case SwitchUserStatus.FAILURE:
840 // HAL failed to switch user
841 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
842 break;
843 }
844
845 if (mRequestIdForUserSwitchInProcess == 0) {
846 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
847 }
Mayank Garg59f22192020-03-27 00:51:45 -0700848 }
felipeale5bf0322020-04-16 15:10:57 -0700849 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700850 });
851 }
852
Mayank Garg587f1942020-05-06 01:41:34 -0700853 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
854 if (mUserSwitchUiReceiver == null) {
855 Log.w(TAG_USER, "No User switch UI receiver.");
856 return;
857 }
858
859 try {
860 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
861 mUserSwitchUiReceiver.send(targetUserId, null);
862 } catch (RemoteException e) {
863 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
864 }
865 }
866
felipeal5e3ede42020-04-23 18:04:07 -0700867 @Override
868 public GetUserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
869 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
870 checkManageUsersPermission("getUserIdentificationAssociation");
871
872 int uid = getCallingUid();
873 int userId = UserHandle.getUserId(uid);
874 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
875
876 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
877 request.userInfo.userId = userId;
878 request.userInfo.flags = getHalUserInfoFlags(userId);
879
880 request.numberAssociationTypes = types.length;
881 for (int i = 0; i < types.length; i++) {
882 request.associationTypes.add(types[i]);
883 }
884
885 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
886 if (halResponse == null) {
887 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
888 + Arrays.toString(types));
889 return null;
890 }
891
892 int[] values = new int[halResponse.associations.size()];
893 for (int i = 0; i < values.length; i++) {
894 values[i] = halResponse.associations.get(i).value;
895 }
896 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
897
898 return new GetUserIdentificationAssociationResponse(halResponse.errorMessage, values);
899 }
900
901 /**
902 * Gets the User HAL flags for the given user.
903 *
904 * @throws IllegalArgumentException if the user does not exist.
905 */
906 private int getHalUserInfoFlags(@UserIdInt int userId) {
907 UserInfo user = mUserManager.getUserInfo(userId);
908 Preconditions.checkArgument(user != null, "no user for id %d", userId);
909 return UserHalHelper.convertFlags(user);
910 }
911
Mayank Garg0e239142020-04-14 19:16:31 -0700912 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
913 @Nullable Bundle resultData) {
914 try {
915 receiver.send(resultCode, resultData);
916 } catch (RemoteException e) {
917 // ignore
918 Log.w(TAG_USER, "error while sending results", e);
919 }
920 }
921
felipeale5bf0322020-04-16 15:10:57 -0700922 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
923 @UserSwitchResult.Status int status) {
924 sendResult(receiver, status, /* errorMessage= */ null);
925 }
926
927 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
928 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
929 receiver.complete(new UserSwitchResult(status, errorMessage));
930 }
931
Mayank Garg7a114c82020-04-08 21:25:06 -0700932 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
933 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
934 UsersInfo usersInfo = getUsersInfo();
935 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
936 new android.hardware.automotive.vehicle.V2_0.UserInfo();
937 halTargetUser.userId = targetUser.id;
938 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700939 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
940 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700941 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
942 }
943
Mayank Garg59f22192020-03-27 00:51:45 -0700944 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700945 * Checks if the User HAL is supported.
946 */
947 public boolean isUserHalSupported() {
948 return mHal.isSupported();
949 }
950
Mayank Garg587f1942020-05-06 01:41:34 -0700951 /**
952 * Sets a callback which is invoked before user switch.
953 *
954 * <p>
955 * This method should only be called by the Car System UI. The purpose of this call is to notify
956 * Car System UI to show the user switch UI before the user switch.
957 */
958 @Override
959 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
960 // TODO(b/154958003): check UID, only carSysUI should be allowed to set it.
961 mUserSwitchUiReceiver = receiver;
962 }
963
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800964 // TODO(b/144120654): use helper to generate UsersInfo
965 private UsersInfo getUsersInfo() {
966 UserInfo currentUser;
967 try {
968 currentUser = mAm.getCurrentUser();
969 } catch (RemoteException e) {
970 // shouldn't happen
971 throw new IllegalStateException("Could not get current user: ", e);
972 }
Mayank Garge5de0f92020-04-23 21:38:38 -0700973 return getUsersInfo(currentUser);
974 }
975
976 // TODO(b/144120654): use helper to generate UsersInfo
977 private UsersInfo getUsersInfo(@NonNull UserInfo currentUser) {
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800978 List<UserInfo> existingUsers = mUserManager.getUsers();
979 int size = existingUsers.size();
980
981 UsersInfo usersInfo = new UsersInfo();
982 usersInfo.numberUsers = size;
983 usersInfo.currentUser.userId = currentUser.id;
984 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
985
986 for (int i = 0; i < size; i++) {
987 UserInfo androidUser = existingUsers.get(i);
988 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
989 new android.hardware.automotive.vehicle.V2_0.UserInfo();
990 halUser.userId = androidUser.id;
991 halUser.flags = UserHalHelper.convertFlags(androidUser);
992 usersInfo.existingUsers.add(halUser);
993 }
994
995 return usersInfo;
996 }
997
Eric Jeong1545f3b2019-09-16 13:56:52 -0700998 /** Returns whether the given user is a system user. */
999 private static boolean isSystemUser(@UserIdInt int userId) {
1000 return userId == UserHandle.USER_SYSTEM;
1001 }
1002
Keun young Park13a7a822019-04-04 15:53:08 -07001003 private void updateDefaultUserRestriction() {
1004 // We want to set restrictions on system and guest users only once. These are persisted
1005 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1006 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001007 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1008 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001009 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001010 // Only apply the system user restrictions if the system user is headless.
1011 if (UserManager.isHeadlessSystemUserMode()) {
1012 setSystemUserRestrictions();
1013 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001014 Settings.Global.putInt(mContext.getContentResolver(),
1015 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001016 }
1017
Eric Jeong1545f3b2019-09-16 13:56:52 -07001018 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001019 return !mUserManager.getUserInfo(userId).isEphemeral();
1020 }
1021
Antonio Kantekc8114752020-03-05 21:37:39 -08001022 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001023 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1024 */
1025 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1026 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001027 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001028 }
1029
1030 /**
1031 * Removes previously added {@link UserLifecycleListener}.
1032 */
1033 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1034 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001035 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001036 }
1037
Eric Jeongc91f9452019-08-30 15:04:21 -07001038 /** Adds callback to listen to passenger activity events. */
1039 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001040 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001041 mPassengerCallbacks.add(callback);
1042 }
1043
1044 /** Removes previously added callback to listen passenger events. */
1045 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001046 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001047 mPassengerCallbacks.remove(callback);
1048 }
1049
1050 /** Sets the implementation of ZoneUserBindingHelper. */
1051 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1052 synchronized (mLockHelper) {
1053 mZoneUserBindingHelper = helper;
1054 }
1055 }
1056
felipeal98900c82020-04-09 09:05:02 -07001057 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001058 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001059 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001060 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001061 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001062 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1063 updateDefaultUserRestriction();
1064 tasks = new ArrayList<>(mUser0UnlockTasks);
1065 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001066 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001067 }
1068 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001069 Integer user = userId;
1070 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001071 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001072 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001073 mBackgroundUsersToRestart.remove(user);
1074 mBackgroundUsersToRestart.add(0, user);
1075 }
1076 // -1 for user 0
1077 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001078 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001079 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001080 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001081 + ", dropping least recently user from restart list:" + userToDrop);
1082 // Drop the least recently used user.
1083 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1084 }
1085 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001086 }
1087 }
1088 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001089 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001090 for (Runnable r : tasks) {
1091 r.run();
1092 }
1093 }
1094 }
1095
1096 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001097 * Starts all background users that were active in system.
1098 *
Keun young Parkfb656372019-03-12 18:37:55 -07001099 * @return list of background users started successfully.
1100 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001101 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001102 public ArrayList<Integer> startAllBackgroundUsers() {
1103 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001104 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001105 users = new ArrayList<>(mBackgroundUsersToRestart);
1106 mBackgroundUsersRestartedHere.clear();
1107 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001108 }
1109 ArrayList<Integer> startedUsers = new ArrayList<>();
1110 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001111 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001112 continue;
1113 }
1114 try {
1115 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001116 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1117 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001118 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001119 } else if (mAm.unlockUser(user, null, null, null)) {
1120 startedUsers.add(user);
1121 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001122 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001123 if (mUserManager.isUserRunning(user)) {
1124 // add to started list so that it can be stopped later.
1125 startedUsers.add(user);
1126 }
Keun young Parkfb656372019-03-12 18:37:55 -07001127 }
1128 }
1129 } catch (RemoteException e) {
1130 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001131 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001132 }
1133 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001134 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001135 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001136 ArrayList<Integer> usersToRemove = new ArrayList<>();
1137 for (Integer user : mBackgroundUsersToRestart) {
1138 if (!startedUsers.contains(user)) {
1139 usersToRemove.add(user);
1140 }
1141 }
1142 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1143 }
Keun young Parkfb656372019-03-12 18:37:55 -07001144 return startedUsers;
1145 }
1146
1147 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001148 * Stops all background users that were active in system.
1149 *
1150 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001151 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001152 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001153 if (userId == UserHandle.USER_SYSTEM) {
1154 return false;
1155 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001156 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001157 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001158 return false;
1159 }
1160 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001161 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001162 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001163 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001164 Integer user = userId;
1165 mBackgroundUsersRestartedHere.remove(user);
1166 }
1167 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1168 return false;
1169 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001170 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001171 return false;
1172 }
1173 } catch (RemoteException e) {
1174 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001175 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001176 }
1177 return true;
1178 }
1179
1180 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001181 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001182 */
felipeale8c5dce2020-04-15 11:27:06 -07001183 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1184 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1185 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001186
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001187 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001188 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001189 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001190 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1191 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001192 }
1193
felipeale8c5dce2020-04-15 11:27:06 -07001194 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001195 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001196
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001197 mHandler.post(() -> {
1198 handleNotifyServiceUserLifecycleListeners(event);
1199 handleNotifyAppUserLifecycleListeners(event);
1200 });
felipeale8c5dce2020-04-15 11:27:06 -07001201
1202 // Finally, update metrics.
1203 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1204 }
1205
1206 /**
1207 * Sets the first user unlocking metrics.
1208 */
1209 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1210 int halResponseTime) {
1211 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001212 }
1213
Mayank Garg7a114c82020-04-08 21:25:06 -07001214 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001215 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001216 || mUserIdForUserSwitchInProcess != userId
1217 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001218 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1219 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1220 }
1221 return;
1222 }
felipealf7368962020-04-16 12:55:19 -07001223 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1224 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001225 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001226 }
1227
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001228 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1229 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001230 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001231 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1232 Log.d(TAG_USER, "No app listener to be notified of " + event);
1233 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001234 return;
1235 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001236 // Must use a different TimingsTraceLog because it's another thread
1237 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1238 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1239 }
felipeal2a84d512020-04-06 18:52:15 -07001240 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001241 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1242 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1243 for (int i = 0; i < listenersSize; i++) {
1244 int uid = mAppLifecycleListeners.keyAt(i);
1245 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1246 Bundle data = new Bundle();
1247 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001248
1249 int fromUid = event.getPreviousUserId();
1250 if (fromUid != UserHandle.USER_NULL) {
1251 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1252 }
1253
felipeal2a84d512020-04-06 18:52:15 -07001254 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001255 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001256 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001257 try {
felipeal2a84d512020-04-06 18:52:15 -07001258 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001259 listener.send(userId, data);
1260 } catch (RemoteException e) {
1261 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1262 } finally {
1263 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001264 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001265 }
1266 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001267 }
1268
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001269 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001270 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1271 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001272 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001273 return;
felipeal2a84d512020-04-06 18:52:15 -07001274 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1275 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1276 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001277 }
felipeal2a84d512020-04-06 18:52:15 -07001278
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001279 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1280 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001281 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001282 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001283 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001284 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001285 listener.onEvent(event);
1286 } catch (RuntimeException e) {
1287 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001288 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001289 } finally {
1290 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001291 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001292 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001293 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001294 }
1295
Mayank Garge5de0f92020-04-23 21:38:38 -07001296 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1297 Log.i(TAG_USER, "onSwitchUser() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001298 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001299 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001300
Mayank Garge5de0f92020-04-23 21:38:38 -07001301 // Switch HAL users if user switch is not requested by CarUserService
1302 notifyHalLegacySwitch(fromUserId, toUserId);
1303
1304 if (!isSystemUser(toUserId)) {
1305 mCarUserManagerHelper.setLastActiveUser(toUserId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001306 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001307 if (mLastPassengerId != UserHandle.USER_NULL) {
1308 stopPassengerInternal(mLastPassengerId, false);
1309 }
1310 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1311 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001312 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001313 }
felipeal98900c82020-04-09 09:05:02 -07001314 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001315 }
1316
Mayank Garge5de0f92020-04-23 21:38:38 -07001317 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1318 synchronized (mLockUser) {
1319 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1320 }
1321
1322 // switch HAL user
1323 UserInfo targetUser = mUserManager.getUserInfo(toUserId);
1324 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1325 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1326 halTargetUser.userId = targetUser.id;
1327 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
1328 UserInfo currentUser = mUserManager.getUserInfo(fromUserId);
1329 UsersInfo usersInfo = getUsersInfo(currentUser);
1330 mHal.legacyUserSwitch(halTargetUser, usersInfo);
1331 }
1332
Pavel Maltsev17e81832019-04-04 14:38:41 -07001333 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001334 * 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 -08001335 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001336 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001337 * @param r Runnable to run.
1338 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001339 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001340 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001341 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001342 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001343 if (mUser0Unlocked) {
1344 runNow = true;
1345 } else {
1346 mUser0UnlockTasks.add(r);
1347 }
1348 }
1349 if (runNow) {
1350 r.run();
1351 }
1352 }
1353
Keun young Parkf3523cd2019-04-08 10:09:17 -07001354 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001355 @NonNull
1356 ArrayList<Integer> getBackgroundUsersToRestart() {
1357 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001358 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001359 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1360 }
1361 return backgroundUsersToRestart;
1362 }
1363
Ying Zheng1ab32b62018-06-26 12:47:26 -07001364 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001365 // Disable Location service for system user.
1366 LocationManager locationManager =
1367 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001368 locationManager.setLocationEnabledForUser(
1369 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001370 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001371
1372 /**
1373 * Creates a new user on the system, the created user would be granted admin role.
1374 *
1375 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001376 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001377 */
1378 @Nullable
1379 private UserInfo createNewAdminUser(String name) {
1380 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1381 // Only admins or system user can create other privileged users.
1382 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1383 return null;
1384 }
1385
1386 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1387 if (user == null) {
1388 // Couldn't create user, most likely because there are too many.
1389 Log.w(TAG_USER, "can't create admin user.");
1390 return null;
1391 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001392 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001393
1394 return user;
1395 }
1396
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001397 /**
1398 * Assigns a default icon to a user according to the user's id.
1399 *
1400 * @param userInfo User whose avatar is set to default icon.
1401 * @return Bitmap of the user icon.
1402 */
1403 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1404 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1405 Bitmap bitmap = UserIcons.convertToBitmap(
1406 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1407 mUserManager.setUserIcon(userInfo.id, bitmap);
1408 return bitmap;
1409 }
1410
Eric Jeong1545f3b2019-09-16 13:56:52 -07001411 private interface UserFilter {
1412 boolean isEligibleUser(UserInfo user);
1413 }
1414
1415 /** Returns all users who are matched by the given filter. */
1416 private List<UserInfo> getUsers(UserFilter filter) {
1417 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1418
1419 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1420 UserInfo user = iterator.next();
1421 if (!filter.isEligibleUser(user)) {
1422 iterator.remove();
1423 }
1424 }
1425 return users;
1426 }
1427
1428 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001429 * Enforces that apps which have the
1430 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1431 * can make certain calls to the CarUserManager.
1432 *
1433 * @param message used as message if SecurityException is thrown.
1434 * @throws SecurityException if the caller is not system or root.
1435 */
1436 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001437 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1438 }
1439
1440 private static void checkManageUsersOrDumpPermission(String message) {
1441 checkAtLeastOnePermission(message,
1442 android.Manifest.permission.MANAGE_USERS,
1443 android.Manifest.permission.DUMP);
1444 }
1445
Felipe Leme5528ff72020-02-10 19:05:14 -08001446 private void checkInteractAcrossUsersPermission(String message) {
1447 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1448 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1449 }
1450
felipeal2d0483c2019-11-02 14:07:22 -07001451 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001452 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001453 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1454 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001455 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001456 }
1457 }
1458
felipeal2d0483c2019-11-02 14:07:22 -07001459 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1460 for (String permission : permissions) {
1461 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1462 /* exported = */ true)
1463 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1464 return true;
1465 }
1466 }
1467 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001468 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001469
1470 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1471 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1472 // Count all users that are managed profiles of the given user.
1473 int managedProfilesCount = 0;
1474 for (UserInfo user : users) {
1475 if (user.isManagedProfile() && user.profileGroupId == userId) {
1476 managedProfilesCount++;
1477 }
1478 }
1479 return managedProfilesCount;
1480 }
1481
1482 /**
1483 * Starts the first passenger of the given driver and assigns the passenger to the front
1484 * passenger zone.
1485 *
1486 * @param driverId User id of the driver.
1487 * @return whether it succeeds.
1488 */
1489 private boolean startFirstPassenger(@UserIdInt int driverId) {
1490 int zoneId = getAvailablePassengerZone();
1491 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1492 Log.w(TAG_USER, "passenger occupant zone is not found");
1493 return false;
1494 }
1495 List<UserInfo> passengers = getPassengers(driverId);
1496 if (passengers.size() < 1) {
1497 Log.w(TAG_USER, "passenger is not found");
1498 return false;
1499 }
1500 // Only one passenger is supported. If there are two or more passengers, the first passenger
1501 // is chosen.
1502 int passengerId = passengers.get(0).id;
1503 if (!startPassenger(passengerId, zoneId)) {
1504 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1505 return false;
1506 }
1507 return true;
1508 }
1509
1510 private int getAvailablePassengerZone() {
1511 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1512 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1513 for (int occupantType : occupantTypes) {
1514 int zoneId = getZoneId(occupantType);
1515 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1516 return zoneId;
1517 }
1518 }
1519 return OccupantZoneInfo.INVALID_ZONE_ID;
1520 }
1521
1522 /**
1523 * Creates a new passenger user when there is no passenger user.
1524 */
1525 private void setupPassengerUser() {
1526 int currentUser = ActivityManager.getCurrentUser();
1527 int profileCount = getNumberOfManagedProfiles(currentUser);
1528 if (profileCount > 0) {
1529 Log.w(TAG_USER, "max profile of user" + currentUser
1530 + " is exceeded: current profile count is " + profileCount);
1531 return;
1532 }
1533 // TODO(b/140311342): Use resource string for the default passenger name.
1534 UserInfo passenger = createPassenger("Passenger", currentUser);
1535 if (passenger == null) {
1536 // Couldn't create user, most likely because there are too many.
1537 Log.w(TAG_USER, "cannot create a passenger user");
1538 return;
1539 }
1540 }
1541
1542 @NonNull
1543 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1544 ZoneUserBindingHelper helper = null;
1545 synchronized (mLockHelper) {
1546 if (mZoneUserBindingHelper == null) {
1547 Log.w(TAG_USER, "implementation is not delegated");
1548 return new ArrayList<OccupantZoneInfo>();
1549 }
1550 helper = mZoneUserBindingHelper;
1551 }
1552 return helper.getOccupantZones(occupantType);
1553 }
1554
1555 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1556 ZoneUserBindingHelper helper = null;
1557 synchronized (mLockHelper) {
1558 if (mZoneUserBindingHelper == null) {
1559 Log.w(TAG_USER, "implementation is not delegated");
1560 return false;
1561 }
1562 helper = mZoneUserBindingHelper;
1563 }
1564 return helper.assignUserToOccupantZone(userId, zoneId);
1565 }
1566
1567 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1568 ZoneUserBindingHelper helper = null;
1569 synchronized (mLockHelper) {
1570 if (mZoneUserBindingHelper == null) {
1571 Log.w(TAG_USER, "implementation is not delegated");
1572 return false;
1573 }
1574 helper = mZoneUserBindingHelper;
1575 }
1576 return helper.unassignUserFromOccupantZone(userId);
1577 }
1578
1579 private boolean isPassengerDisplayAvailable() {
1580 ZoneUserBindingHelper helper = null;
1581 synchronized (mLockHelper) {
1582 if (mZoneUserBindingHelper == null) {
1583 Log.w(TAG_USER, "implementation is not delegated");
1584 return false;
1585 }
1586 helper = mZoneUserBindingHelper;
1587 }
1588 return helper.isPassengerDisplayAvailable();
1589 }
1590
1591 /**
1592 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1593 * zone is returned.
1594 *
1595 * @param occupantType The type of an occupant.
1596 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1597 * if not found.
1598 */
1599 private int getZoneId(@OccupantTypeEnum int occupantType) {
1600 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1601 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1602 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001603}