blob: d17afed040f0d7092778bbcda2ad566e122b734e [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;
felipeale5bf0322020-04-16 15:10:57 -070038import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070039import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070040import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070041import android.car.userlib.HalCallback;
42import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070043import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070044import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070045import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070046import android.content.pm.PackageManager;
47import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070048import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070049import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070050import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070051import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070052import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
53import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Felipe Lemee3cab982020-03-12 11:39:29 -070054import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080055import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070056import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070057import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
58import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070059import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
60import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080061import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070062import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070063import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080064import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070065import android.os.Handler;
66import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070067import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080068import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070069import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070070import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070071import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070072import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070073import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070074import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070075import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080076import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080077import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078
79import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070080import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070081import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080082import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080083import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070084import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070085import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070086import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080087import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070088import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070089import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070090import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070091import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070092
93import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080094import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070095import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070096import java.util.Iterator;
97import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000098import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070099import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700100import java.util.concurrent.CountDownLatch;
101import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700102
103/**
104 * User service for cars. Manages users at boot time. Including:
105 *
106 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700107 * <li> Creates a user used as driver.
108 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700109 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700110 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700111 * <ol/>
112 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700113public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800114
felipealf7368962020-04-16 12:55:19 -0700115 private static final String TAG = TAG_USER;
116
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800117 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700118 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800119 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700120 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800121 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700122 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
felipeala68ecef2020-05-19 12:46:08 -0700123 /**
124 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
125 */
126 public static final String BUNDLE_USER_LOCALES =
127 CarUserServiceConstants.BUNDLE_USER_LOCALES;
128 /**
129 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
130 */
felipeal1a9410d2020-05-06 13:30:05 -0700131 public static final String BUNDLE_INITIAL_INFO_ACTION =
132 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800133
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700134 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700135 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700136 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700137 private final UserManager mUserManager;
138 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700139 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700140
Eric Jeongc91f9452019-08-30 15:04:21 -0700141 private final Object mLockUser = new Object();
142 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800143 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700144 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800145 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700146 // Only one passenger is supported.
147 @GuardedBy("mLockUser")
148 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700149 /**
150 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800151 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700152 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700153 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700154 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
155 /**
156 * Keep the list of background users started here. This is wholly for debugging purpose.
157 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700158 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700159 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
160
Felipe Leme58412202020-01-09 13:45:33 -0800161 private final UserHalService mHal;
162
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700163 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700164 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
165 getClass().getSimpleName());
166 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700167
Felipe Leme5528ff72020-02-10 19:05:14 -0800168 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800169 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700170 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800171 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700172 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800173
174 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800175 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700176 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800177 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700178 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800179
Mayank Garg7a114c82020-04-08 21:25:06 -0700180 /**
181 * User Id for the user switch in process, if any.
182 */
183 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700184 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700185 /**
186 * Request Id for the user switch in process, if any.
187 */
188 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700189 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700190 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
191
Eric Jeongc91f9452019-08-30 15:04:21 -0700192 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
193 new CopyOnWriteArrayList<>();
194
felipeal61ce3732020-04-03 11:01:00 -0700195 @Nullable
196 @GuardedBy("mLockUser")
197 private UserInfo mInitialUser;
198
Mayank Garg71661ea2020-04-29 01:25:03 -0700199 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700200
Mayank Garg587f1942020-05-06 01:41:34 -0700201 private IResultReceiver mUserSwitchUiReceiver;
202
Eric Jeongc91f9452019-08-30 15:04:21 -0700203 /** Interface for callbaks related to passenger activities. */
204 public interface PassengerCallback {
205 /** Called when passenger is started at a certain zone. */
206 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
207 /** Called when passenger is stopped. */
208 void onPassengerStopped(@UserIdInt int passengerId);
209 }
210
211 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
212 public interface ZoneUserBindingHelper {
213 /** Gets occupant zones corresponding to the occupant type. */
214 @NonNull
215 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
216 /** Assigns the user to the occupant zone. */
217 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
218 /** Makes the occupant zone unoccupied. */
219 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
220 /** Returns whether there is a passenger display. */
221 boolean isPassengerDisplayAvailable();
222 }
223
224 private final Object mLockHelper = new Object();
225 @GuardedBy("mLockHelper")
226 private ZoneUserBindingHelper mZoneUserBindingHelper;
227
Felipe Leme58412202020-01-09 13:45:33 -0800228 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700229 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
230 @NonNull IActivityManager am, int maxRunningUsers) {
231 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
232 new UserMetrics());
233 }
234
235 @VisibleForTesting
236 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
237 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
238 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700239 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
240 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700241 }
242 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800243 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700244 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700245 mAm = am;
246 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700247 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700248 mLastPassengerId = UserHandle.USER_NULL;
249 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700250 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700251 }
252
253 @Override
254 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700255 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
256 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700257 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700258 }
259
260 @Override
261 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700262 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
263 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700264 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700265 }
266
267 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700268 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700269 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700270 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800271 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700272 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700273 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700274 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700275 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700276 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
277 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700278 }
279 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
280 List<UserInfo> allDrivers = getAllDrivers();
281 int driversSize = allDrivers.size();
282 writer.println("NumberOfDrivers: " + driversSize);
283 for (int i = 0; i < driversSize; i++) {
284 int driverId = allDrivers.get(i).id;
285 writer.print(indent + "#" + i + ": id=" + driverId);
286 List<UserInfo> passengers = getPassengers(driverId);
287 int passengersSize = passengers.size();
288 writer.print(" NumberPassengers: " + passengersSize);
289 if (passengersSize > 0) {
290 writer.print(" [");
291 for (int j = 0; j < passengersSize; j++) {
292 writer.print(passengers.get(j).id);
293 if (j < passengersSize - 1) {
294 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700295 }
felipeal2d0483c2019-11-02 14:07:22 -0700296 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700297 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700298 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700299 writer.println();
300 }
301 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
302 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
303 writer.printf("Initial user: %s\n", mInitialUser);
304 writer.println("Relevant overlayable properties");
305 Resources res = mContext.getResources();
306 writer.printf("%sowner_name=%s\n", indent,
307 res.getString(com.android.internal.R.string.owner_name));
308 writer.printf("%sdefault_guest_name=%s\n", indent,
309 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700310 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700311 writer.printf("Request Id for the user switch in process=%d\n ",
312 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700313 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700314
315 dumpUserMetrics(writer);
316 }
317
318 /**
319 * Dumps user metrics.
320 */
321 public void dumpUserMetrics(@NonNull PrintWriter writer) {
322 mUserMetrics.dump(writer);
323 }
324
325 /**
326 * Dumps first user unlocking time.
327 */
328 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
329 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700330 }
331
332 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
333 CountDownLatch latch = new CountDownLatch(1);
334 mHandler.post(() -> {
335 handleDumpUserLifecycleListeners(writer);
336 handleDumpAppLifecycleListeners(writer, indent);
337 latch.countDown();
338 });
339 int timeout = 5;
340 try {
341 if (!latch.await(timeout, TimeUnit.SECONDS)) {
342 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
343 timeout);
344 }
345 } catch (InterruptedException e) {
346 Thread.currentThread().interrupt();
347 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
348 }
349 }
350
351 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
352 if (mUserLifecycleListeners.isEmpty()) {
353 writer.println("No user lifecycle listeners");
354 return;
355 }
356 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
357 for (UserLifecycleListener listener : mUserLifecycleListeners) {
358 writer.printf("Listener %s\n", listener);
359 }
360 }
361
362 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
363 int numberListeners = mAppLifecycleListeners.size();
364 if (numberListeners == 0) {
365 writer.println("No lifecycle listeners");
366 return;
367 }
368 writer.printf("%d lifecycle listeners\n", numberListeners);
369 for (int i = 0; i < numberListeners; i++) {
370 int uid = mAppLifecycleListeners.keyAt(i);
371 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
372 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800373 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700374 }
375
376 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800377 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
378 *
379 * @param name The name of the driver to be created.
380 * @param admin Whether the created driver will be an admin.
381 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
382 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700383 */
384 @Override
385 @Nullable
386 public UserInfo createDriver(@NonNull String name, boolean admin) {
387 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000388 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700389 if (admin) {
390 return createNewAdminUser(name);
391 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700392 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700393 }
394
395 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800396 * Creates a passenger who is a profile of the given driver.
397 *
398 * @param name The name of the passenger to be created.
399 * @param driverId User id of the driver under whom a passenger is created.
400 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
401 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700402 */
403 @Override
404 @Nullable
405 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
406 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000407 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700408 UserInfo driver = mUserManager.getUserInfo(driverId);
409 if (driver == null) {
410 Log.w(TAG_USER, "the driver is invalid");
411 return null;
412 }
413 if (driver.isGuest()) {
414 Log.w(TAG_USER, "a guest driver cannot create a passenger");
415 return null;
416 }
Bookatz42fb1a62019-10-30 11:45:01 -0700417 UserInfo user = mUserManager.createProfileForUser(name,
418 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700419 if (user == null) {
420 // Couldn't create user, most likely because there are too many.
421 Log.w(TAG_USER, "can't create a profile for user" + driverId);
422 return null;
423 }
424 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700425 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700426 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700427 return user;
428 }
429
430 /**
431 * @see CarUserManager.switchDriver
432 */
433 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700434 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700435 checkManageUsersPermission("switchDriver");
Eric Jeong25666cf2020-05-14 15:16:27 -0700436 if (UserHelper.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700437 // System user doesn't associate with real person, can not be switched to.
438 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700439 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700440 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700441 }
442 int userSwitchable = mUserManager.getUserSwitchability();
443 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
444 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700445 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700446 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700448 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700449 }
450
451 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800452 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
453 *
454 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700455 */
456 @Override
457 @NonNull
458 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700459 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700460 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700461 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700462 }
463
464 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800465 * Returns all passengers under the given driver.
466 *
467 * @param driverId User id of a driver.
468 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700469 */
470 @Override
471 @NonNull
472 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700473 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700475 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
476 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700477 });
478 }
479
480 /**
481 * @see CarUserManager.startPassenger
482 */
483 @Override
484 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
485 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700486 synchronized (mLockUser) {
487 try {
488 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
489 Log.w(TAG_USER, "could not start passenger");
490 return false;
491 }
492 } catch (RemoteException e) {
493 // ignore
494 Log.w(TAG_USER, "error while starting passenger", e);
495 return false;
496 }
497 if (!assignUserToOccupantZone(passengerId, zoneId)) {
498 Log.w(TAG_USER, "could not assign passenger to zone");
499 return false;
500 }
501 mLastPassengerId = passengerId;
502 }
503 for (PassengerCallback callback : mPassengerCallbacks) {
504 callback.onPassengerStarted(passengerId, zoneId);
505 }
506 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700507 }
508
509 /**
510 * @see CarUserManager.stopPassenger
511 */
512 @Override
513 public boolean stopPassenger(@UserIdInt int passengerId) {
514 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700515 return stopPassengerInternal(passengerId, true);
516 }
517
518 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
519 synchronized (mLockUser) {
520 UserInfo passenger = mUserManager.getUserInfo(passengerId);
521 if (passenger == null) {
522 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
523 return false;
524 }
525 if (mLastPassengerId != passengerId) {
526 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
527 return true;
528 }
529 if (checkCurrentDriver) {
530 int currentUser = ActivityManager.getCurrentUser();
531 if (passenger.profileGroupId != currentUser) {
532 Log.w(TAG_USER, "passenger " + passengerId
533 + " is not a profile of the current user");
534 return false;
535 }
536 }
537 // Passenger is a profile, so cannot be stopped through activity manager.
538 // Instead, activities started by the passenger are stopped and the passenger is
539 // unassigned from the zone.
540 stopAllTasks(passengerId);
541 if (!unassignUserFromOccupantZone(passengerId)) {
542 Log.w(TAG_USER, "could not unassign user from occupant zone");
543 return false;
544 }
545 mLastPassengerId = UserHandle.USER_NULL;
546 }
547 for (PassengerCallback callback : mPassengerCallbacks) {
548 callback.onPassengerStopped(passengerId);
549 }
550 return true;
551 }
552
553 private void stopAllTasks(@UserIdInt int userId) {
554 try {
555 for (StackInfo info : mAm.getAllStackInfos()) {
556 for (int i = 0; i < info.taskIds.length; i++) {
557 if (info.taskUserIds[i] == userId) {
558 int taskId = info.taskIds[i];
559 if (!mAm.removeTask(taskId)) {
560 Log.w(TAG_USER, "could not remove task " + taskId);
561 }
562 }
563 }
564 }
565 } catch (RemoteException e) {
566 Log.e(TAG_USER, "could not get stack info", e);
567 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700568 }
569
Felipe Leme5528ff72020-02-10 19:05:14 -0800570 @Override
571 public void setLifecycleListenerForUid(IResultReceiver listener) {
572 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700573 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800574 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
575
576 try {
577 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
578 } catch (RemoteException e) {
579 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
580 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700581 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800582 }
583
584 private void onListenerDeath(int uid) {
585 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700586 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800587 }
588
589 @Override
590 public void resetLifecycleListenerForUid() {
591 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700592 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800593 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700594 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800595 }
596
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800597 @Override
598 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800599 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700600 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
601 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800602 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700603 checkManageUsersPermission("getInitialInfo");
felipealdfdf8512020-06-01 09:35:45 -0700604 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800605 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700606 Bundle resultData = null;
607 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700608 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
609 status, resp.action, resp.userToSwitchOrCreate.userId,
felipeala68ecef2020-05-19 12:46:08 -0700610 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
Mayank Garg0e239142020-04-14 19:16:31 -0700611 switch (resp.action) {
612 case InitialUserInfoResponseAction.SWITCH:
613 resultData = new Bundle();
614 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
615 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
616 break;
617 case InitialUserInfoResponseAction.CREATE:
618 resultData = new Bundle();
619 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
620 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
621 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
622 break;
623 case InitialUserInfoResponseAction.DEFAULT:
624 resultData = new Bundle();
625 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
626 break;
627 default:
628 // That's ok, it will be the same as DEFAULT...
629 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800630 }
felipeal312416a2020-04-14 12:28:24 -0700631 } else {
632 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800633 }
felipeala68ecef2020-05-19 12:46:08 -0700634 if (resultData != null && !TextUtils.isEmpty(resp.userLocales)) {
635 resultData.putString(BUNDLE_USER_LOCALES, resp.userLocales);
636 }
637
Mayank Garg0e239142020-04-14 19:16:31 -0700638 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800639 });
640 }
641
Felipe Lemee3cab982020-03-12 11:39:29 -0700642 /**
felipeal61ce3732020-04-03 11:01:00 -0700643 * Gets the initial foreground user after the device boots or resumes from suspension.
644 *
645 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
646 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
647 * method returns {@code null}.
648 *
649 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
650 * (like switching to the last active user), and this method will return the result of such
651 * operation.
652 *
653 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
654 * {@code null}.
655 *
656 * @hide
657 */
658 @Nullable
659 public UserInfo getInitialUser() {
660 checkInteractAcrossUsersPermission("getInitialUser");
661 synchronized (mLockUser) {
662 return mInitialUser;
663 }
664 }
665
666 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
667 // some reason passing the whole UserInfo through a raw binder transaction is not working.
668 /**
669 * Sets the initial foreground user after the device boots or resumes from suspension.
670 */
671 public void setInitialUser(@UserIdInt int userId) {
672 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
673 : mUserManager.getUserInfo(userId);
674 setInitialUser(initialUser);
675 }
676
677 /**
678 * Sets the initial foreground user after the device boots or resumes from suspension.
679 */
680 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700681 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
682 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700683 synchronized (mLockUser) {
684 mInitialUser = user;
685 }
686 if (user == null) {
687 // This mean InitialUserSetter failed and could not fallback, so the initial user was
688 // not switched (and most likely is SYSTEM_USER).
689 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
690 Log.wtf(TAG_USER, "Initial user set to null");
691 }
692 }
693
694 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700695 * Calls the User HAL to get the initial user info.
696 *
697 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
698 * @param callback callback to receive the results.
699 */
700 public void getInitialUserInfo(int requestType,
701 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700702 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
703 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700704 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700705 checkManageUsersPermission("getInitialUserInfo");
felipealdfdf8512020-06-01 09:35:45 -0700706 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemee3cab982020-03-12 11:39:29 -0700707 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
708 }
709
710 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700711 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
712 *
713 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700714 * When everything works well, the workflow is:
715 * <ol>
716 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
717 * type, current user id, target user id, and a callback.
718 * <li> HAL called back with SUCCESS.
719 * <li> {@link IActivityManager} is called for Android user switch.
720 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
721 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
722 * request type, current user id, and target user id. In this case, the current and target
723 * user IDs would be same.
724 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700725 *
726 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700727 * Corner cases:
728 * <ul>
729 * <li> If target user is already the current user, no user switch is performed and receiver
730 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
731 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
732 * {@code STATUS_HAL_INTERNAL_FAILURE}.
733 * <li> If HAL user switch call is successful, but android user switch call fails,
734 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
735 * target user id, but in this case the current and target user IDs would be different.
736 * <li> If another user switch request for the same target user is received while previous
737 * request is in process, receiver would receive
738 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
739 * <li> If a user switch request is received while another user switch request for different
740 * target user is in process, the previous request would be abandoned and new request will be
741 * processed. No POST_SWITCH would be sent for the previous request.
742 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700743 *
Mayank Garge19c2922020-03-30 18:05:53 -0700744 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700745 * @param timeoutMs - timeout for HAL to wait
746 * @param receiver - receiver for the results
747 */
Mayank Garge19c2922020-03-30 18:05:53 -0700748 @Override
749 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700750 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700751 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700752 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700753 Objects.requireNonNull(receiver);
754 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700755 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700756
felipealf7368962020-04-16 12:55:19 -0700757 int currentUser = ActivityManager.getCurrentUser();
758 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700759 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
760 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
761 }
felipeale5bf0322020-04-16 15:10:57 -0700762 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
felipealdfdf8512020-06-01 09:35:45 -0700763 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700764 return;
765 }
766
Mayank Garg7a114c82020-04-08 21:25:06 -0700767 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700768 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
769 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
770 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
771 }
772
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700773 // If there is another request for the same target user, return another request in
774 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
775 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
776 // user switch request in process for different target user, but that request is now
777 // ignored.
felipealf7368962020-04-16 12:55:19 -0700778 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700779 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
780 Log.d(TAG_USER,
781 "Another user switch request in process for the requested target user: "
782 + targetUserId);
783 }
784
785 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700786 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700787 return;
788 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700789 else {
790 mUserIdForUserSwitchInProcess = targetUserId;
791 mRequestIdForUserSwitchInProcess = 0;
792 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700793 }
794
felipealdfdf8512020-06-01 09:35:45 -0700795 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg7a114c82020-04-08 21:25:06 -0700796 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700797 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700798 halTargetUser.userId = targetUser.id;
799 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
800 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700801 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
802 Log.d(TAG, "switch response: status="
803 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
804 }
805
felipeale5bf0322020-04-16 15:10:57 -0700806 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700807
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700808 synchronized (mLockUser) {
809 if (status != HalCallback.STATUS_OK) {
810 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
811 Log.w(TAG, "invalid callback status ("
812 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
813 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700814 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700815 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
816 return;
817 }
felipealf7368962020-04-16 12:55:19 -0700818
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700819 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
820 resp.errorMessage);
821
822 if (mUserIdForUserSwitchInProcess != targetUserId) {
823 // Another user switch request received while HAL responded. No need to process
824 // this request further
825 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
826 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
827 + "abondoned for : " + targetUserId + ". Current user in process: "
828 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700829 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700830 resultStatus =
831 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700832 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700833 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
834 return;
835 }
836
837 switch (resp.status) {
838 case SwitchUserStatus.SUCCESS:
839 boolean switched;
840 try {
841 switched = mAm.switchUser(targetUserId);
842 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700843 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700844 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
845 mRequestIdForUserSwitchInProcess = resp.requestId;
846 } else {
847 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
848 postSwitchHalResponse(resp.requestId, targetUserId);
849 }
850 } catch (RemoteException e) {
851 // ignore
852 Log.w(TAG_USER,
853 "error while switching user " + targetUser.toFullString(), e);
854 }
855 break;
856 case SwitchUserStatus.FAILURE:
857 // HAL failed to switch user
858 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
859 break;
felipealdfdf8512020-06-01 09:35:45 -0700860 default:
861 // Shouldn't happen because UserHalService validates the status
862 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700863 }
864
865 if (mRequestIdForUserSwitchInProcess == 0) {
866 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
867 }
Mayank Garg59f22192020-03-27 00:51:45 -0700868 }
felipealdfdf8512020-06-01 09:35:45 -0700869 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700870 });
871 }
872
Mayank Garg587f1942020-05-06 01:41:34 -0700873 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
874 if (mUserSwitchUiReceiver == null) {
875 Log.w(TAG_USER, "No User switch UI receiver.");
876 return;
877 }
878
felipealdfdf8512020-06-01 09:35:45 -0700879 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -0700880 try {
Mayank Garg587f1942020-05-06 01:41:34 -0700881 mUserSwitchUiReceiver.send(targetUserId, null);
882 } catch (RemoteException e) {
883 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
884 }
885 }
886
felipeal5e3ede42020-04-23 18:04:07 -0700887 @Override
felipealdfdf8512020-06-01 09:35:45 -0700888 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
889 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
890 Objects.requireNonNull(userType, "user type cannot be null");
891 Objects.requireNonNull(receiver, "receiver cannot be null");
892 checkManageOrCreateUsersPermission("createUser");
893 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
894 userType, flags, timeoutMs);
895
896 UserInfo newUser;
897 try {
898 newUser = mUserManager.createUser(name, userType, flags);
899 if (newUser == null) {
900 Log.w(TAG, "um.createUser() returned null for user of type " + userType
901 + " and flags " + UserInfo.flagsToString(flags));
902 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
903 return;
904 }
905 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
906 Log.d(TAG, "Created user: " + newUser.toFullString());
907 }
908 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
909 UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
910 } catch (RuntimeException e) {
911 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
912 + UserInfo.flagsToString(flags), e);
913 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
914 return;
915 }
916
917 CreateUserRequest request = new CreateUserRequest();
918 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
919 if (!TextUtils.isEmpty(name)) {
920 request.newUserName = name;
921 }
922 request.newUserInfo.userId = newUser.id;
923 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
924 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
925 Log.d(TAG, "Create user request: " + request);
926 }
927
928 try {
929 mHal.createUser(request, timeoutMs, (status, resp) -> {
930 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
931 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
932 Log.d(TAG, "createUserResponse: status="
933 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
934 }
935 UserInfo user = null; // user returned in the result
936 if (status != HalCallback.STATUS_OK) {
937 Log.w(TAG, "invalid callback status ("
938 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
939 + resp);
940 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
941 resultStatus, resp.errorMessage);
942 removeUser(newUser, "HAL call failed with "
943 + UserHalHelper.halCallbackStatusToString(status));
944 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
945 return;
946 }
947
948 switch (resp.status) {
949 case CreateUserStatus.SUCCESS:
950 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
951 user = newUser;
952 break;
953 case CreateUserStatus.FAILURE:
954 // HAL failed to switch user
955 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
956 break;
957 default:
958 // Shouldn't happen because UserHalService validates the status
959 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
960 }
961 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
962 resultStatus, resp.errorMessage);
963 if (user == null) {
964 removeUser(newUser, "HAL returned "
965 + UserCreationResult.statusToString(resultStatus));
966 }
967 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
968 });
969 } catch (Exception e) {
970 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
971 removeUser(newUser, "mHal.createUser() failed");
972 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
973 }
974 }
975
976 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
977 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
978 try {
979 if (!mUserManager.removeUser(user.id)) {
980 Log.w(TAG, "Failed to remove user " + user.toFullString());
981 }
982 } catch (Exception e) {
983 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
984 }
985 }
986
987 @Override
felipeal159a2a42020-05-08 10:32:11 -0700988 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
felipeal5e3ede42020-04-23 18:04:07 -0700989 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
990 checkManageUsersPermission("getUserIdentificationAssociation");
991
992 int uid = getCallingUid();
993 int userId = UserHandle.getUserId(uid);
994 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
995
996 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
997 request.userInfo.userId = userId;
998 request.userInfo.flags = getHalUserInfoFlags(userId);
999
1000 request.numberAssociationTypes = types.length;
1001 for (int i = 0; i < types.length; i++) {
1002 request.associationTypes.add(types[i]);
1003 }
1004
1005 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1006 if (halResponse == null) {
1007 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1008 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001009 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001010 }
1011
1012 int[] values = new int[halResponse.associations.size()];
1013 for (int i = 0; i < values.length; i++) {
1014 values[i] = halResponse.associations.get(i).value;
1015 }
1016 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1017
felipeal159a2a42020-05-08 10:32:11 -07001018 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1019 }
1020
1021 @Override
1022 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1023 AndroidFuture<UserIdentificationAssociationResponse> result) {
1024 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1025 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1026 if (types.length != values.length) {
1027 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1028 + Arrays.toString(values) + ") should have the same length");
1029 }
1030 checkManageUsersPermission("setUserIdentificationAssociation");
1031
1032 int uid = getCallingUid();
1033 int userId = UserHandle.getUserId(uid);
1034 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1035
1036 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1037 request.userInfo.userId = userId;
1038 request.userInfo.flags = getHalUserInfoFlags(userId);
1039
1040 request.numberAssociations = types.length;
1041 for (int i = 0; i < types.length; i++) {
1042 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1043 association.type = types[i];
1044 association.value = values[i];
1045 request.associations.add(association);
1046 }
1047
1048 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1049 if (status != HalCallback.STATUS_OK) {
1050 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1051 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1052 + resp);
1053 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1054 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1055 result.complete(UserIdentificationAssociationResponse.forFailure());
1056 return;
1057 }
1058 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1059 resp.errorMessage);
1060 result.complete(
1061 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1062 return;
1063 }
1064 int respSize = resp.associations.size();
1065 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1066 resp.errorMessage);
1067
1068 int[] responseTypes = new int[respSize];
1069 for (int i = 0; i < respSize; i++) {
1070 responseTypes[i] = resp.associations.get(i).value;
1071 }
1072 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1073 .forSuccess(responseTypes, resp.errorMessage);
1074 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1075 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1076 + ", converted=" + response);
1077 }
1078 result.complete(response);
1079 });
felipeal5e3ede42020-04-23 18:04:07 -07001080 }
1081
1082 /**
1083 * Gets the User HAL flags for the given user.
1084 *
1085 * @throws IllegalArgumentException if the user does not exist.
1086 */
1087 private int getHalUserInfoFlags(@UserIdInt int userId) {
1088 UserInfo user = mUserManager.getUserInfo(userId);
1089 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1090 return UserHalHelper.convertFlags(user);
1091 }
1092
Mayank Garg0e239142020-04-14 19:16:31 -07001093 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1094 @Nullable Bundle resultData) {
1095 try {
1096 receiver.send(resultCode, resultData);
1097 } catch (RemoteException e) {
1098 // ignore
1099 Log.w(TAG_USER, "error while sending results", e);
1100 }
1101 }
1102
felipealdfdf8512020-06-01 09:35:45 -07001103 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001104 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001105 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001106 }
1107
felipealdfdf8512020-06-01 09:35:45 -07001108 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001109 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1110 receiver.complete(new UserSwitchResult(status, errorMessage));
1111 }
1112
felipealdfdf8512020-06-01 09:35:45 -07001113 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1114 @UserCreationResult.Status int status) {
1115 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1116 }
1117
1118 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1119 @UserCreationResult.Status int status, @NonNull UserInfo user,
1120 @Nullable String errorMessage) {
1121 if (TextUtils.isEmpty(errorMessage)) {
1122 errorMessage = null;
1123 }
1124 receiver.complete(new UserCreationResult(status, user, errorMessage));
1125 }
1126
Mayank Garg6307fe42020-04-15 23:09:03 -07001127 /**
1128 * Calls activity manager for user switch.
1129 *
1130 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1131 *
1132 * @param requestId for the user switch request
1133 * @param targetUserId of the target user
1134 *
1135 * @hide
1136 */
1137 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1138 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1139 targetUserId);
1140 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1141
1142 try {
1143 boolean result = mAm.switchUser(targetUserId);
1144 if (result) {
1145 updateUserSwitchInProcess(requestId, targetUserId);
1146 } else {
1147 postSwitchHalResponse(requestId, targetUserId);
1148 }
1149 } catch (RemoteException e) {
1150 // ignore
1151 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1152 }
1153 }
1154
1155 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1156 synchronized (mLockUser) {
1157 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1158 // Some other user switch is in process.
1159 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1160 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1161 + " is in process. Abandoning it as a new user switch is requested"
1162 + " for the target user: " + targetUserId);
1163 }
1164 }
1165 mUserIdForUserSwitchInProcess = targetUserId;
1166 mRequestIdForUserSwitchInProcess = requestId;
1167 }
1168 }
1169
Mayank Garg7a114c82020-04-08 21:25:06 -07001170 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
1171 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealdfdf8512020-06-01 09:35:45 -07001172 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg7a114c82020-04-08 21:25:06 -07001173 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1174 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1175 halTargetUser.userId = targetUser.id;
1176 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -07001177 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1178 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001179 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
1180 }
1181
Mayank Garg59f22192020-03-27 00:51:45 -07001182 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001183 * Checks if the User HAL is supported.
1184 */
1185 public boolean isUserHalSupported() {
1186 return mHal.isSupported();
1187 }
1188
Mayank Garg587f1942020-05-06 01:41:34 -07001189 /**
1190 * Sets a callback which is invoked before user switch.
1191 *
1192 * <p>
1193 * This method should only be called by the Car System UI. The purpose of this call is to notify
1194 * Car System UI to show the user switch UI before the user switch.
1195 */
1196 @Override
1197 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001198 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001199
1200 // Confirm that caller is system UI.
1201 String systemUiPackageName = getSystemUiPackageName();
1202 if (systemUiPackageName == null) {
1203 throw new IllegalStateException("System UI package not found.");
1204 }
1205
1206 try {
1207 int systemUiUid = mContext
1208 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1209 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1210 int callerUid = Binder.getCallingUid();
1211 if (systemUiUid != callerUid) {
1212 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1213 + " is allowed to make this call");
1214 }
1215 } catch (NameNotFoundException e) {
1216 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1217 }
1218
Mayank Garg587f1942020-05-06 01:41:34 -07001219 mUserSwitchUiReceiver = receiver;
1220 }
1221
Mayank Garga480dd92020-05-14 03:14:57 -07001222 // TODO(157082995): This information can be taken from
1223 // PackageManageInternalImpl.getSystemUiServiceComponent
1224 @Nullable
1225 private String getSystemUiPackageName() {
1226 try {
1227 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1228 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1229 return componentName.getPackageName();
1230 } catch (RuntimeException e) {
1231 Log.w(TAG_USER, "error while getting system UI package name.", e);
1232 return null;
1233 }
1234 }
1235
Keun young Park13a7a822019-04-04 15:53:08 -07001236 private void updateDefaultUserRestriction() {
1237 // We want to set restrictions on system and guest users only once. These are persisted
1238 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1239 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001240 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1241 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001242 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001243 // Only apply the system user restrictions if the system user is headless.
1244 if (UserManager.isHeadlessSystemUserMode()) {
1245 setSystemUserRestrictions();
1246 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001247 Settings.Global.putInt(mContext.getContentResolver(),
1248 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001249 }
1250
Eric Jeong1545f3b2019-09-16 13:56:52 -07001251 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001252 return !mUserManager.getUserInfo(userId).isEphemeral();
1253 }
1254
Antonio Kantekc8114752020-03-05 21:37:39 -08001255 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001256 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1257 */
1258 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1259 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001260 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001261 }
1262
1263 /**
1264 * Removes previously added {@link UserLifecycleListener}.
1265 */
1266 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1267 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001268 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001269 }
1270
Eric Jeongc91f9452019-08-30 15:04:21 -07001271 /** Adds callback to listen to passenger activity events. */
1272 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001273 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001274 mPassengerCallbacks.add(callback);
1275 }
1276
1277 /** Removes previously added callback to listen passenger events. */
1278 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001279 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001280 mPassengerCallbacks.remove(callback);
1281 }
1282
1283 /** Sets the implementation of ZoneUserBindingHelper. */
1284 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1285 synchronized (mLockHelper) {
1286 mZoneUserBindingHelper = helper;
1287 }
1288 }
1289
felipeal98900c82020-04-09 09:05:02 -07001290 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001291 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001292 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001293 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001294 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001295 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1296 updateDefaultUserRestriction();
1297 tasks = new ArrayList<>(mUser0UnlockTasks);
1298 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001299 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001300 }
1301 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001302 Integer user = userId;
1303 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001304 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001305 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001306 mBackgroundUsersToRestart.remove(user);
1307 mBackgroundUsersToRestart.add(0, user);
1308 }
1309 // -1 for user 0
1310 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001311 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001312 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001313 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001314 + ", dropping least recently user from restart list:" + userToDrop);
1315 // Drop the least recently used user.
1316 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1317 }
1318 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001319 }
1320 }
1321 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001322 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001323 for (Runnable r : tasks) {
1324 r.run();
1325 }
1326 }
1327 }
1328
1329 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001330 * Starts all background users that were active in system.
1331 *
Keun young Parkfb656372019-03-12 18:37:55 -07001332 * @return list of background users started successfully.
1333 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001334 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001335 public ArrayList<Integer> startAllBackgroundUsers() {
1336 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001337 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001338 users = new ArrayList<>(mBackgroundUsersToRestart);
1339 mBackgroundUsersRestartedHere.clear();
1340 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001341 }
1342 ArrayList<Integer> startedUsers = new ArrayList<>();
1343 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001344 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001345 continue;
1346 }
1347 try {
1348 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001349 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1350 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001351 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001352 } else if (mAm.unlockUser(user, null, null, null)) {
1353 startedUsers.add(user);
1354 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001355 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001356 if (mUserManager.isUserRunning(user)) {
1357 // add to started list so that it can be stopped later.
1358 startedUsers.add(user);
1359 }
Keun young Parkfb656372019-03-12 18:37:55 -07001360 }
1361 }
1362 } catch (RemoteException e) {
1363 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001364 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001365 }
1366 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001367 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001368 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001369 ArrayList<Integer> usersToRemove = new ArrayList<>();
1370 for (Integer user : mBackgroundUsersToRestart) {
1371 if (!startedUsers.contains(user)) {
1372 usersToRemove.add(user);
1373 }
1374 }
1375 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1376 }
Keun young Parkfb656372019-03-12 18:37:55 -07001377 return startedUsers;
1378 }
1379
1380 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001381 * Stops all background users that were active in system.
1382 *
1383 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001384 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001385 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001386 if (userId == UserHandle.USER_SYSTEM) {
1387 return false;
1388 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001389 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001390 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001391 return false;
1392 }
1393 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001394 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001395 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001396 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001397 Integer user = userId;
1398 mBackgroundUsersRestartedHere.remove(user);
1399 }
1400 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1401 return false;
1402 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001403 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001404 return false;
1405 }
1406 } catch (RemoteException e) {
1407 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001408 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001409 }
1410 return true;
1411 }
1412
1413 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001414 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001415 */
felipeale8c5dce2020-04-15 11:27:06 -07001416 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1417 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1418 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001419
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001420 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001421 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001422 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001423 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1424 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001425 }
1426
felipeale8c5dce2020-04-15 11:27:06 -07001427 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001428 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001429
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001430 mHandler.post(() -> {
1431 handleNotifyServiceUserLifecycleListeners(event);
1432 handleNotifyAppUserLifecycleListeners(event);
1433 });
felipeale8c5dce2020-04-15 11:27:06 -07001434
Keun young Park1fced442020-05-29 09:26:29 -07001435 if (timestampMs != 0) {
1436 // Finally, update metrics.
1437 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1438 }
felipeale8c5dce2020-04-15 11:27:06 -07001439 }
1440
1441 /**
1442 * Sets the first user unlocking metrics.
1443 */
1444 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1445 int halResponseTime) {
1446 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001447 }
1448
Mayank Garg7a114c82020-04-08 21:25:06 -07001449 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001450 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001451 || mUserIdForUserSwitchInProcess != userId
1452 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001453 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1454 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1455 }
1456 return;
1457 }
felipealf7368962020-04-16 12:55:19 -07001458 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1459 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001460 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001461 }
1462
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001463 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1464 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001465 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001466 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1467 Log.d(TAG_USER, "No app listener to be notified of " + event);
1468 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001469 return;
1470 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001471 // Must use a different TimingsTraceLog because it's another thread
1472 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1473 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1474 }
felipeal2a84d512020-04-06 18:52:15 -07001475 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001476 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1477 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1478 for (int i = 0; i < listenersSize; i++) {
1479 int uid = mAppLifecycleListeners.keyAt(i);
1480 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1481 Bundle data = new Bundle();
1482 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001483
1484 int fromUid = event.getPreviousUserId();
1485 if (fromUid != UserHandle.USER_NULL) {
1486 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1487 }
1488
felipeal2a84d512020-04-06 18:52:15 -07001489 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001490 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001491 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001492 try {
felipeal2a84d512020-04-06 18:52:15 -07001493 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001494 listener.send(userId, data);
1495 } catch (RemoteException e) {
1496 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1497 } finally {
1498 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001499 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001500 }
1501 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001502 }
1503
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001504 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001505 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1506 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001507 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001508 return;
felipeal2a84d512020-04-06 18:52:15 -07001509 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1510 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1511 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001512 }
felipeal2a84d512020-04-06 18:52:15 -07001513
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001514 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1515 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001516 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001517 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001518 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001519 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001520 listener.onEvent(event);
1521 } catch (RuntimeException e) {
1522 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001523 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001524 } finally {
1525 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001526 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001527 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001528 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001529 }
1530
Mayank Garge5de0f92020-04-23 21:38:38 -07001531 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001532 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001533 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001534 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001535
Mayank Garge5de0f92020-04-23 21:38:38 -07001536 // Switch HAL users if user switch is not requested by CarUserService
1537 notifyHalLegacySwitch(fromUserId, toUserId);
1538
Felipe Lemeaba246c2020-05-11 15:02:52 -07001539 if (!UserHelper.isHeadlessSystemUser(toUserId)) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001540 mCarUserManagerHelper.setLastActiveUser(toUserId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001541 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001542 if (mLastPassengerId != UserHandle.USER_NULL) {
1543 stopPassengerInternal(mLastPassengerId, false);
1544 }
1545 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1546 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001547 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001548 }
felipeal98900c82020-04-09 09:05:02 -07001549 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001550 }
1551
Mayank Garge5de0f92020-04-23 21:38:38 -07001552 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1553 synchronized (mLockUser) {
1554 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1555 }
1556
1557 // switch HAL user
1558 UserInfo targetUser = mUserManager.getUserInfo(toUserId);
1559 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1560 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1561 halTargetUser.userId = targetUser.id;
1562 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipealdfdf8512020-06-01 09:35:45 -07001563 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garge5de0f92020-04-23 21:38:38 -07001564 mHal.legacyUserSwitch(halTargetUser, usersInfo);
1565 }
1566
Pavel Maltsev17e81832019-04-04 14:38:41 -07001567 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001568 * 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 -08001569 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001570 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001571 * @param r Runnable to run.
1572 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001573 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001574 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001575 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001576 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001577 if (mUser0Unlocked) {
1578 runNow = true;
1579 } else {
1580 mUser0UnlockTasks.add(r);
1581 }
1582 }
1583 if (runNow) {
1584 r.run();
1585 }
1586 }
1587
Keun young Parkf3523cd2019-04-08 10:09:17 -07001588 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001589 @NonNull
1590 ArrayList<Integer> getBackgroundUsersToRestart() {
1591 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001592 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001593 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1594 }
1595 return backgroundUsersToRestart;
1596 }
1597
Ying Zheng1ab32b62018-06-26 12:47:26 -07001598 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001599 // Disable Location service for system user.
1600 LocationManager locationManager =
1601 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001602 locationManager.setLocationEnabledForUser(
1603 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001604 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001605
1606 /**
1607 * Creates a new user on the system, the created user would be granted admin role.
1608 *
1609 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001610 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001611 */
1612 @Nullable
1613 private UserInfo createNewAdminUser(String name) {
1614 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1615 // Only admins or system user can create other privileged users.
1616 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1617 return null;
1618 }
1619
1620 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1621 if (user == null) {
1622 // Couldn't create user, most likely because there are too many.
1623 Log.w(TAG_USER, "can't create admin user.");
1624 return null;
1625 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001626 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001627
1628 return user;
1629 }
1630
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001631 /**
1632 * Assigns a default icon to a user according to the user's id.
1633 *
1634 * @param userInfo User whose avatar is set to default icon.
1635 * @return Bitmap of the user icon.
1636 */
1637 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1638 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1639 Bitmap bitmap = UserIcons.convertToBitmap(
1640 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1641 mUserManager.setUserIcon(userInfo.id, bitmap);
1642 return bitmap;
1643 }
1644
Eric Jeong1545f3b2019-09-16 13:56:52 -07001645 private interface UserFilter {
1646 boolean isEligibleUser(UserInfo user);
1647 }
1648
1649 /** Returns all users who are matched by the given filter. */
1650 private List<UserInfo> getUsers(UserFilter filter) {
1651 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1652
1653 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1654 UserInfo user = iterator.next();
1655 if (!filter.isEligibleUser(user)) {
1656 iterator.remove();
1657 }
1658 }
1659 return users;
1660 }
1661
1662 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001663 * Enforces that apps which have the
1664 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1665 * can make certain calls to the CarUserManager.
1666 *
1667 * @param message used as message if SecurityException is thrown.
1668 * @throws SecurityException if the caller is not system or root.
1669 */
1670 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001671 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1672 }
1673
felipealdfdf8512020-06-01 09:35:45 -07001674 private static void checkManageOrCreateUsersPermission(String message) {
1675 checkAtLeastOnePermission(message,
1676 android.Manifest.permission.MANAGE_USERS,
1677 android.Manifest.permission.CREATE_USERS);
1678 }
1679
felipeal2d0483c2019-11-02 14:07:22 -07001680 private static void checkManageUsersOrDumpPermission(String message) {
1681 checkAtLeastOnePermission(message,
1682 android.Manifest.permission.MANAGE_USERS,
1683 android.Manifest.permission.DUMP);
1684 }
1685
Felipe Leme5528ff72020-02-10 19:05:14 -08001686 private void checkInteractAcrossUsersPermission(String message) {
1687 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1688 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1689 }
1690
felipeal2d0483c2019-11-02 14:07:22 -07001691 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001692 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001693 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1694 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001695 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001696 }
1697 }
1698
felipeal2d0483c2019-11-02 14:07:22 -07001699 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1700 for (String permission : permissions) {
1701 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1702 /* exported = */ true)
1703 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1704 return true;
1705 }
1706 }
1707 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001708 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001709
1710 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1711 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1712 // Count all users that are managed profiles of the given user.
1713 int managedProfilesCount = 0;
1714 for (UserInfo user : users) {
1715 if (user.isManagedProfile() && user.profileGroupId == userId) {
1716 managedProfilesCount++;
1717 }
1718 }
1719 return managedProfilesCount;
1720 }
1721
1722 /**
1723 * Starts the first passenger of the given driver and assigns the passenger to the front
1724 * passenger zone.
1725 *
1726 * @param driverId User id of the driver.
1727 * @return whether it succeeds.
1728 */
1729 private boolean startFirstPassenger(@UserIdInt int driverId) {
1730 int zoneId = getAvailablePassengerZone();
1731 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1732 Log.w(TAG_USER, "passenger occupant zone is not found");
1733 return false;
1734 }
1735 List<UserInfo> passengers = getPassengers(driverId);
1736 if (passengers.size() < 1) {
1737 Log.w(TAG_USER, "passenger is not found");
1738 return false;
1739 }
1740 // Only one passenger is supported. If there are two or more passengers, the first passenger
1741 // is chosen.
1742 int passengerId = passengers.get(0).id;
1743 if (!startPassenger(passengerId, zoneId)) {
1744 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1745 return false;
1746 }
1747 return true;
1748 }
1749
1750 private int getAvailablePassengerZone() {
1751 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1752 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1753 for (int occupantType : occupantTypes) {
1754 int zoneId = getZoneId(occupantType);
1755 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1756 return zoneId;
1757 }
1758 }
1759 return OccupantZoneInfo.INVALID_ZONE_ID;
1760 }
1761
1762 /**
1763 * Creates a new passenger user when there is no passenger user.
1764 */
1765 private void setupPassengerUser() {
1766 int currentUser = ActivityManager.getCurrentUser();
1767 int profileCount = getNumberOfManagedProfiles(currentUser);
1768 if (profileCount > 0) {
1769 Log.w(TAG_USER, "max profile of user" + currentUser
1770 + " is exceeded: current profile count is " + profileCount);
1771 return;
1772 }
1773 // TODO(b/140311342): Use resource string for the default passenger name.
1774 UserInfo passenger = createPassenger("Passenger", currentUser);
1775 if (passenger == null) {
1776 // Couldn't create user, most likely because there are too many.
1777 Log.w(TAG_USER, "cannot create a passenger user");
1778 return;
1779 }
1780 }
1781
1782 @NonNull
1783 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1784 ZoneUserBindingHelper helper = null;
1785 synchronized (mLockHelper) {
1786 if (mZoneUserBindingHelper == null) {
1787 Log.w(TAG_USER, "implementation is not delegated");
1788 return new ArrayList<OccupantZoneInfo>();
1789 }
1790 helper = mZoneUserBindingHelper;
1791 }
1792 return helper.getOccupantZones(occupantType);
1793 }
1794
1795 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1796 ZoneUserBindingHelper helper = null;
1797 synchronized (mLockHelper) {
1798 if (mZoneUserBindingHelper == null) {
1799 Log.w(TAG_USER, "implementation is not delegated");
1800 return false;
1801 }
1802 helper = mZoneUserBindingHelper;
1803 }
1804 return helper.assignUserToOccupantZone(userId, zoneId);
1805 }
1806
1807 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1808 ZoneUserBindingHelper helper = null;
1809 synchronized (mLockHelper) {
1810 if (mZoneUserBindingHelper == null) {
1811 Log.w(TAG_USER, "implementation is not delegated");
1812 return false;
1813 }
1814 helper = mZoneUserBindingHelper;
1815 }
1816 return helper.unassignUserFromOccupantZone(userId);
1817 }
1818
1819 private boolean isPassengerDisplayAvailable() {
1820 ZoneUserBindingHelper helper = null;
1821 synchronized (mLockHelper) {
1822 if (mZoneUserBindingHelper == null) {
1823 Log.w(TAG_USER, "implementation is not delegated");
1824 return false;
1825 }
1826 helper = mZoneUserBindingHelper;
1827 }
1828 return helper.isPassengerDisplayAvailable();
1829 }
1830
1831 /**
1832 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1833 * zone is returned.
1834 *
1835 * @param occupantType The type of an occupant.
1836 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1837 * if not found.
1838 */
1839 private int getZoneId(@OccupantTypeEnum int occupantType) {
1840 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1841 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1842 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001843}