blob: bd45abb231aac218488fa2381a50969a8d0591dc [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;
felipealdfdf8512020-06-01 09:35:45 -070036import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070037import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070038import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070039import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070040import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070041import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070042import android.car.userlib.HalCallback;
43import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070044import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070046import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070047import android.content.pm.PackageManager;
48import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070049import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070050import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070051import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070052import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070053import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
54import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Felipe Lemee3cab982020-03-12 11:39:29 -070055import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080056import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070057import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070058import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070059import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070062import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
63import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080064import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070065import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070066import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080067import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070068import android.os.Handler;
69import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070070import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080071import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070072import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070073import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070074import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070075import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070076import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070077import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080079import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080080import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081
82import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070083import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070084import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080085import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080086import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070087import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070088import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070089import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080090import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070091import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070092import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070093import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070094import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070095
96import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080097import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070098import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070099import java.util.Iterator;
100import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000101import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700102import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700103import java.util.concurrent.CountDownLatch;
104import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700105
106/**
107 * User service for cars. Manages users at boot time. Including:
108 *
109 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700110 * <li> Creates a user used as driver.
111 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700112 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700113 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114 * <ol/>
115 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700116public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800117
felipealf7368962020-04-16 12:55:19 -0700118 private static final String TAG = TAG_USER;
119
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800120 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700121 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800122 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700123 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800124 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700125 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
felipeala68ecef2020-05-19 12:46:08 -0700126 /**
127 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
128 */
129 public static final String BUNDLE_USER_LOCALES =
130 CarUserServiceConstants.BUNDLE_USER_LOCALES;
131 /**
132 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
133 */
felipeal1a9410d2020-05-06 13:30:05 -0700134 public static final String BUNDLE_INITIAL_INFO_ACTION =
135 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800136
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700137 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700138 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700139 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700140 private final UserManager mUserManager;
141 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700142 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700143
Eric Jeongc91f9452019-08-30 15:04:21 -0700144 private final Object mLockUser = new Object();
145 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800146 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800148 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700149 // Only one passenger is supported.
150 @GuardedBy("mLockUser")
151 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700152 /**
153 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800154 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700155 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700156 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700157 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
158 /**
159 * Keep the list of background users started here. This is wholly for debugging purpose.
160 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700161 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700162 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
163
Felipe Leme58412202020-01-09 13:45:33 -0800164 private final UserHalService mHal;
165
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700166 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700167 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
168 getClass().getSimpleName());
169 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700170
Felipe Leme5528ff72020-02-10 19:05:14 -0800171 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800172 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700173 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800174 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700175 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800176
177 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800178 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700179 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800180 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700181 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800182
Mayank Garg7a114c82020-04-08 21:25:06 -0700183 /**
184 * User Id for the user switch in process, if any.
185 */
186 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700187 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700188 /**
189 * Request Id for the user switch in process, if any.
190 */
191 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700192 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700193 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
194
Eric Jeongc91f9452019-08-30 15:04:21 -0700195 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
196 new CopyOnWriteArrayList<>();
197
felipeal61ce3732020-04-03 11:01:00 -0700198 @Nullable
199 @GuardedBy("mLockUser")
200 private UserInfo mInitialUser;
201
Mayank Garg71661ea2020-04-29 01:25:03 -0700202 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700203
Mayank Garg587f1942020-05-06 01:41:34 -0700204 private IResultReceiver mUserSwitchUiReceiver;
205
Eric Jeongc91f9452019-08-30 15:04:21 -0700206 /** Interface for callbaks related to passenger activities. */
207 public interface PassengerCallback {
208 /** Called when passenger is started at a certain zone. */
209 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
210 /** Called when passenger is stopped. */
211 void onPassengerStopped(@UserIdInt int passengerId);
212 }
213
214 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
215 public interface ZoneUserBindingHelper {
216 /** Gets occupant zones corresponding to the occupant type. */
217 @NonNull
218 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
219 /** Assigns the user to the occupant zone. */
220 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
221 /** Makes the occupant zone unoccupied. */
222 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
223 /** Returns whether there is a passenger display. */
224 boolean isPassengerDisplayAvailable();
225 }
226
227 private final Object mLockHelper = new Object();
228 @GuardedBy("mLockHelper")
229 private ZoneUserBindingHelper mZoneUserBindingHelper;
230
Felipe Leme58412202020-01-09 13:45:33 -0800231 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700232 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
233 @NonNull IActivityManager am, int maxRunningUsers) {
234 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
235 new UserMetrics());
236 }
237
238 @VisibleForTesting
239 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
240 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
241 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700242 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
243 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700244 }
245 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800246 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700247 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700248 mAm = am;
249 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700250 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700251 mLastPassengerId = UserHandle.USER_NULL;
252 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700253 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700254 }
255
256 @Override
257 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700258 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
259 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700260 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700261 }
262
263 @Override
264 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700265 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
266 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700267 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700268 }
269
270 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700271 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700272 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700273 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800274 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700275 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700276 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700277 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700278 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700279 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
280 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700281 }
282 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
283 List<UserInfo> allDrivers = getAllDrivers();
284 int driversSize = allDrivers.size();
285 writer.println("NumberOfDrivers: " + driversSize);
286 for (int i = 0; i < driversSize; i++) {
287 int driverId = allDrivers.get(i).id;
288 writer.print(indent + "#" + i + ": id=" + driverId);
289 List<UserInfo> passengers = getPassengers(driverId);
290 int passengersSize = passengers.size();
291 writer.print(" NumberPassengers: " + passengersSize);
292 if (passengersSize > 0) {
293 writer.print(" [");
294 for (int j = 0; j < passengersSize; j++) {
295 writer.print(passengers.get(j).id);
296 if (j < passengersSize - 1) {
297 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700298 }
felipeal2d0483c2019-11-02 14:07:22 -0700299 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700300 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700301 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700302 writer.println();
303 }
304 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
305 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
306 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700307
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700308 writer.println("Relevant overlayable properties");
309 Resources res = mContext.getResources();
310 writer.printf("%sowner_name=%s\n", indent,
311 res.getString(com.android.internal.R.string.owner_name));
312 writer.printf("%sdefault_guest_name=%s\n", indent,
313 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700314 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700315 writer.printf("Request Id for the user switch in process=%d\n ",
316 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700317 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700318
felipealbf327652020-06-03 11:33:29 -0700319 writer.println("Relevant Global settings");
320 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
321 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
322
felipeale8c5dce2020-04-15 11:27:06 -0700323 dumpUserMetrics(writer);
324 }
325
felipealbf327652020-06-03 11:33:29 -0700326 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
327 String value = Settings.Global.getString(mContext.getContentResolver(), property);
328 writer.printf("%s%s=%s\n", indent, property, value);
329 }
330
felipeale8c5dce2020-04-15 11:27:06 -0700331 /**
332 * Dumps user metrics.
333 */
334 public void dumpUserMetrics(@NonNull PrintWriter writer) {
335 mUserMetrics.dump(writer);
336 }
337
338 /**
339 * Dumps first user unlocking time.
340 */
341 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
342 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700343 }
344
345 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
346 CountDownLatch latch = new CountDownLatch(1);
347 mHandler.post(() -> {
348 handleDumpUserLifecycleListeners(writer);
349 handleDumpAppLifecycleListeners(writer, indent);
350 latch.countDown();
351 });
352 int timeout = 5;
353 try {
354 if (!latch.await(timeout, TimeUnit.SECONDS)) {
355 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
356 timeout);
357 }
358 } catch (InterruptedException e) {
359 Thread.currentThread().interrupt();
360 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
361 }
362 }
363
364 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
365 if (mUserLifecycleListeners.isEmpty()) {
366 writer.println("No user lifecycle listeners");
367 return;
368 }
369 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
370 for (UserLifecycleListener listener : mUserLifecycleListeners) {
371 writer.printf("Listener %s\n", listener);
372 }
373 }
374
375 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
376 int numberListeners = mAppLifecycleListeners.size();
377 if (numberListeners == 0) {
378 writer.println("No lifecycle listeners");
379 return;
380 }
381 writer.printf("%d lifecycle listeners\n", numberListeners);
382 for (int i = 0; i < numberListeners; i++) {
383 int uid = mAppLifecycleListeners.keyAt(i);
384 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
385 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800386 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700387 }
388
389 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800390 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
391 *
392 * @param name The name of the driver to be created.
393 * @param admin Whether the created driver will be an admin.
394 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
395 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700396 */
397 @Override
398 @Nullable
399 public UserInfo createDriver(@NonNull String name, boolean admin) {
400 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000401 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700402 if (admin) {
403 return createNewAdminUser(name);
404 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700405 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700406 }
407
408 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800409 * Creates a passenger who is a profile of the given driver.
410 *
411 * @param name The name of the passenger to be created.
412 * @param driverId User id of the driver under whom a passenger is created.
413 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
414 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700415 */
416 @Override
417 @Nullable
418 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
419 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000420 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700421 UserInfo driver = mUserManager.getUserInfo(driverId);
422 if (driver == null) {
423 Log.w(TAG_USER, "the driver is invalid");
424 return null;
425 }
426 if (driver.isGuest()) {
427 Log.w(TAG_USER, "a guest driver cannot create a passenger");
428 return null;
429 }
Bookatz42fb1a62019-10-30 11:45:01 -0700430 UserInfo user = mUserManager.createProfileForUser(name,
431 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700432 if (user == null) {
433 // Couldn't create user, most likely because there are too many.
434 Log.w(TAG_USER, "can't create a profile for user" + driverId);
435 return null;
436 }
437 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700438 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700439 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700440 return user;
441 }
442
443 /**
444 * @see CarUserManager.switchDriver
445 */
446 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700447 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700448 checkManageUsersPermission("switchDriver");
Eric Jeong25666cf2020-05-14 15:16:27 -0700449 if (UserHelper.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700450 // System user doesn't associate with real person, can not be switched to.
451 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700452 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700453 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700454 }
455 int userSwitchable = mUserManager.getUserSwitchability();
456 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
457 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700458 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700459 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700460 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700461 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700462 }
463
464 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800465 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
466 *
467 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700468 */
469 @Override
470 @NonNull
471 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700472 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700473 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700474 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700475 }
476
477 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800478 * Returns all passengers under the given driver.
479 *
480 * @param driverId User id of a driver.
481 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700482 */
483 @Override
484 @NonNull
485 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700486 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700487 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700488 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
489 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700490 });
491 }
492
493 /**
494 * @see CarUserManager.startPassenger
495 */
496 @Override
497 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
498 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700499 synchronized (mLockUser) {
500 try {
501 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
502 Log.w(TAG_USER, "could not start passenger");
503 return false;
504 }
505 } catch (RemoteException e) {
506 // ignore
507 Log.w(TAG_USER, "error while starting passenger", e);
508 return false;
509 }
510 if (!assignUserToOccupantZone(passengerId, zoneId)) {
511 Log.w(TAG_USER, "could not assign passenger to zone");
512 return false;
513 }
514 mLastPassengerId = passengerId;
515 }
516 for (PassengerCallback callback : mPassengerCallbacks) {
517 callback.onPassengerStarted(passengerId, zoneId);
518 }
519 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700520 }
521
522 /**
523 * @see CarUserManager.stopPassenger
524 */
525 @Override
526 public boolean stopPassenger(@UserIdInt int passengerId) {
527 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700528 return stopPassengerInternal(passengerId, true);
529 }
530
531 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
532 synchronized (mLockUser) {
533 UserInfo passenger = mUserManager.getUserInfo(passengerId);
534 if (passenger == null) {
535 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
536 return false;
537 }
538 if (mLastPassengerId != passengerId) {
539 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
540 return true;
541 }
542 if (checkCurrentDriver) {
543 int currentUser = ActivityManager.getCurrentUser();
544 if (passenger.profileGroupId != currentUser) {
545 Log.w(TAG_USER, "passenger " + passengerId
546 + " is not a profile of the current user");
547 return false;
548 }
549 }
550 // Passenger is a profile, so cannot be stopped through activity manager.
551 // Instead, activities started by the passenger are stopped and the passenger is
552 // unassigned from the zone.
553 stopAllTasks(passengerId);
554 if (!unassignUserFromOccupantZone(passengerId)) {
555 Log.w(TAG_USER, "could not unassign user from occupant zone");
556 return false;
557 }
558 mLastPassengerId = UserHandle.USER_NULL;
559 }
560 for (PassengerCallback callback : mPassengerCallbacks) {
561 callback.onPassengerStopped(passengerId);
562 }
563 return true;
564 }
565
566 private void stopAllTasks(@UserIdInt int userId) {
567 try {
568 for (StackInfo info : mAm.getAllStackInfos()) {
569 for (int i = 0; i < info.taskIds.length; i++) {
570 if (info.taskUserIds[i] == userId) {
571 int taskId = info.taskIds[i];
572 if (!mAm.removeTask(taskId)) {
573 Log.w(TAG_USER, "could not remove task " + taskId);
574 }
575 }
576 }
577 }
578 } catch (RemoteException e) {
579 Log.e(TAG_USER, "could not get stack info", e);
580 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700581 }
582
Felipe Leme5528ff72020-02-10 19:05:14 -0800583 @Override
584 public void setLifecycleListenerForUid(IResultReceiver listener) {
585 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700586 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800587 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
588
589 try {
590 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
591 } catch (RemoteException e) {
592 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
593 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700594 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800595 }
596
597 private void onListenerDeath(int uid) {
598 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700599 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800600 }
601
602 @Override
603 public void resetLifecycleListenerForUid() {
604 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700605 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800606 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700607 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800608 }
609
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800610 @Override
611 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800612 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700613 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
614 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800615 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700616 checkManageUsersPermission("getInitialInfo");
felipealdfdf8512020-06-01 09:35:45 -0700617 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800618 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700619 Bundle resultData = null;
620 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700621 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
622 status, resp.action, resp.userToSwitchOrCreate.userId,
felipeala68ecef2020-05-19 12:46:08 -0700623 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
Mayank Garg0e239142020-04-14 19:16:31 -0700624 switch (resp.action) {
625 case InitialUserInfoResponseAction.SWITCH:
626 resultData = new Bundle();
627 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
628 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
629 break;
630 case InitialUserInfoResponseAction.CREATE:
631 resultData = new Bundle();
632 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
633 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
634 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
635 break;
636 case InitialUserInfoResponseAction.DEFAULT:
637 resultData = new Bundle();
638 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
639 break;
640 default:
641 // That's ok, it will be the same as DEFAULT...
642 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800643 }
felipeal312416a2020-04-14 12:28:24 -0700644 } else {
645 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800646 }
felipeala68ecef2020-05-19 12:46:08 -0700647 if (resultData != null && !TextUtils.isEmpty(resp.userLocales)) {
648 resultData.putString(BUNDLE_USER_LOCALES, resp.userLocales);
649 }
650
Mayank Garg0e239142020-04-14 19:16:31 -0700651 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800652 });
653 }
654
Felipe Lemee3cab982020-03-12 11:39:29 -0700655 /**
felipeal61ce3732020-04-03 11:01:00 -0700656 * Gets the initial foreground user after the device boots or resumes from suspension.
657 *
658 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
659 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
660 * method returns {@code null}.
661 *
662 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
663 * (like switching to the last active user), and this method will return the result of such
664 * operation.
665 *
666 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
667 * {@code null}.
668 *
669 * @hide
670 */
671 @Nullable
672 public UserInfo getInitialUser() {
673 checkInteractAcrossUsersPermission("getInitialUser");
674 synchronized (mLockUser) {
675 return mInitialUser;
676 }
677 }
678
679 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
680 // some reason passing the whole UserInfo through a raw binder transaction is not working.
681 /**
682 * Sets the initial foreground user after the device boots or resumes from suspension.
683 */
684 public void setInitialUser(@UserIdInt int userId) {
685 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
686 : mUserManager.getUserInfo(userId);
687 setInitialUser(initialUser);
688 }
689
690 /**
691 * Sets the initial foreground user after the device boots or resumes from suspension.
692 */
693 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700694 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
695 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700696 synchronized (mLockUser) {
697 mInitialUser = user;
698 }
699 if (user == null) {
700 // This mean InitialUserSetter failed and could not fallback, so the initial user was
701 // not switched (and most likely is SYSTEM_USER).
702 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
703 Log.wtf(TAG_USER, "Initial user set to null");
704 }
705 }
706
707 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700708 * Calls the User HAL to get the initial user info.
709 *
710 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
711 * @param callback callback to receive the results.
712 */
713 public void getInitialUserInfo(int requestType,
714 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700715 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
716 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700717 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700718 checkManageUsersPermission("getInitialUserInfo");
felipealdfdf8512020-06-01 09:35:45 -0700719 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemee3cab982020-03-12 11:39:29 -0700720 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
721 }
722
723 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700724 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
725 *
726 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700727 * When everything works well, the workflow is:
728 * <ol>
729 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
730 * type, current user id, target user id, and a callback.
731 * <li> HAL called back with SUCCESS.
732 * <li> {@link IActivityManager} is called for Android user switch.
733 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
734 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
735 * request type, current user id, and target user id. In this case, the current and target
736 * user IDs would be same.
737 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700738 *
739 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700740 * Corner cases:
741 * <ul>
742 * <li> If target user is already the current user, no user switch is performed and receiver
743 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
744 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
745 * {@code STATUS_HAL_INTERNAL_FAILURE}.
746 * <li> If HAL user switch call is successful, but android user switch call fails,
747 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
748 * target user id, but in this case the current and target user IDs would be different.
749 * <li> If another user switch request for the same target user is received while previous
750 * request is in process, receiver would receive
751 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
752 * <li> If a user switch request is received while another user switch request for different
753 * target user is in process, the previous request would be abandoned and new request will be
754 * processed. No POST_SWITCH would be sent for the previous request.
755 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700756 *
Mayank Garge19c2922020-03-30 18:05:53 -0700757 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700758 * @param timeoutMs - timeout for HAL to wait
759 * @param receiver - receiver for the results
760 */
Mayank Garge19c2922020-03-30 18:05:53 -0700761 @Override
762 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700763 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700764 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700765 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700766 Objects.requireNonNull(receiver);
767 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700768 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700769
felipealf7368962020-04-16 12:55:19 -0700770 int currentUser = ActivityManager.getCurrentUser();
771 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700772 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
773 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
774 }
felipeale5bf0322020-04-16 15:10:57 -0700775 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
felipealdfdf8512020-06-01 09:35:45 -0700776 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700777 return;
778 }
779
Mayank Garg7a114c82020-04-08 21:25:06 -0700780 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700781 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
782 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
783 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
784 }
785
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700786 // If there is another request for the same target user, return another request in
787 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
788 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
789 // user switch request in process for different target user, but that request is now
790 // ignored.
felipealf7368962020-04-16 12:55:19 -0700791 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700792 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
793 Log.d(TAG_USER,
794 "Another user switch request in process for the requested target user: "
795 + targetUserId);
796 }
797
798 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700799 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700800 return;
801 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700802 else {
803 mUserIdForUserSwitchInProcess = targetUserId;
804 mRequestIdForUserSwitchInProcess = 0;
805 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700806 }
807
felipealdfdf8512020-06-01 09:35:45 -0700808 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700809 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
810
811 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700812 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
813 Log.d(TAG, "switch response: status="
814 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
815 }
816
felipeale5bf0322020-04-16 15:10:57 -0700817 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700818
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700819 synchronized (mLockUser) {
820 if (status != HalCallback.STATUS_OK) {
821 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
822 Log.w(TAG, "invalid callback status ("
823 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
824 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700825 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700826 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
827 return;
828 }
felipealf7368962020-04-16 12:55:19 -0700829
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700830 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
831 resp.errorMessage);
832
833 if (mUserIdForUserSwitchInProcess != targetUserId) {
834 // Another user switch request received while HAL responded. No need to process
835 // this request further
836 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
837 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
838 + "abondoned for : " + targetUserId + ". Current user in process: "
839 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700840 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700841 resultStatus =
842 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700843 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700844 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
845 return;
846 }
847
848 switch (resp.status) {
849 case SwitchUserStatus.SUCCESS:
850 boolean switched;
851 try {
852 switched = mAm.switchUser(targetUserId);
853 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700854 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700855 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
856 mRequestIdForUserSwitchInProcess = resp.requestId;
857 } else {
858 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
859 postSwitchHalResponse(resp.requestId, targetUserId);
860 }
861 } catch (RemoteException e) {
862 // ignore
863 Log.w(TAG_USER,
864 "error while switching user " + targetUser.toFullString(), e);
865 }
866 break;
867 case SwitchUserStatus.FAILURE:
868 // HAL failed to switch user
869 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
870 break;
felipealdfdf8512020-06-01 09:35:45 -0700871 default:
872 // Shouldn't happen because UserHalService validates the status
873 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700874 }
875
876 if (mRequestIdForUserSwitchInProcess == 0) {
877 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
878 }
Mayank Garg59f22192020-03-27 00:51:45 -0700879 }
felipealdfdf8512020-06-01 09:35:45 -0700880 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700881 });
882 }
883
Mayank Garga55c3092020-05-28 03:19:24 -0700884 @Override
885 public UserRemovalResult removeUser(@UserIdInt int userId) {
886 checkManageUsersPermission("removeUser");
887 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
888 // If the requested user is the current user, return error.
889 if (ActivityManager.getCurrentUser() == userId) {
890 return logAndGetResults(userId,
891 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
892 }
893
894 // If requested user is the only admin user, return error.
895 UserInfo userInfo = mUserManager.getUserInfo(userId);
896 if (userInfo == null) {
897 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
898 }
899
900 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
901 new android.hardware.automotive.vehicle.V2_0.UserInfo();
902 halUser.userId = userInfo.id;
903 halUser.flags = UserHalHelper.convertFlags(userInfo);
904 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
905
906 // Do not delete last admin user.
907 if (UserHalHelper.isAdmin(halUser.flags)) {
908 int size = usersInfo.existingUsers.size();
909 int totalAdminUsers = 0;
910 for (int i = 0; i < size; i++) {
911 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
912 totalAdminUsers++;
913 }
914 }
915 if (totalAdminUsers == 1) {
916 return logAndGetResults(userId,
917 UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
918 }
919 }
920
921 // First remove user from android and then remove from HAL because HAL remove user is one
922 // way call.
923 if (!mUserManager.removeUser(userId)) {
924 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
925 }
926
927 RemoveUserRequest request = new RemoveUserRequest();
928 request.removedUserInfo = halUser;
929 request.usersInfo = usersInfo;
930 mHal.removeUser(request);
931 return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
932 }
933
934 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
935 @UserRemovalResult.Status int result) {
936 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
937 return new UserRemovalResult(result);
938 }
939
Mayank Garg587f1942020-05-06 01:41:34 -0700940 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
941 if (mUserSwitchUiReceiver == null) {
942 Log.w(TAG_USER, "No User switch UI receiver.");
943 return;
944 }
945
felipealdfdf8512020-06-01 09:35:45 -0700946 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -0700947 try {
Mayank Garg587f1942020-05-06 01:41:34 -0700948 mUserSwitchUiReceiver.send(targetUserId, null);
949 } catch (RemoteException e) {
950 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
951 }
952 }
953
felipeal5e3ede42020-04-23 18:04:07 -0700954 @Override
felipealdfdf8512020-06-01 09:35:45 -0700955 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
956 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
957 Objects.requireNonNull(userType, "user type cannot be null");
958 Objects.requireNonNull(receiver, "receiver cannot be null");
959 checkManageOrCreateUsersPermission("createUser");
960 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
961 userType, flags, timeoutMs);
962
963 UserInfo newUser;
964 try {
965 newUser = mUserManager.createUser(name, userType, flags);
966 if (newUser == null) {
967 Log.w(TAG, "um.createUser() returned null for user of type " + userType
968 + " and flags " + UserInfo.flagsToString(flags));
969 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
970 return;
971 }
972 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
973 Log.d(TAG, "Created user: " + newUser.toFullString());
974 }
975 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
976 UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
977 } catch (RuntimeException e) {
978 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
979 + UserInfo.flagsToString(flags), e);
980 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
981 return;
982 }
983
984 CreateUserRequest request = new CreateUserRequest();
985 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
986 if (!TextUtils.isEmpty(name)) {
987 request.newUserName = name;
988 }
989 request.newUserInfo.userId = newUser.id;
990 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
991 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
992 Log.d(TAG, "Create user request: " + request);
993 }
994
995 try {
996 mHal.createUser(request, timeoutMs, (status, resp) -> {
997 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
998 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
999 Log.d(TAG, "createUserResponse: status="
1000 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1001 }
1002 UserInfo user = null; // user returned in the result
1003 if (status != HalCallback.STATUS_OK) {
1004 Log.w(TAG, "invalid callback status ("
1005 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1006 + resp);
1007 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1008 resultStatus, resp.errorMessage);
1009 removeUser(newUser, "HAL call failed with "
1010 + UserHalHelper.halCallbackStatusToString(status));
1011 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1012 return;
1013 }
1014
1015 switch (resp.status) {
1016 case CreateUserStatus.SUCCESS:
1017 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1018 user = newUser;
1019 break;
1020 case CreateUserStatus.FAILURE:
1021 // HAL failed to switch user
1022 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1023 break;
1024 default:
1025 // Shouldn't happen because UserHalService validates the status
1026 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1027 }
1028 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1029 resultStatus, resp.errorMessage);
1030 if (user == null) {
1031 removeUser(newUser, "HAL returned "
1032 + UserCreationResult.statusToString(resultStatus));
1033 }
1034 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1035 });
1036 } catch (Exception e) {
1037 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1038 removeUser(newUser, "mHal.createUser() failed");
1039 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1040 }
1041 }
1042
1043 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1044 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1045 try {
1046 if (!mUserManager.removeUser(user.id)) {
1047 Log.w(TAG, "Failed to remove user " + user.toFullString());
1048 }
1049 } catch (Exception e) {
1050 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1051 }
1052 }
1053
1054 @Override
felipeal159a2a42020-05-08 10:32:11 -07001055 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
felipeal5e3ede42020-04-23 18:04:07 -07001056 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1057 checkManageUsersPermission("getUserIdentificationAssociation");
1058
1059 int uid = getCallingUid();
1060 int userId = UserHandle.getUserId(uid);
1061 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1062
1063 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1064 request.userInfo.userId = userId;
1065 request.userInfo.flags = getHalUserInfoFlags(userId);
1066
1067 request.numberAssociationTypes = types.length;
1068 for (int i = 0; i < types.length; i++) {
1069 request.associationTypes.add(types[i]);
1070 }
1071
1072 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1073 if (halResponse == null) {
1074 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1075 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001076 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001077 }
1078
1079 int[] values = new int[halResponse.associations.size()];
1080 for (int i = 0; i < values.length; i++) {
1081 values[i] = halResponse.associations.get(i).value;
1082 }
1083 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1084
felipeal159a2a42020-05-08 10:32:11 -07001085 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1086 }
1087
1088 @Override
1089 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1090 AndroidFuture<UserIdentificationAssociationResponse> result) {
1091 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1092 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1093 if (types.length != values.length) {
1094 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1095 + Arrays.toString(values) + ") should have the same length");
1096 }
1097 checkManageUsersPermission("setUserIdentificationAssociation");
1098
1099 int uid = getCallingUid();
1100 int userId = UserHandle.getUserId(uid);
1101 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1102
1103 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1104 request.userInfo.userId = userId;
1105 request.userInfo.flags = getHalUserInfoFlags(userId);
1106
1107 request.numberAssociations = types.length;
1108 for (int i = 0; i < types.length; i++) {
1109 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1110 association.type = types[i];
1111 association.value = values[i];
1112 request.associations.add(association);
1113 }
1114
1115 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1116 if (status != HalCallback.STATUS_OK) {
1117 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1118 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1119 + resp);
1120 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1121 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1122 result.complete(UserIdentificationAssociationResponse.forFailure());
1123 return;
1124 }
1125 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1126 resp.errorMessage);
1127 result.complete(
1128 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1129 return;
1130 }
1131 int respSize = resp.associations.size();
1132 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1133 resp.errorMessage);
1134
1135 int[] responseTypes = new int[respSize];
1136 for (int i = 0; i < respSize; i++) {
1137 responseTypes[i] = resp.associations.get(i).value;
1138 }
1139 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1140 .forSuccess(responseTypes, resp.errorMessage);
1141 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1142 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1143 + ", converted=" + response);
1144 }
1145 result.complete(response);
1146 });
felipeal5e3ede42020-04-23 18:04:07 -07001147 }
1148
1149 /**
1150 * Gets the User HAL flags for the given user.
1151 *
1152 * @throws IllegalArgumentException if the user does not exist.
1153 */
1154 private int getHalUserInfoFlags(@UserIdInt int userId) {
1155 UserInfo user = mUserManager.getUserInfo(userId);
1156 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1157 return UserHalHelper.convertFlags(user);
1158 }
1159
Mayank Garg0e239142020-04-14 19:16:31 -07001160 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1161 @Nullable Bundle resultData) {
1162 try {
1163 receiver.send(resultCode, resultData);
1164 } catch (RemoteException e) {
1165 // ignore
1166 Log.w(TAG_USER, "error while sending results", e);
1167 }
1168 }
1169
felipealdfdf8512020-06-01 09:35:45 -07001170 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001171 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001172 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001173 }
1174
felipealdfdf8512020-06-01 09:35:45 -07001175 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001176 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1177 receiver.complete(new UserSwitchResult(status, errorMessage));
1178 }
1179
felipealdfdf8512020-06-01 09:35:45 -07001180 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1181 @UserCreationResult.Status int status) {
1182 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1183 }
1184
1185 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1186 @UserCreationResult.Status int status, @NonNull UserInfo user,
1187 @Nullable String errorMessage) {
1188 if (TextUtils.isEmpty(errorMessage)) {
1189 errorMessage = null;
1190 }
1191 receiver.complete(new UserCreationResult(status, user, errorMessage));
1192 }
1193
Mayank Garg6307fe42020-04-15 23:09:03 -07001194 /**
1195 * Calls activity manager for user switch.
1196 *
1197 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1198 *
1199 * @param requestId for the user switch request
1200 * @param targetUserId of the target user
1201 *
1202 * @hide
1203 */
1204 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1205 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1206 targetUserId);
1207 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1208
1209 try {
1210 boolean result = mAm.switchUser(targetUserId);
1211 if (result) {
1212 updateUserSwitchInProcess(requestId, targetUserId);
1213 } else {
1214 postSwitchHalResponse(requestId, targetUserId);
1215 }
1216 } catch (RemoteException e) {
1217 // ignore
1218 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1219 }
1220 }
1221
1222 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1223 synchronized (mLockUser) {
1224 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1225 // Some other user switch is in process.
1226 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1227 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1228 + " is in process. Abandoning it as a new user switch is requested"
1229 + " for the target user: " + targetUserId);
1230 }
1231 }
1232 mUserIdForUserSwitchInProcess = targetUserId;
1233 mRequestIdForUserSwitchInProcess = requestId;
1234 }
1235 }
Mayank Garg7a114c82020-04-08 21:25:06 -07001236 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
felipealdfdf8512020-06-01 09:35:45 -07001237 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001238 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1239 targetUserId, usersInfo.currentUser.userId);
1240 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1241 request.requestId = requestId;
1242 mHal.postSwitchResponse(request);
1243 }
1244
1245 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1246 @NonNull UsersInfo usersInfo) {
1247 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001248 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1249 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1250 halTargetUser.userId = targetUser.id;
1251 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001252 SwitchUserRequest request = new SwitchUserRequest();
1253 request.targetUser = halTargetUser;
1254 request.usersInfo = usersInfo;
1255 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001256 }
1257
Mayank Garg59f22192020-03-27 00:51:45 -07001258 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001259 * Checks if the User HAL is supported.
1260 */
1261 public boolean isUserHalSupported() {
1262 return mHal.isSupported();
1263 }
1264
Mayank Garg587f1942020-05-06 01:41:34 -07001265 /**
1266 * Sets a callback which is invoked before user switch.
1267 *
1268 * <p>
1269 * This method should only be called by the Car System UI. The purpose of this call is to notify
1270 * Car System UI to show the user switch UI before the user switch.
1271 */
1272 @Override
1273 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001274 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001275
1276 // Confirm that caller is system UI.
1277 String systemUiPackageName = getSystemUiPackageName();
1278 if (systemUiPackageName == null) {
1279 throw new IllegalStateException("System UI package not found.");
1280 }
1281
1282 try {
1283 int systemUiUid = mContext
1284 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1285 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1286 int callerUid = Binder.getCallingUid();
1287 if (systemUiUid != callerUid) {
1288 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1289 + " is allowed to make this call");
1290 }
1291 } catch (NameNotFoundException e) {
1292 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1293 }
1294
Mayank Garg587f1942020-05-06 01:41:34 -07001295 mUserSwitchUiReceiver = receiver;
1296 }
1297
Mayank Garga480dd92020-05-14 03:14:57 -07001298 // TODO(157082995): This information can be taken from
1299 // PackageManageInternalImpl.getSystemUiServiceComponent
1300 @Nullable
1301 private String getSystemUiPackageName() {
1302 try {
1303 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1304 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1305 return componentName.getPackageName();
1306 } catch (RuntimeException e) {
1307 Log.w(TAG_USER, "error while getting system UI package name.", e);
1308 return null;
1309 }
1310 }
1311
Keun young Park13a7a822019-04-04 15:53:08 -07001312 private void updateDefaultUserRestriction() {
1313 // We want to set restrictions on system and guest users only once. These are persisted
1314 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1315 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001316 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1317 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001318 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001319 // Only apply the system user restrictions if the system user is headless.
1320 if (UserManager.isHeadlessSystemUserMode()) {
1321 setSystemUserRestrictions();
1322 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001323 Settings.Global.putInt(mContext.getContentResolver(),
1324 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001325 }
1326
Eric Jeong1545f3b2019-09-16 13:56:52 -07001327 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001328 return !mUserManager.getUserInfo(userId).isEphemeral();
1329 }
1330
Antonio Kantekc8114752020-03-05 21:37:39 -08001331 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001332 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1333 */
1334 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1335 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001336 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001337 }
1338
1339 /**
1340 * Removes previously added {@link UserLifecycleListener}.
1341 */
1342 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1343 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001344 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001345 }
1346
Eric Jeongc91f9452019-08-30 15:04:21 -07001347 /** Adds callback to listen to passenger activity events. */
1348 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001349 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001350 mPassengerCallbacks.add(callback);
1351 }
1352
1353 /** Removes previously added callback to listen passenger events. */
1354 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001355 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001356 mPassengerCallbacks.remove(callback);
1357 }
1358
1359 /** Sets the implementation of ZoneUserBindingHelper. */
1360 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1361 synchronized (mLockHelper) {
1362 mZoneUserBindingHelper = helper;
1363 }
1364 }
1365
felipeal98900c82020-04-09 09:05:02 -07001366 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001367 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001368 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001369 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001370 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001371 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1372 updateDefaultUserRestriction();
1373 tasks = new ArrayList<>(mUser0UnlockTasks);
1374 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001375 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001376 }
1377 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001378 Integer user = userId;
1379 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001380 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001381 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001382 mBackgroundUsersToRestart.remove(user);
1383 mBackgroundUsersToRestart.add(0, user);
1384 }
1385 // -1 for user 0
1386 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001387 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001388 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001389 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001390 + ", dropping least recently user from restart list:" + userToDrop);
1391 // Drop the least recently used user.
1392 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1393 }
1394 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001395 }
1396 }
1397 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001398 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001399 for (Runnable r : tasks) {
1400 r.run();
1401 }
1402 }
1403 }
1404
1405 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001406 * Starts all background users that were active in system.
1407 *
Keun young Parkfb656372019-03-12 18:37:55 -07001408 * @return list of background users started successfully.
1409 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001410 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001411 public ArrayList<Integer> startAllBackgroundUsers() {
1412 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001413 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001414 users = new ArrayList<>(mBackgroundUsersToRestart);
1415 mBackgroundUsersRestartedHere.clear();
1416 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001417 }
1418 ArrayList<Integer> startedUsers = new ArrayList<>();
1419 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001420 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001421 continue;
1422 }
1423 try {
1424 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001425 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1426 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001427 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001428 } else if (mAm.unlockUser(user, null, null, null)) {
1429 startedUsers.add(user);
1430 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001431 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001432 if (mUserManager.isUserRunning(user)) {
1433 // add to started list so that it can be stopped later.
1434 startedUsers.add(user);
1435 }
Keun young Parkfb656372019-03-12 18:37:55 -07001436 }
1437 }
1438 } catch (RemoteException e) {
1439 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001440 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001441 }
1442 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001443 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001444 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001445 ArrayList<Integer> usersToRemove = new ArrayList<>();
1446 for (Integer user : mBackgroundUsersToRestart) {
1447 if (!startedUsers.contains(user)) {
1448 usersToRemove.add(user);
1449 }
1450 }
1451 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1452 }
Keun young Parkfb656372019-03-12 18:37:55 -07001453 return startedUsers;
1454 }
1455
1456 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001457 * Stops all background users that were active in system.
1458 *
1459 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001460 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001461 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001462 if (userId == UserHandle.USER_SYSTEM) {
1463 return false;
1464 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001465 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001466 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001467 return false;
1468 }
1469 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001470 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001471 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001472 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001473 Integer user = userId;
1474 mBackgroundUsersRestartedHere.remove(user);
1475 }
1476 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1477 return false;
1478 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001479 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001480 return false;
1481 }
1482 } catch (RemoteException e) {
1483 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001484 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001485 }
1486 return true;
1487 }
1488
1489 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001490 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001491 */
felipeale8c5dce2020-04-15 11:27:06 -07001492 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1493 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1494 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001495
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001496 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001497 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001498 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001499 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1500 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001501 }
1502
felipeale8c5dce2020-04-15 11:27:06 -07001503 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001504 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001505
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001506 mHandler.post(() -> {
1507 handleNotifyServiceUserLifecycleListeners(event);
1508 handleNotifyAppUserLifecycleListeners(event);
1509 });
felipeale8c5dce2020-04-15 11:27:06 -07001510
Keun young Park1fced442020-05-29 09:26:29 -07001511 if (timestampMs != 0) {
1512 // Finally, update metrics.
1513 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1514 }
felipeale8c5dce2020-04-15 11:27:06 -07001515 }
1516
1517 /**
1518 * Sets the first user unlocking metrics.
1519 */
1520 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1521 int halResponseTime) {
1522 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001523 }
1524
Mayank Garg7a114c82020-04-08 21:25:06 -07001525 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001526 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001527 || mUserIdForUserSwitchInProcess != userId
1528 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001529 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1530 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1531 }
1532 return;
1533 }
felipealf7368962020-04-16 12:55:19 -07001534 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1535 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001536 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001537 }
1538
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001539 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1540 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001541 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001542 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1543 Log.d(TAG_USER, "No app listener to be notified of " + event);
1544 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001545 return;
1546 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001547 // Must use a different TimingsTraceLog because it's another thread
1548 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1549 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1550 }
felipeal2a84d512020-04-06 18:52:15 -07001551 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001552 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1553 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1554 for (int i = 0; i < listenersSize; i++) {
1555 int uid = mAppLifecycleListeners.keyAt(i);
1556 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1557 Bundle data = new Bundle();
1558 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001559
1560 int fromUid = event.getPreviousUserId();
1561 if (fromUid != UserHandle.USER_NULL) {
1562 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1563 }
1564
felipeal2a84d512020-04-06 18:52:15 -07001565 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001566 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001567 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001568 try {
felipeal2a84d512020-04-06 18:52:15 -07001569 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001570 listener.send(userId, data);
1571 } catch (RemoteException e) {
1572 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1573 } finally {
1574 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001575 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001576 }
1577 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001578 }
1579
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001580 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001581 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1582 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001583 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001584 return;
felipeal2a84d512020-04-06 18:52:15 -07001585 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1586 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1587 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001588 }
felipeal2a84d512020-04-06 18:52:15 -07001589
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001590 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1591 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001592 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001593 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001594 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001595 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001596 listener.onEvent(event);
1597 } catch (RuntimeException e) {
1598 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001599 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001600 } finally {
1601 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001602 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001603 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001604 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001605 }
1606
Mayank Garge5de0f92020-04-23 21:38:38 -07001607 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001608 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001609 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001610 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001611
Mayank Garge5de0f92020-04-23 21:38:38 -07001612 // Switch HAL users if user switch is not requested by CarUserService
1613 notifyHalLegacySwitch(fromUserId, toUserId);
1614
felipealbf327652020-06-03 11:33:29 -07001615 mCarUserManagerHelper.setLastActiveUser(toUserId);
1616
Eric Jeongc91f9452019-08-30 15:04:21 -07001617 if (mLastPassengerId != UserHandle.USER_NULL) {
1618 stopPassengerInternal(mLastPassengerId, false);
1619 }
1620 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1621 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001622 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001623 }
felipeal98900c82020-04-09 09:05:02 -07001624 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001625 }
1626
Mayank Garge5de0f92020-04-23 21:38:38 -07001627 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1628 synchronized (mLockUser) {
1629 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1630 }
1631
1632 // switch HAL user
felipealdfdf8512020-06-01 09:35:45 -07001633 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001634 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1635 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001636 }
1637
Pavel Maltsev17e81832019-04-04 14:38:41 -07001638 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001639 * 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 -08001640 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001641 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001642 * @param r Runnable to run.
1643 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001644 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001645 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001646 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001647 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001648 if (mUser0Unlocked) {
1649 runNow = true;
1650 } else {
1651 mUser0UnlockTasks.add(r);
1652 }
1653 }
1654 if (runNow) {
1655 r.run();
1656 }
1657 }
1658
Keun young Parkf3523cd2019-04-08 10:09:17 -07001659 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001660 @NonNull
1661 ArrayList<Integer> getBackgroundUsersToRestart() {
1662 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001663 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001664 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1665 }
1666 return backgroundUsersToRestart;
1667 }
1668
Ying Zheng1ab32b62018-06-26 12:47:26 -07001669 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001670 // Disable Location service for system user.
1671 LocationManager locationManager =
1672 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001673 locationManager.setLocationEnabledForUser(
1674 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001675 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001676
1677 /**
1678 * Creates a new user on the system, the created user would be granted admin role.
1679 *
1680 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001681 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001682 */
1683 @Nullable
1684 private UserInfo createNewAdminUser(String name) {
1685 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1686 // Only admins or system user can create other privileged users.
1687 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1688 return null;
1689 }
1690
1691 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1692 if (user == null) {
1693 // Couldn't create user, most likely because there are too many.
1694 Log.w(TAG_USER, "can't create admin user.");
1695 return null;
1696 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001697 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001698
1699 return user;
1700 }
1701
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001702 /**
1703 * Assigns a default icon to a user according to the user's id.
1704 *
1705 * @param userInfo User whose avatar is set to default icon.
1706 * @return Bitmap of the user icon.
1707 */
1708 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1709 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1710 Bitmap bitmap = UserIcons.convertToBitmap(
1711 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1712 mUserManager.setUserIcon(userInfo.id, bitmap);
1713 return bitmap;
1714 }
1715
Eric Jeong1545f3b2019-09-16 13:56:52 -07001716 private interface UserFilter {
1717 boolean isEligibleUser(UserInfo user);
1718 }
1719
1720 /** Returns all users who are matched by the given filter. */
1721 private List<UserInfo> getUsers(UserFilter filter) {
1722 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1723
1724 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1725 UserInfo user = iterator.next();
1726 if (!filter.isEligibleUser(user)) {
1727 iterator.remove();
1728 }
1729 }
1730 return users;
1731 }
1732
1733 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001734 * Enforces that apps which have the
1735 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1736 * can make certain calls to the CarUserManager.
1737 *
1738 * @param message used as message if SecurityException is thrown.
1739 * @throws SecurityException if the caller is not system or root.
1740 */
1741 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001742 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1743 }
1744
felipealdfdf8512020-06-01 09:35:45 -07001745 private static void checkManageOrCreateUsersPermission(String message) {
1746 checkAtLeastOnePermission(message,
1747 android.Manifest.permission.MANAGE_USERS,
1748 android.Manifest.permission.CREATE_USERS);
1749 }
1750
felipeal2d0483c2019-11-02 14:07:22 -07001751 private static void checkManageUsersOrDumpPermission(String message) {
1752 checkAtLeastOnePermission(message,
1753 android.Manifest.permission.MANAGE_USERS,
1754 android.Manifest.permission.DUMP);
1755 }
1756
Felipe Leme5528ff72020-02-10 19:05:14 -08001757 private void checkInteractAcrossUsersPermission(String message) {
1758 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1759 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1760 }
1761
felipeal2d0483c2019-11-02 14:07:22 -07001762 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001763 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001764 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1765 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001766 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001767 }
1768 }
1769
felipeal2d0483c2019-11-02 14:07:22 -07001770 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1771 for (String permission : permissions) {
1772 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1773 /* exported = */ true)
1774 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1775 return true;
1776 }
1777 }
1778 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001779 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001780
1781 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1782 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1783 // Count all users that are managed profiles of the given user.
1784 int managedProfilesCount = 0;
1785 for (UserInfo user : users) {
1786 if (user.isManagedProfile() && user.profileGroupId == userId) {
1787 managedProfilesCount++;
1788 }
1789 }
1790 return managedProfilesCount;
1791 }
1792
1793 /**
1794 * Starts the first passenger of the given driver and assigns the passenger to the front
1795 * passenger zone.
1796 *
1797 * @param driverId User id of the driver.
1798 * @return whether it succeeds.
1799 */
1800 private boolean startFirstPassenger(@UserIdInt int driverId) {
1801 int zoneId = getAvailablePassengerZone();
1802 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1803 Log.w(TAG_USER, "passenger occupant zone is not found");
1804 return false;
1805 }
1806 List<UserInfo> passengers = getPassengers(driverId);
1807 if (passengers.size() < 1) {
1808 Log.w(TAG_USER, "passenger is not found");
1809 return false;
1810 }
1811 // Only one passenger is supported. If there are two or more passengers, the first passenger
1812 // is chosen.
1813 int passengerId = passengers.get(0).id;
1814 if (!startPassenger(passengerId, zoneId)) {
1815 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1816 return false;
1817 }
1818 return true;
1819 }
1820
1821 private int getAvailablePassengerZone() {
1822 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1823 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1824 for (int occupantType : occupantTypes) {
1825 int zoneId = getZoneId(occupantType);
1826 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1827 return zoneId;
1828 }
1829 }
1830 return OccupantZoneInfo.INVALID_ZONE_ID;
1831 }
1832
1833 /**
1834 * Creates a new passenger user when there is no passenger user.
1835 */
1836 private void setupPassengerUser() {
1837 int currentUser = ActivityManager.getCurrentUser();
1838 int profileCount = getNumberOfManagedProfiles(currentUser);
1839 if (profileCount > 0) {
1840 Log.w(TAG_USER, "max profile of user" + currentUser
1841 + " is exceeded: current profile count is " + profileCount);
1842 return;
1843 }
1844 // TODO(b/140311342): Use resource string for the default passenger name.
1845 UserInfo passenger = createPassenger("Passenger", currentUser);
1846 if (passenger == null) {
1847 // Couldn't create user, most likely because there are too many.
1848 Log.w(TAG_USER, "cannot create a passenger user");
1849 return;
1850 }
1851 }
1852
1853 @NonNull
1854 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1855 ZoneUserBindingHelper helper = null;
1856 synchronized (mLockHelper) {
1857 if (mZoneUserBindingHelper == null) {
1858 Log.w(TAG_USER, "implementation is not delegated");
1859 return new ArrayList<OccupantZoneInfo>();
1860 }
1861 helper = mZoneUserBindingHelper;
1862 }
1863 return helper.getOccupantZones(occupantType);
1864 }
1865
1866 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1867 ZoneUserBindingHelper helper = null;
1868 synchronized (mLockHelper) {
1869 if (mZoneUserBindingHelper == null) {
1870 Log.w(TAG_USER, "implementation is not delegated");
1871 return false;
1872 }
1873 helper = mZoneUserBindingHelper;
1874 }
1875 return helper.assignUserToOccupantZone(userId, zoneId);
1876 }
1877
1878 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1879 ZoneUserBindingHelper helper = null;
1880 synchronized (mLockHelper) {
1881 if (mZoneUserBindingHelper == null) {
1882 Log.w(TAG_USER, "implementation is not delegated");
1883 return false;
1884 }
1885 helper = mZoneUserBindingHelper;
1886 }
1887 return helper.unassignUserFromOccupantZone(userId);
1888 }
1889
1890 private boolean isPassengerDisplayAvailable() {
1891 ZoneUserBindingHelper helper = null;
1892 synchronized (mLockHelper) {
1893 if (mZoneUserBindingHelper == null) {
1894 Log.w(TAG_USER, "implementation is not delegated");
1895 return false;
1896 }
1897 helper = mZoneUserBindingHelper;
1898 }
1899 return helper.isPassengerDisplayAvailable();
1900 }
1901
1902 /**
1903 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1904 * zone is returned.
1905 *
1906 * @param occupantType The type of an occupant.
1907 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1908 * if not found.
1909 */
1910 private int getZoneId(@OccupantTypeEnum int occupantType) {
1911 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1912 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1913 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001914}