blob: c887a9a447ce527fe7ca0265e43cc725a7cbe514 [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
Felipe Leme17799202020-09-03 12:55:53 -070019import static android.Manifest.permission.CREATE_USERS;
20import static android.Manifest.permission.MANAGE_USERS;
Felipe Leme5d5ab142020-10-27 13:49:10 -070021import static android.car.drivingstate.CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP;
Felipe Leme17799202020-09-03 12:55:53 -070022
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import static com.android.car.CarLog.TAG_USER;
Felipe Leme55236722020-10-16 16:54:32 -070024import static com.android.car.PermissionHelper.checkHasAtLeastOnePermissionGranted;
25import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted;
Eric Jeong1545f3b2019-09-16 13:56:52 -070026
27import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070028import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070029import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070030import android.app.ActivityManager;
Louis Chang3bf2f202020-08-18 13:04:28 +080031import android.app.ActivityTaskManager.RootTaskInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070032import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070033import android.car.CarOccupantZoneManager;
34import android.car.CarOccupantZoneManager.OccupantTypeEnum;
35import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070036import android.car.ICarUserService;
Felipe Leme5d5ab142020-10-27 13:49:10 -070037import android.car.drivingstate.CarUxRestrictions;
Felipe Leme56ef9ad2020-11-05 18:39:03 -080038import android.car.drivingstate.ICarUxRestrictionsChangeListener;
jovanak24470652018-09-11 17:51:57 -070039import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080040import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080041import android.car.user.CarUserManager.UserLifecycleEvent;
42import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070043import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070044import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070045import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070046import android.car.user.UserSwitchResult;
felipeal19e3d732020-03-18 12:07:32 -070047import android.car.userlib.HalCallback;
48import android.car.userlib.UserHalHelper;
Mayank Garge90a4082020-09-30 12:57:34 -070049import android.car.userlib.UserHelper;
Felipe Leme6b34fc32020-10-26 15:49:17 -070050import android.content.BroadcastReceiver;
Mayank Garga480dd92020-05-14 03:14:57 -070051import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070052import android.content.Context;
Felipe Leme6b34fc32020-10-26 15:49:17 -070053import android.content.Intent;
54import android.content.IntentFilter;
Mayank Garga480dd92020-05-14 03:14:57 -070055import android.content.pm.PackageManager;
56import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070057import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070058import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070059import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070060import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070061import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
62import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070063import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080064import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070065import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070066import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070067import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070068import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
69import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070070import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
71import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080072import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070073import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070074import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080075import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070076import android.os.Handler;
77import android.os.HandlerThread;
Felipe Leme17799202020-09-03 12:55:53 -070078import android.os.Process;
Keun young Parkfb656372019-03-12 18:37:55 -070079import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080080import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070081import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070082import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070083import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070084import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070085import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070086import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070087import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080088import android.util.SparseArray;
Felipe Leme6b34fc32020-10-26 15:49:17 -070089import android.util.SparseBooleanArray;
Mayank Garg31e73042020-01-23 00:10:38 -080090import android.util.TimingsTraceLog;
Felipe Leme56ef9ad2020-11-05 18:39:03 -080091import android.view.Display;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070092
93import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070094import com.android.car.CarServiceUtils;
Felipe Leme5d5ab142020-10-27 13:49:10 -070095import com.android.car.CarUxRestrictionsManagerService;
Eric Jeongc91f9452019-08-30 15:04:21 -070096import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080097import com.android.car.hal.UserHalService;
Felipe Leme56ef9ad2020-11-05 18:39:03 -080098import com.android.car.internal.ICarServiceHelper;
Mayank Gargf59f95b2020-10-01 14:55:11 -070099import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
Mayank Garg801ea6a2020-09-29 15:43:49 -0700100import com.android.car.internal.common.EventLogTags;
101import com.android.car.internal.common.UserHelperLite;
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700102import com.android.car.power.CarPowerManagementService;
Mayank Garg665c20b2020-08-07 16:19:28 -0700103import com.android.car.user.InitialUserSetter.InitialUserInfo;
Keun-young Parkd462a912019-02-11 08:53:42 -0800104import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700105import com.android.internal.annotations.VisibleForTesting;
felipeale5bf0322020-04-16 15:10:57 -0700106import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -0800107import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -0700108import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -0700109import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -0700110import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700111import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700112
113import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -0800114import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -0700115import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700116import java.util.Iterator;
117import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000118import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700119import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700120import java.util.concurrent.CountDownLatch;
121import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700122
123/**
124 * User service for cars. Manages users at boot time. Including:
125 *
126 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700127 * <li> Creates a user used as driver.
128 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700129 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700130 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700131 * <ol/>
132 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700133public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800134
felipealf7368962020-04-16 12:55:19 -0700135 private static final String TAG = TAG_USER;
136
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800137 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700138 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800139 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700140 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800141 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700142 public static final String BUNDLE_USER_NAME = "user.name";
felipeala68ecef2020-05-19 12:46:08 -0700143 /**
144 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
145 */
Mayank Garg8f932822020-09-17 16:09:12 -0700146 public static final String BUNDLE_USER_LOCALES = "user.locales";
felipeala68ecef2020-05-19 12:46:08 -0700147 /**
148 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
149 */
Mayank Garg8f932822020-09-17 16:09:12 -0700150 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800151
Mayank Garg9ed099e2020-06-04 16:05:20 -0700152 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
153
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700154 private final Context mContext;
Keun young Parkfb656372019-03-12 18:37:55 -0700155 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700156 private final UserManager mUserManager;
157 private final int mMaxRunningUsers;
Mayank Garg70732a82020-08-05 20:17:47 -0700158 private final InitialUserSetter mInitialUserSetter;
Eric Jeongc91f9452019-08-30 15:04:21 -0700159 private final boolean mEnablePassengerSupport;
Mayank Garg9732d602020-08-09 21:02:40 -0700160 private final UserPreCreator mUserPreCreator;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700161
Eric Jeongc91f9452019-08-30 15:04:21 -0700162 private final Object mLockUser = new Object();
163 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800164 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700165 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800166 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 // Only one passenger is supported.
168 @GuardedBy("mLockUser")
169 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700170 /**
171 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800172 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700173 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700174 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700175 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
176 /**
177 * Keep the list of background users started here. This is wholly for debugging purpose.
178 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700179 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700180 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
181
Felipe Leme58412202020-01-09 13:45:33 -0800182 private final UserHalService mHal;
183
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700184 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700185 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
186 getClass().getSimpleName());
187 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700188
Felipe Leme5528ff72020-02-10 19:05:14 -0800189 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800190 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700191 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800192 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700193 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800194
195 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800196 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700197 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800198 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700199 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800200
Mayank Garg7a114c82020-04-08 21:25:06 -0700201 /**
202 * User Id for the user switch in process, if any.
203 */
204 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700205 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700206 /**
207 * Request Id for the user switch in process, if any.
208 */
209 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700210 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700211 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
212
Eric Jeongc91f9452019-08-30 15:04:21 -0700213 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
214 new CopyOnWriteArrayList<>();
215
Mayank Garg7e1450b2020-08-07 18:15:15 -0700216 // TODO(b/163566866): Use mSwitchGuestUserBeforeSleep for new create guest request
217 private final boolean mSwitchGuestUserBeforeSleep;
218
felipeal61ce3732020-04-03 11:01:00 -0700219 @Nullable
220 @GuardedBy("mLockUser")
221 private UserInfo mInitialUser;
222
Mayank Garg587f1942020-05-06 01:41:34 -0700223 private IResultReceiver mUserSwitchUiReceiver;
224
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800225 private final CarUxRestrictionsManagerService mCarUxRestrictionService;
226
227 /**
228 * Whether some operations - like user switch - are restricted by driving safety constraints.
229 */
230 @GuardedBy("mLockUser")
231 private boolean mUxRestricted;
232
233 /**
234 * Callback to notify {@code CarServiceHelper} about driving safety changes (through
235 * {@link ICarServiceHelper#setSafetyMode(boolean).
236 *
237 * <p>NOTE: in theory, that logic should belong to {@code CarDevicePolicyService}, but it's
238 * simpler to do it here (and that service already depends on this one).
239 */
240 @GuardedBy("mLockUser")
241 private ICarServiceHelper mICarServiceHelper;
242
243 private final ICarUxRestrictionsChangeListener mCarUxRestrictionsChangeListener =
244 new ICarUxRestrictionsChangeListener.Stub() {
245 @Override
246 public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
247 setUxRestrictions(restrictions);
248 }
249 };
Felipe Leme5d5ab142020-10-27 13:49:10 -0700250
Eric Jeongc91f9452019-08-30 15:04:21 -0700251 /** Interface for callbaks related to passenger activities. */
252 public interface PassengerCallback {
253 /** Called when passenger is started at a certain zone. */
254 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
255 /** Called when passenger is stopped. */
256 void onPassengerStopped(@UserIdInt int passengerId);
257 }
258
259 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
260 public interface ZoneUserBindingHelper {
261 /** Gets occupant zones corresponding to the occupant type. */
262 @NonNull
263 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
264 /** Assigns the user to the occupant zone. */
265 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
266 /** Makes the occupant zone unoccupied. */
267 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
268 /** Returns whether there is a passenger display. */
269 boolean isPassengerDisplayAvailable();
270 }
271
272 private final Object mLockHelper = new Object();
273 @GuardedBy("mLockHelper")
274 private ZoneUserBindingHelper mZoneUserBindingHelper;
275
Felipe Leme6b34fc32020-10-26 15:49:17 -0700276 private final BroadcastReceiver mUserLifecycleReceiver = new BroadcastReceiver() {
277 @Override
278 public void onReceive(Context context, Intent intent) {
279 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
280 Log.d(TAG_USER, "onReceive: " + intent);
281 }
282 switch(intent.getAction()) {
283 case Intent.ACTION_USER_REMOVED:
284 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
285 notifyHalUserRemoved(userId);
286 break;
287 default:
288 Log.w(TAG, "received unexpected intent: " + intent);
289 }
290 }
291 };
292
293 /** Map used to avoid calling UserHAL when a user was removed because HAL creation failed. */
294 @GuardedBy("mLockUser")
295 private final SparseBooleanArray mFailedToCreateUserIds = new SparseBooleanArray(1);
296
Felipe Leme58412202020-01-09 13:45:33 -0800297 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garge90a4082020-09-30 12:57:34 -0700298 @NonNull UserManager userManager,
Felipe Leme5d5ab142020-10-27 13:49:10 -0700299 @NonNull IActivityManager am, int maxRunningUsers,
300 @NonNull CarUxRestrictionsManagerService uxRestrictionService) {
Mayank Garge90a4082020-09-30 12:57:34 -0700301 this(context, hal, userManager, am, maxRunningUsers,
Felipe Leme5d5ab142020-10-27 13:49:10 -0700302 /* initialUserSetter= */ null, /* userPreCreator= */ null, uxRestrictionService);
Mayank Garg71661ea2020-04-29 01:25:03 -0700303 }
304
305 @VisibleForTesting
306 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garge90a4082020-09-30 12:57:34 -0700307 @NonNull UserManager userManager,
Mayank Gargccad8062020-08-30 15:05:10 -0700308 @NonNull IActivityManager am, int maxRunningUsers,
Mayank Garg1bb1c382020-09-03 17:11:11 -0700309 @Nullable InitialUserSetter initialUserSetter,
Felipe Leme5d5ab142020-10-27 13:49:10 -0700310 @Nullable UserPreCreator userPreCreator,
311 @NonNull CarUxRestrictionsManagerService uxRestrictionService) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700312 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
313 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700314 }
315 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800316 mHal = hal;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700317 mAm = am;
318 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700319 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700320 mLastPassengerId = UserHandle.USER_NULL;
Mayank Garg1bb1c382020-09-03 17:11:11 -0700321 mInitialUserSetter =
322 initialUserSetter == null ? new InitialUserSetter(context, (u) -> setInitialUser(u))
323 : initialUserSetter;
324 mUserPreCreator =
325 userPreCreator == null ? new UserPreCreator(mUserManager) : userPreCreator;
Mayank Garg7e1450b2020-08-07 18:15:15 -0700326 Resources resources = context.getResources();
327 mEnablePassengerSupport = resources.getBoolean(R.bool.enablePassengerSupport);
328 mSwitchGuestUserBeforeSleep = resources.getBoolean(
329 R.bool.config_switchGuestUserBeforeGoingSleep);
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800330 mCarUxRestrictionService = uxRestrictionService;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700331 }
332
333 @Override
334 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700335 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800336 Log.d(TAG_USER, "init()");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700337 }
Felipe Leme6b34fc32020-10-26 15:49:17 -0700338 mContext.registerReceiver(mUserLifecycleReceiver,
339 new IntentFilter(Intent.ACTION_USER_REMOVED));
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800340 mCarUxRestrictionService.registerUxRestrictionsChangeListener(
341 mCarUxRestrictionsChangeListener, Display.DEFAULT_DISPLAY);
342
343 setUxRestrictions(mCarUxRestrictionService.getCurrentUxRestrictions());
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700344 }
345
346 @Override
347 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700348 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800349 Log.d(TAG_USER, "release()");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700350 }
Felipe Leme6b34fc32020-10-26 15:49:17 -0700351 mContext.unregisterReceiver(mUserLifecycleReceiver);
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800352 mCarUxRestrictionService
353 .unregisterUxRestrictionsChangeListener(mCarUxRestrictionsChangeListener);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700354 }
355
356 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700357 public void dump(@NonNull PrintWriter writer) {
Felipe Leme55236722020-10-16 16:54:32 -0700358 checkHasDumpPermissionGranted("dump()");
359
Eric Jeong1545f3b2019-09-16 13:56:52 -0700360 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800361 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700362 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700363 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700364 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700365 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700366 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
367 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Felipe Leme6b34fc32020-10-26 15:49:17 -0700368 if (mFailedToCreateUserIds.size() > 0) {
369 writer.println("FailedToCreateUserIds: " + mFailedToCreateUserIds);
370 }
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800371 writer.printf("Is UX restricted: %b\n", mUxRestricted);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700372 }
373 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
374 List<UserInfo> allDrivers = getAllDrivers();
375 int driversSize = allDrivers.size();
376 writer.println("NumberOfDrivers: " + driversSize);
377 for (int i = 0; i < driversSize; i++) {
378 int driverId = allDrivers.get(i).id;
379 writer.print(indent + "#" + i + ": id=" + driverId);
380 List<UserInfo> passengers = getPassengers(driverId);
381 int passengersSize = passengers.size();
382 writer.print(" NumberPassengers: " + passengersSize);
383 if (passengersSize > 0) {
384 writer.print(" [");
385 for (int j = 0; j < passengersSize; j++) {
386 writer.print(passengers.get(j).id);
387 if (j < passengersSize - 1) {
388 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700389 }
felipeal2d0483c2019-11-02 14:07:22 -0700390 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700391 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700392 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700393 writer.println();
394 }
395 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
396 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
397 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700398
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700399 writer.println("Relevant overlayable properties");
400 Resources res = mContext.getResources();
401 writer.printf("%sowner_name=%s\n", indent,
402 res.getString(com.android.internal.R.string.owner_name));
403 writer.printf("%sdefault_guest_name=%s\n", indent,
404 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700405 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700406 writer.printf("Request Id for the user switch in process=%d\n ",
407 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700408 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700409
felipealbf327652020-06-03 11:33:29 -0700410 writer.println("Relevant Global settings");
411 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
412 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
413
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700414 mInitialUserSetter.dump(writer);
felipeale8c5dce2020-04-15 11:27:06 -0700415 }
416
felipealbf327652020-06-03 11:33:29 -0700417 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
418 String value = Settings.Global.getString(mContext.getContentResolver(), property);
419 writer.printf("%s%s=%s\n", indent, property, value);
420 }
421
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700422 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
423 CountDownLatch latch = new CountDownLatch(1);
424 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700425 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700426 handleDumpAppLifecycleListeners(writer, indent);
427 latch.countDown();
428 });
429 int timeout = 5;
430 try {
431 if (!latch.await(timeout, TimeUnit.SECONDS)) {
432 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
433 timeout);
434 }
435 } catch (InterruptedException e) {
436 Thread.currentThread().interrupt();
437 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
438 }
439 }
440
felipealde1e16d2020-06-03 13:20:48 -0700441 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700442 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700443 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700444 return;
445 }
felipealde1e16d2020-06-03 13:20:48 -0700446 int size = mUserLifecycleListeners.size();
447 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
448 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700449 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700450 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700451 }
452 }
453
454 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700455 int size = mAppLifecycleListeners.size();
456 if (size == 0) {
457 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700458 return;
459 }
felipealde1e16d2020-06-03 13:20:48 -0700460 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
461 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700462 int uid = mAppLifecycleListeners.keyAt(i);
463 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
Felipe Lemeea4b5322020-10-26 15:33:36 -0700464 writer.printf("%suid: %d listener: %s\n", indent, uid,
465 FunctionalUtils.getLambdaName(listener));
Keun-young Parkd462a912019-02-11 08:53:42 -0800466 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700467 }
468
469 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700470 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700471 */
472 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700473 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000475 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700476
477 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
478 @Override
479 protected void onCompleted(UserCreationResult result, Throwable err) {
480 if (result == null) {
481 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
482 } else {
483 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
484 assignDefaultIcon(result.getUser());
485 }
486 }
487 super.onCompleted(result, err);
488 };
489 };
490 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700491 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700492 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
493 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
494 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
495 return future;
496 }
497 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700498 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700499 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
500 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700501 }
502
503 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700504 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700505 */
506 @Override
507 @Nullable
508 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
509 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000510 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700511 UserInfo driver = mUserManager.getUserInfo(driverId);
512 if (driver == null) {
513 Log.w(TAG_USER, "the driver is invalid");
514 return null;
515 }
516 if (driver.isGuest()) {
517 Log.w(TAG_USER, "a guest driver cannot create a passenger");
518 return null;
519 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700520 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700521 UserInfo user = mUserManager.createProfileForUser(name,
522 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700523 if (user == null) {
524 // Couldn't create user, most likely because there are too many.
525 Log.w(TAG_USER, "can't create a profile for user" + driverId);
526 return null;
527 }
528 // Passenger user should be a non-admin user.
Mayank Garge90a4082020-09-30 12:57:34 -0700529 UserHelper.setDefaultNonAdminRestrictions(mContext, user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700530 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700531 return user;
532 }
533
534 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700535 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700536 */
537 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700538 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700539 checkManageUsersPermission("switchDriver");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700540 if (UserHelperLite.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700541 // System user doesn't associate with real person, can not be switched to.
542 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700543 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700544 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700545 }
546 int userSwitchable = mUserManager.getUserSwitchability();
547 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
548 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700549 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700550 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700551 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700552 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700553 }
554
555 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800556 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
557 *
558 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700559 */
560 @Override
561 @NonNull
562 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700563 checkManageUsersOrDumpPermission("getAllDrivers");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700564 return getUsers((user) -> !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700565 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700566 }
567
568 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800569 * Returns all passengers under the given driver.
570 *
571 * @param driverId User id of a driver.
572 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700573 */
574 @Override
575 @NonNull
576 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700577 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700578 return getUsers((user) -> {
Mayank Garg94f3eb92020-08-12 12:38:58 -0700579 return !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Eric Jeong40f8fa32020-05-12 12:23:33 -0700580 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700581 });
582 }
583
584 /**
585 * @see CarUserManager.startPassenger
586 */
587 @Override
588 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
589 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700590 synchronized (mLockUser) {
591 try {
592 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
593 Log.w(TAG_USER, "could not start passenger");
594 return false;
595 }
596 } catch (RemoteException e) {
597 // ignore
598 Log.w(TAG_USER, "error while starting passenger", e);
599 return false;
600 }
601 if (!assignUserToOccupantZone(passengerId, zoneId)) {
602 Log.w(TAG_USER, "could not assign passenger to zone");
603 return false;
604 }
605 mLastPassengerId = passengerId;
606 }
607 for (PassengerCallback callback : mPassengerCallbacks) {
608 callback.onPassengerStarted(passengerId, zoneId);
609 }
610 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700611 }
612
613 /**
614 * @see CarUserManager.stopPassenger
615 */
616 @Override
617 public boolean stopPassenger(@UserIdInt int passengerId) {
618 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700619 return stopPassengerInternal(passengerId, true);
620 }
621
622 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
623 synchronized (mLockUser) {
624 UserInfo passenger = mUserManager.getUserInfo(passengerId);
625 if (passenger == null) {
626 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
627 return false;
628 }
629 if (mLastPassengerId != passengerId) {
630 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
631 return true;
632 }
633 if (checkCurrentDriver) {
634 int currentUser = ActivityManager.getCurrentUser();
635 if (passenger.profileGroupId != currentUser) {
636 Log.w(TAG_USER, "passenger " + passengerId
637 + " is not a profile of the current user");
638 return false;
639 }
640 }
641 // Passenger is a profile, so cannot be stopped through activity manager.
642 // Instead, activities started by the passenger are stopped and the passenger is
643 // unassigned from the zone.
644 stopAllTasks(passengerId);
645 if (!unassignUserFromOccupantZone(passengerId)) {
646 Log.w(TAG_USER, "could not unassign user from occupant zone");
647 return false;
648 }
649 mLastPassengerId = UserHandle.USER_NULL;
650 }
651 for (PassengerCallback callback : mPassengerCallbacks) {
652 callback.onPassengerStopped(passengerId);
653 }
654 return true;
655 }
656
657 private void stopAllTasks(@UserIdInt int userId) {
658 try {
Louis Chang3bf2f202020-08-18 13:04:28 +0800659 for (RootTaskInfo info : mAm.getAllRootTaskInfos()) {
660 for (int i = 0; i < info.childTaskIds.length; i++) {
661 if (info.childTaskUserIds[i] == userId) {
662 int taskId = info.childTaskIds[i];
Eric Jeongc91f9452019-08-30 15:04:21 -0700663 if (!mAm.removeTask(taskId)) {
664 Log.w(TAG_USER, "could not remove task " + taskId);
665 }
666 }
667 }
668 }
669 } catch (RemoteException e) {
670 Log.e(TAG_USER, "could not get stack info", e);
671 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700672 }
673
Felipe Leme5528ff72020-02-10 19:05:14 -0800674 @Override
675 public void setLifecycleListenerForUid(IResultReceiver listener) {
676 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700677 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800678 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
679
680 try {
681 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
682 } catch (RemoteException e) {
683 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
684 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700685 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800686 }
687
688 private void onListenerDeath(int uid) {
689 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700690 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800691 }
692
693 @Override
694 public void resetLifecycleListenerForUid() {
695 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700696 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800697 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700698 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800699 }
700
Felipe Lemee3cab982020-03-12 11:39:29 -0700701 /**
felipeal61ce3732020-04-03 11:01:00 -0700702 * Gets the initial foreground user after the device boots or resumes from suspension.
703 *
704 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
705 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
706 * method returns {@code null}.
707 *
708 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
709 * (like switching to the last active user), and this method will return the result of such
710 * operation.
711 *
712 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
713 * {@code null}.
714 *
715 * @hide
716 */
717 @Nullable
718 public UserInfo getInitialUser() {
719 checkInteractAcrossUsersPermission("getInitialUser");
720 synchronized (mLockUser) {
721 return mInitialUser;
722 }
723 }
724
felipeal61ce3732020-04-03 11:01:00 -0700725 /**
726 * Sets the initial foreground user after the device boots or resumes from suspension.
727 */
728 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700729 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
730 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700731 synchronized (mLockUser) {
732 mInitialUser = user;
733 }
734 if (user == null) {
735 // This mean InitialUserSetter failed and could not fallback, so the initial user was
736 // not switched (and most likely is SYSTEM_USER).
737 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
738 Log.wtf(TAG_USER, "Initial user set to null");
739 }
740 }
741
Mayank Garg7e1450b2020-08-07 18:15:15 -0700742 private void initResumeReplaceGuest() {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700743 int currentUserId = ActivityManager.getCurrentUser();
744 UserInfo currentUser = mUserManager.getUserInfo(currentUserId);
745
746 if (!mInitialUserSetter.canReplaceGuestUser(currentUser)) return; // Not a guest
747
748 InitialUserInfo info =
749 new InitialUserSetter.Builder(InitialUserSetter.TYPE_REPLACE_GUEST).build();
750
751 mInitialUserSetter.set(info);
752 }
753
754 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700755 * Calls to switch user at the power suspend.
Mayank Garg7e1450b2020-08-07 18:15:15 -0700756 *
757 * <p><b>Note:</b> Should be used only by {@link CarPowerManagementService}
758 *
Mayank Garg7e1450b2020-08-07 18:15:15 -0700759 */
Mayank Garg0baf88a2020-08-30 21:57:36 -0700760 public void onSuspend() {
Mayank Garg7e1450b2020-08-07 18:15:15 -0700761 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Mayank Garg0baf88a2020-08-30 21:57:36 -0700762 Log.d(TAG_USER, "onSuspend called.");
Mayank Garg7e1450b2020-08-07 18:15:15 -0700763 }
764
Mayank Garg0baf88a2020-08-30 21:57:36 -0700765 if (mSwitchGuestUserBeforeSleep) {
766 initResumeReplaceGuest();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700767 }
Mayank Garg1bb1c382020-09-03 17:11:11 -0700768
769 preCreateUsers();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700770 }
771
772 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700773 * Calls to switch user at the power resume.
774 *
775 * <p>
776 * <b>Note:</b> Should be used only by {@link CarPowerManagementService}
777 *
778 */
779 public void onResume() {
780 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
781 Log.d(TAG_USER, "onResume called.");
782 }
783
784 initBootUser(InitialUserInfoRequestType.RESUME);
785 }
786
787 /**
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700788 * Calls to start user at the android startup.
Mayank Garg70732a82020-08-05 20:17:47 -0700789 */
790 public void initBootUser() {
791 int requestType = getInitialUserInfoRequestType();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700792 initBootUser(requestType);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700793 }
794
Mayank Garg7e1450b2020-08-07 18:15:15 -0700795 private void initBootUser(int requestType) {
796 boolean replaceGuest =
797 requestType == InitialUserInfoRequestType.RESUME && !mSwitchGuestUserBeforeSleep;
Mayank Garg70732a82020-08-05 20:17:47 -0700798 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
799 mHalTimeoutMs);
800 checkManageUsersPermission("startInitialUser");
801
802 if (!isUserHalSupported()) {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700803 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700804 return;
805 }
806
807 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
808 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
809 if (resp != null) {
810 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
811 status, resp.action, resp.userToSwitchOrCreate.userId,
812 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
813
814 String userLocales = resp.userLocales;
815 InitialUserInfo info;
816 switch (resp.action) {
817 case InitialUserInfoResponseAction.SWITCH:
818 int userId = resp.userToSwitchOrCreate.userId;
819 if (userId <= 0) {
820 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700821 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700822 break;
823 }
824 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
825 .setUserLocales(userLocales)
826 .setSwitchUserId(userId)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700827 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700828 .build();
829 mInitialUserSetter.set(info);
830 break;
831
832 case InitialUserInfoResponseAction.CREATE:
833 int halFlags = resp.userToSwitchOrCreate.flags;
834 String userName = resp.userNameToCreate;
835 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
836 .setUserLocales(userLocales)
837 .setNewUserName(userName)
838 .setNewUserFlags(halFlags)
839 .build();
840 mInitialUserSetter.set(info);
841 break;
842
843 case InitialUserInfoResponseAction.DEFAULT:
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700844 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700845 break;
846 default:
847 Log.w(TAG_USER, "invalid response action on " + resp);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700848 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700849 break;
850
851 }
852 } else {
853 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700854 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700855 }
856 });
857 }
858
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700859 private void fallbackToDefaultInitialUserBehavior(String userLocales, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700860 InitialUserInfo info = new InitialUserSetter.Builder(
861 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
862 .setUserLocales(userLocales)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700863 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700864 .build();
865 mInitialUserSetter.set(info);
866 }
867
868 @VisibleForTesting
869 int getInitialUserInfoRequestType() {
Mayank Garge90a4082020-09-30 12:57:34 -0700870 if (!mInitialUserSetter.hasInitialUser()) {
Mayank Garg70732a82020-08-05 20:17:47 -0700871 return InitialUserInfoRequestType.FIRST_BOOT;
872 }
873 if (mContext.getPackageManager().isDeviceUpgrading()) {
874 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
875 }
876 return InitialUserInfoRequestType.COLD_BOOT;
877 }
878
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800879 /**
880 * Sets the {@link ICarServiceHelper} so it can receive UX restriction updates.
881 */
882 public void setCarServiceHelper(ICarServiceHelper helper) {
883 boolean restricted;
884 synchronized (mLockUser) {
885 mICarServiceHelper = helper;
886 restricted = mUxRestricted;
887 }
888 updateSafetyMode(helper, restricted);
889 }
890
891 private void updateSafetyMode(@Nullable ICarServiceHelper helper, boolean restricted) {
892 if (helper == null) return;
893
894 boolean isSafe = !restricted;
895 try {
896 helper.setSafetyMode(isSafe);
897 } catch (Exception e) {
898 Log.e(TAG, "Exception calling helper.setDpmSafetyMode(" + isSafe + ")", e);
899 }
900 }
901
902 private void setUxRestrictions(@Nullable CarUxRestrictions restrictions) {
Felipe Leme5d5ab142020-10-27 13:49:10 -0700903 boolean restricted = restrictions != null
904 && (restrictions.getActiveRestrictions() & UX_RESTRICTIONS_NO_SETUP)
905 == UX_RESTRICTIONS_NO_SETUP;
906 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800907 Log.d(TAG_USER, "setUxRestrictions(" + restrictions + "): restricted=" + restricted);
908 } else {
909 Log.i(TAG_USER, "Setting UX restricted to " + restricted);
Felipe Leme5d5ab142020-10-27 13:49:10 -0700910 }
Felipe Leme56ef9ad2020-11-05 18:39:03 -0800911
912 ICarServiceHelper helper = null;
913
914 synchronized (mLockUser) {
915 mUxRestricted = restricted;
916 if (mICarServiceHelper == null) {
917 Log.e(TAG, "onUxRestrictionsChanged(): no mICarServiceHelper");
918 }
919 helper = mICarServiceHelper;
920 }
921 updateSafetyMode(helper, restricted);
922 }
923
924 private boolean isUxRestricted() {
925 synchronized (mLockUser) {
926 return mUxRestricted;
927 }
Felipe Leme5d5ab142020-10-27 13:49:10 -0700928 }
929
Mayank Garg70732a82020-08-05 20:17:47 -0700930 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700931 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
932 *
933 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700934 * When everything works well, the workflow is:
935 * <ol>
936 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
937 * type, current user id, target user id, and a callback.
938 * <li> HAL called back with SUCCESS.
939 * <li> {@link IActivityManager} is called for Android user switch.
940 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
941 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
942 * request type, current user id, and target user id. In this case, the current and target
943 * user IDs would be same.
944 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700945 *
946 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700947 * Corner cases:
948 * <ul>
949 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700950 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700951 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
952 * {@code STATUS_HAL_INTERNAL_FAILURE}.
953 * <li> If HAL user switch call is successful, but android user switch call fails,
954 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
955 * target user id, but in this case the current and target user IDs would be different.
956 * <li> If another user switch request for the same target user is received while previous
957 * request is in process, receiver would receive
958 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
959 * <li> If a user switch request is received while another user switch request for different
960 * target user is in process, the previous request would be abandoned and new request will be
961 * processed. No POST_SWITCH would be sent for the previous request.
962 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700963 *
Mayank Garge19c2922020-03-30 18:05:53 -0700964 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700965 * @param timeoutMs - timeout for HAL to wait
966 * @param receiver - receiver for the results
967 */
Mayank Garge19c2922020-03-30 18:05:53 -0700968 @Override
969 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700970 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700971 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Felipe Leme17799202020-09-03 12:55:53 -0700972 checkManageOrCreateUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700973 Objects.requireNonNull(receiver);
974 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700975 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700976
felipealf7368962020-04-16 12:55:19 -0700977 int currentUser = ActivityManager.getCurrentUser();
978 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700979 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
980 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
981 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700982 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700983 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700984 return;
985 }
986
Felipe Leme5d5ab142020-10-27 13:49:10 -0700987 if (isUxRestricted()) {
988 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
989 return;
990 }
991
Mayank Garg9ed099e2020-06-04 16:05:20 -0700992 // If User Hal is not supported, just android user switch.
993 if (!isUserHalSupported()) {
994 try {
995 if (mAm.switchUser(targetUserId)) {
996 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
997 return;
998 }
999 } catch (RemoteException e) {
1000 // ignore
1001 Log.w(TAG_USER,
1002 "error while switching user " + targetUser.toFullString(), e);
1003 }
1004 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
1005 return;
1006 }
1007
Mayank Garg7a114c82020-04-08 21:25:06 -07001008 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -07001009 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1010 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
1011 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
1012 }
1013
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001014 // If there is another request for the same target user, return another request in
1015 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
1016 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
1017 // user switch request in process for different target user, but that request is now
1018 // ignored.
felipealf7368962020-04-16 12:55:19 -07001019 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001020 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1021 Log.d(TAG_USER,
1022 "Another user switch request in process for the requested target user: "
1023 + targetUserId);
1024 }
1025
1026 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -07001027 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -07001028 return;
1029 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001030 else {
1031 mUserIdForUserSwitchInProcess = targetUserId;
1032 mRequestIdForUserSwitchInProcess = 0;
1033 }
Mayank Garg7a114c82020-04-08 21:25:06 -07001034 }
1035
felipealdfdf8512020-06-01 09:35:45 -07001036 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001037 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1038
Felipe Leme5d5ab142020-10-27 13:49:10 -07001039 mHal.switchUser(request, timeoutMs, (halCallbackStatus, resp) -> {
felipealf7368962020-04-16 12:55:19 -07001040 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1041 Log.d(TAG, "switch response: status="
Felipe Leme5d5ab142020-10-27 13:49:10 -07001042 + UserHalHelper.halCallbackStatusToString(halCallbackStatus)
1043 + ", resp=" + resp);
felipealf7368962020-04-16 12:55:19 -07001044 }
1045
felipeale5bf0322020-04-16 15:10:57 -07001046 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -07001047
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001048 synchronized (mLockUser) {
Felipe Leme5d5ab142020-10-27 13:49:10 -07001049 if (halCallbackStatus != HalCallback.STATUS_OK) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001050 Log.w(TAG, "invalid callback status ("
Felipe Leme5d5ab142020-10-27 13:49:10 -07001051 + UserHalHelper.halCallbackStatusToString(halCallbackStatus)
1052 + ") for response " + resp);
felipealdfdf8512020-06-01 09:35:45 -07001053 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001054 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
1055 return;
1056 }
felipealf7368962020-04-16 12:55:19 -07001057
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001058 if (mUserIdForUserSwitchInProcess != targetUserId) {
1059 // Another user switch request received while HAL responded. No need to process
1060 // this request further
1061 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1062 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
1063 + "abondoned for : " + targetUserId + ". Current user in process: "
1064 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -07001065 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001066 resultStatus =
1067 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -07001068 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001069 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
1070 return;
1071 }
1072
1073 switch (resp.status) {
1074 case SwitchUserStatus.SUCCESS:
1075 boolean switched;
1076 try {
1077 switched = mAm.switchUser(targetUserId);
1078 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -07001079 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001080 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
1081 mRequestIdForUserSwitchInProcess = resp.requestId;
1082 } else {
1083 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
1084 postSwitchHalResponse(resp.requestId, targetUserId);
1085 }
1086 } catch (RemoteException e) {
1087 // ignore
1088 Log.w(TAG_USER,
1089 "error while switching user " + targetUser.toFullString(), e);
1090 }
1091 break;
1092 case SwitchUserStatus.FAILURE:
1093 // HAL failed to switch user
1094 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
1095 break;
felipealdfdf8512020-06-01 09:35:45 -07001096 default:
1097 // Shouldn't happen because UserHalService validates the status
1098 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001099 }
1100
1101 if (mRequestIdForUserSwitchInProcess == 0) {
1102 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
1103 }
Mayank Garg59f22192020-03-27 00:51:45 -07001104 }
Felipe Leme5d5ab142020-10-27 13:49:10 -07001105 sendUserSwitchResult(receiver, halCallbackStatus, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -07001106 });
1107 }
1108
Mayank Garga55c3092020-05-28 03:19:24 -07001109 @Override
Felipe Leme55236722020-10-16 16:54:32 -07001110 public UserRemovalResult removeUser(@UserIdInt int userId) {
1111 return removeUser(userId, /* hasCallerRestrictions= */ false);
1112 }
1113
1114 /**
1115 * Internal implementation of {@code removeUser()}, which is used by both
1116 * {@code ICarUserService} and {@code ICarDevicePolicyService}.
1117 *
1118 * @param userId user to be removed
1119 * @param hasCallerRestrictions when {@code true}, if the caller user is not an admin, it can
1120 * only remove itself.
1121 *
1122 * @return result of the operation.
1123 */
Felipe Lemee5bb26b2020-10-26 15:49:17 -07001124 public UserRemovalResult removeUser(@UserIdInt int userId, boolean hasCallerRestrictions) {
Felipe Leme17799202020-09-03 12:55:53 -07001125 checkManageOrCreateUsersPermission("removeUser");
Felipe Leme55236722020-10-16 16:54:32 -07001126 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId,
1127 hasCallerRestrictions ? 1 : 0);
Felipe Lemee5bb26b2020-10-26 15:49:17 -07001128
Mayank Garga55c3092020-05-28 03:19:24 -07001129 // If the requested user is the current user, return error.
1130 if (ActivityManager.getCurrentUser() == userId) {
1131 return logAndGetResults(userId,
1132 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
1133 }
1134
1135 // If requested user is the only admin user, return error.
1136 UserInfo userInfo = mUserManager.getUserInfo(userId);
1137 if (userInfo == null) {
1138 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
1139 }
1140
Felipe Lemee5bb26b2020-10-26 15:49:17 -07001141 if (hasCallerRestrictions) {
1142 // Restrictions: non-admin user can only remove itself, admins have no restrictions
1143 int callingUserId = Binder.getCallingUserHandle().getIdentifier();
1144 UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
1145 if (!callingUser.isAdmin() && userId != callingUserId) {
1146 throw new SecurityException("Non-admin user " + callingUserId
1147 + " can only remove itself");
1148 }
1149 }
1150
Mayank Garga55c3092020-05-28 03:19:24 -07001151 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1152 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1153 halUser.userId = userInfo.id;
1154 halUser.flags = UserHalHelper.convertFlags(userInfo);
1155 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1156
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001157 // check if the user is last admin user.
1158 boolean isLastAdmin = false;
Mayank Garga55c3092020-05-28 03:19:24 -07001159 if (UserHalHelper.isAdmin(halUser.flags)) {
1160 int size = usersInfo.existingUsers.size();
1161 int totalAdminUsers = 0;
1162 for (int i = 0; i < size; i++) {
1163 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
1164 totalAdminUsers++;
1165 }
1166 }
1167 if (totalAdminUsers == 1) {
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001168 isLastAdmin = true;
Mayank Garga55c3092020-05-28 03:19:24 -07001169 }
1170 }
1171
1172 // First remove user from android and then remove from HAL because HAL remove user is one
1173 // way call.
1174 if (!mUserManager.removeUser(userId)) {
1175 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1176 }
1177
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001178 if (isLastAdmin) {
1179 Log.w(TAG_USER, "Last admin user successfully removed. User Id: " + userId);
1180 }
1181
1182 return logAndGetResults(userId,
1183 isLastAdmin ? UserRemovalResult.STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED
1184 : UserRemovalResult.STATUS_SUCCESSFUL);
Mayank Garga55c3092020-05-28 03:19:24 -07001185 }
1186
Felipe Leme6b34fc32020-10-26 15:49:17 -07001187 private void notifyHalUserRemoved(@UserIdInt int userId) {
1188 if (!isUserHalSupported()) return;
1189
1190 if (userId == UserHandle.USER_NULL) {
1191 Log.wtf(TAG, "notifyHalUserRemoved() Called for UserHandle.USER_NULL");
1192 return;
1193 }
1194
1195 synchronized (mLockUser) {
1196 if (mFailedToCreateUserIds.get(userId)) {
1197 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1198 Log.d(TAG, "notifyHalUserRemoved(): skipping " + userId);
1199 }
1200 mFailedToCreateUserIds.delete(userId);
1201 return;
1202 }
1203 }
1204
1205 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1206 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1207 halUser.userId = userId;
1208 // TODO(b/155913815): per the REMOVE_USER API, the userFlags should be set as well, but it's
1209 // gone. We'll need to either update the documentation, or if that's not possible (as it's
1210 // breaking the contract), either change the intent to contain the flags, or keep track of
1211 // the flags internally.
1212
1213 RemoveUserRequest request = new RemoveUserRequest();
1214 request.removedUserInfo = halUser;
1215 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1216 mHal.removeUser(request);
1217 }
1218
Mayank Garga55c3092020-05-28 03:19:24 -07001219 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1220 @UserRemovalResult.Status int result) {
1221 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1222 return new UserRemovalResult(result);
1223 }
1224
Mayank Garg587f1942020-05-06 01:41:34 -07001225 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1226 if (mUserSwitchUiReceiver == null) {
1227 Log.w(TAG_USER, "No User switch UI receiver.");
1228 return;
1229 }
1230
felipealdfdf8512020-06-01 09:35:45 -07001231 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001232 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001233 mUserSwitchUiReceiver.send(targetUserId, null);
1234 } catch (RemoteException e) {
1235 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1236 }
1237 }
1238
felipeal5e3ede42020-04-23 18:04:07 -07001239 @Override
felipealdfdf8512020-06-01 09:35:45 -07001240 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1241 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
Felipe Leme8c888ab2020-11-02 17:39:52 -08001242 createUser(name, userType, flags, timeoutMs, receiver, /* hasCallerRestrictions= */ false);
1243 }
1244
1245 /**
1246 * Internal implementation of {@code createUser()}, which is used by both
1247 * {@code ICarUserService} and {@code ICarDevicePolicyService}.
1248 *
1249 * @param hasCallerRestrictions when {@code true}, if the caller user is not an admin, it can
1250 * only create admin users
1251 */
1252 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1253 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver,
1254 boolean hasCallerRestrictions) {
felipealdfdf8512020-06-01 09:35:45 -07001255 Objects.requireNonNull(userType, "user type cannot be null");
1256 Objects.requireNonNull(receiver, "receiver cannot be null");
Felipe Leme17799202020-09-03 12:55:53 -07001257 checkManageOrCreateUsersPermission(flags);
1258
Mayank Garg94f3eb92020-08-12 12:38:58 -07001259 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
Felipe Leme8c888ab2020-11-02 17:39:52 -08001260 UserHelperLite.safeName(name), userType, flags, timeoutMs,
1261 hasCallerRestrictions ? 1 : 0);
1262
1263 if (hasCallerRestrictions) {
1264 // Restrictions:
1265 // - type/flag can only be normal user, admin, or guest
1266 // - non-admin user can only create non-admin users
1267
1268 boolean validCombination;
1269 switch (userType) {
1270 case UserManager.USER_TYPE_FULL_SECONDARY:
1271 validCombination = flags == 0
1272 || (flags & UserInfo.FLAG_ADMIN) == UserInfo.FLAG_ADMIN;
1273 break;
1274 case UserManager.USER_TYPE_FULL_GUEST:
1275 validCombination = flags == 0;
1276 break;
1277 default:
1278 validCombination = false;
1279 }
1280 if (!validCombination) {
Felipe Leme71d296f2020-11-04 12:11:42 -08001281 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1282 Log.d(TAG, "Invalid combination of user type(" + userType
1283 + ") and flags (" + UserInfo.flagsToString(flags)
1284 + ") for caller with restrictions");
1285 }
1286 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_INVALID_REQUEST);
1287 return;
1288
Felipe Leme8c888ab2020-11-02 17:39:52 -08001289 }
1290
1291 int callingUserId = Binder.getCallingUserHandle().getIdentifier();
1292 UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
1293 if (!callingUser.isAdmin() && (flags & UserInfo.FLAG_ADMIN) == UserInfo.FLAG_ADMIN) {
Felipe Leme71d296f2020-11-04 12:11:42 -08001294 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1295 Log.d(TAG, "Non-admin user " + callingUserId
1296 + " can only create non-admin users");
1297 }
1298 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_INVALID_REQUEST);
1299 return;
Felipe Leme8c888ab2020-11-02 17:39:52 -08001300 }
Felipe Leme71d296f2020-11-04 12:11:42 -08001301
Felipe Leme8c888ab2020-11-02 17:39:52 -08001302 }
felipealdfdf8512020-06-01 09:35:45 -07001303
1304 UserInfo newUser;
1305 try {
1306 newUser = mUserManager.createUser(name, userType, flags);
1307 if (newUser == null) {
1308 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1309 + " and flags " + UserInfo.flagsToString(flags));
1310 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1311 return;
1312 }
1313 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1314 Log.d(TAG, "Created user: " + newUser.toFullString());
1315 }
1316 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
Mayank Garg94f3eb92020-08-12 12:38:58 -07001317 UserHelperLite.safeName(newUser.name), newUser.userType, newUser.flags);
felipealdfdf8512020-06-01 09:35:45 -07001318 } catch (RuntimeException e) {
1319 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1320 + UserInfo.flagsToString(flags), e);
1321 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1322 return;
1323 }
1324
Mayank Garg9ed099e2020-06-04 16:05:20 -07001325 if (!isUserHalSupported()) {
1326 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1327 return;
1328 }
1329
felipealdfdf8512020-06-01 09:35:45 -07001330 CreateUserRequest request = new CreateUserRequest();
1331 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1332 if (!TextUtils.isEmpty(name)) {
1333 request.newUserName = name;
1334 }
1335 request.newUserInfo.userId = newUser.id;
1336 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1337 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1338 Log.d(TAG, "Create user request: " + request);
1339 }
1340
1341 try {
1342 mHal.createUser(request, timeoutMs, (status, resp) -> {
1343 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1344 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1345 Log.d(TAG, "createUserResponse: status="
1346 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1347 }
1348 UserInfo user = null; // user returned in the result
1349 if (status != HalCallback.STATUS_OK) {
1350 Log.w(TAG, "invalid callback status ("
1351 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1352 + resp);
1353 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1354 resultStatus, resp.errorMessage);
Felipe Leme6b34fc32020-10-26 15:49:17 -07001355 removeCreatedUser(newUser, "HAL call failed with "
felipealdfdf8512020-06-01 09:35:45 -07001356 + UserHalHelper.halCallbackStatusToString(status));
1357 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1358 return;
1359 }
1360
1361 switch (resp.status) {
1362 case CreateUserStatus.SUCCESS:
1363 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1364 user = newUser;
1365 break;
1366 case CreateUserStatus.FAILURE:
1367 // HAL failed to switch user
1368 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1369 break;
1370 default:
1371 // Shouldn't happen because UserHalService validates the status
1372 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1373 }
1374 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1375 resultStatus, resp.errorMessage);
1376 if (user == null) {
Felipe Leme6b34fc32020-10-26 15:49:17 -07001377 removeCreatedUser(newUser, "HAL returned "
felipealdfdf8512020-06-01 09:35:45 -07001378 + UserCreationResult.statusToString(resultStatus));
1379 }
1380 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1381 });
1382 } catch (Exception e) {
1383 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
Felipe Leme6b34fc32020-10-26 15:49:17 -07001384 removeCreatedUser(newUser, "mHal.createUser() failed");
felipealdfdf8512020-06-01 09:35:45 -07001385 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1386 }
1387 }
1388
Felipe Leme6b34fc32020-10-26 15:49:17 -07001389 private void removeCreatedUser(@NonNull UserInfo user, @NonNull String reason) {
1390 int userId = user.id;
1391 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, userId, reason);
1392
1393 synchronized (mLockUser) {
1394 mFailedToCreateUserIds.put(userId, true);
1395 }
1396
felipealdfdf8512020-06-01 09:35:45 -07001397 try {
Felipe Leme6b34fc32020-10-26 15:49:17 -07001398 if (!mUserManager.removeUser(userId)) {
felipealdfdf8512020-06-01 09:35:45 -07001399 Log.w(TAG, "Failed to remove user " + user.toFullString());
1400 }
1401 } catch (Exception e) {
1402 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1403 }
1404 }
1405
1406 @Override
felipeal159a2a42020-05-08 10:32:11 -07001407 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001408 if (!isUserHalUserAssociationSupported()) {
1409 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1410 }
1411
felipeal5e3ede42020-04-23 18:04:07 -07001412 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
Felipe Leme17799202020-09-03 12:55:53 -07001413 checkManageOrCreateUsersPermission("getUserIdentificationAssociation");
felipeal5e3ede42020-04-23 18:04:07 -07001414
1415 int uid = getCallingUid();
1416 int userId = UserHandle.getUserId(uid);
1417 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1418
1419 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1420 request.userInfo.userId = userId;
1421 request.userInfo.flags = getHalUserInfoFlags(userId);
1422
1423 request.numberAssociationTypes = types.length;
1424 for (int i = 0; i < types.length; i++) {
1425 request.associationTypes.add(types[i]);
1426 }
1427
1428 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1429 if (halResponse == null) {
1430 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1431 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001432 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001433 }
1434
1435 int[] values = new int[halResponse.associations.size()];
1436 for (int i = 0; i < values.length; i++) {
1437 values[i] = halResponse.associations.get(i).value;
1438 }
1439 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1440
felipeal159a2a42020-05-08 10:32:11 -07001441 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1442 }
1443
1444 @Override
1445 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1446 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001447 if (!isUserHalUserAssociationSupported()) {
1448 result.complete(
1449 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1450 return;
1451 }
1452
felipeal159a2a42020-05-08 10:32:11 -07001453 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1454 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1455 if (types.length != values.length) {
1456 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1457 + Arrays.toString(values) + ") should have the same length");
1458 }
Felipe Leme17799202020-09-03 12:55:53 -07001459 checkManageOrCreateUsersPermission("setUserIdentificationAssociation");
felipeal159a2a42020-05-08 10:32:11 -07001460
1461 int uid = getCallingUid();
1462 int userId = UserHandle.getUserId(uid);
1463 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1464
1465 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1466 request.userInfo.userId = userId;
1467 request.userInfo.flags = getHalUserInfoFlags(userId);
1468
1469 request.numberAssociations = types.length;
1470 for (int i = 0; i < types.length; i++) {
1471 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1472 association.type = types[i];
1473 association.value = values[i];
1474 request.associations.add(association);
1475 }
1476
1477 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1478 if (status != HalCallback.STATUS_OK) {
1479 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1480 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1481 + resp);
1482 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1483 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1484 result.complete(UserIdentificationAssociationResponse.forFailure());
1485 return;
1486 }
1487 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1488 resp.errorMessage);
1489 result.complete(
1490 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1491 return;
1492 }
1493 int respSize = resp.associations.size();
1494 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1495 resp.errorMessage);
1496
1497 int[] responseTypes = new int[respSize];
1498 for (int i = 0; i < respSize; i++) {
1499 responseTypes[i] = resp.associations.get(i).value;
1500 }
1501 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1502 .forSuccess(responseTypes, resp.errorMessage);
1503 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1504 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1505 + ", converted=" + response);
1506 }
1507 result.complete(response);
1508 });
felipeal5e3ede42020-04-23 18:04:07 -07001509 }
1510
1511 /**
1512 * Gets the User HAL flags for the given user.
1513 *
1514 * @throws IllegalArgumentException if the user does not exist.
1515 */
1516 private int getHalUserInfoFlags(@UserIdInt int userId) {
1517 UserInfo user = mUserManager.getUserInfo(userId);
1518 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1519 return UserHalHelper.convertFlags(user);
1520 }
1521
Mayank Garg0e239142020-04-14 19:16:31 -07001522 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1523 @Nullable Bundle resultData) {
1524 try {
1525 receiver.send(resultCode, resultData);
1526 } catch (RemoteException e) {
1527 // ignore
1528 Log.w(TAG_USER, "error while sending results", e);
1529 }
1530 }
1531
felipealdfdf8512020-06-01 09:35:45 -07001532 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
Felipe Leme5d5ab142020-10-27 13:49:10 -07001533 @UserSwitchResult.Status int userSwitchStatus) {
1534 sendUserSwitchResult(receiver, HalCallback.STATUS_INVALID, userSwitchStatus,
1535 /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001536 }
1537
felipealdfdf8512020-06-01 09:35:45 -07001538 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
Felipe Leme5d5ab142020-10-27 13:49:10 -07001539 @HalCallback.HalCallbackStatus int halCallbackStatus,
1540 @UserSwitchResult.Status int userSwitchStatus, @Nullable String errorMessage) {
1541 if (errorMessage != null) {
1542 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, halCallbackStatus,
1543 userSwitchStatus, errorMessage);
1544 } else {
1545 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, halCallbackStatus,
1546 userSwitchStatus);
1547 }
1548 receiver.complete(new UserSwitchResult(userSwitchStatus, errorMessage));
felipeale5bf0322020-04-16 15:10:57 -07001549 }
1550
felipealdfdf8512020-06-01 09:35:45 -07001551 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1552 @UserCreationResult.Status int status) {
1553 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1554 }
1555
1556 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1557 @UserCreationResult.Status int status, @NonNull UserInfo user,
1558 @Nullable String errorMessage) {
1559 if (TextUtils.isEmpty(errorMessage)) {
1560 errorMessage = null;
1561 }
1562 receiver.complete(new UserCreationResult(status, user, errorMessage));
1563 }
1564
Mayank Garg6307fe42020-04-15 23:09:03 -07001565 /**
1566 * Calls activity manager for user switch.
1567 *
1568 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1569 *
1570 * @param requestId for the user switch request
1571 * @param targetUserId of the target user
1572 *
1573 * @hide
1574 */
1575 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1576 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1577 targetUserId);
1578 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1579
1580 try {
1581 boolean result = mAm.switchUser(targetUserId);
1582 if (result) {
1583 updateUserSwitchInProcess(requestId, targetUserId);
1584 } else {
1585 postSwitchHalResponse(requestId, targetUserId);
1586 }
1587 } catch (RemoteException e) {
1588 // ignore
1589 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1590 }
1591 }
1592
1593 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1594 synchronized (mLockUser) {
1595 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1596 // Some other user switch is in process.
1597 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1598 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1599 + " is in process. Abandoning it as a new user switch is requested"
1600 + " for the target user: " + targetUserId);
1601 }
1602 }
1603 mUserIdForUserSwitchInProcess = targetUserId;
1604 mRequestIdForUserSwitchInProcess = requestId;
1605 }
1606 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001607
Mayank Garg7a114c82020-04-08 21:25:06 -07001608 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001609 if (!isUserHalSupported()) return;
1610
felipealdfdf8512020-06-01 09:35:45 -07001611 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001612 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1613 targetUserId, usersInfo.currentUser.userId);
1614 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1615 request.requestId = requestId;
1616 mHal.postSwitchResponse(request);
1617 }
1618
1619 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1620 @NonNull UsersInfo usersInfo) {
1621 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001622 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1623 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1624 halTargetUser.userId = targetUser.id;
1625 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001626 SwitchUserRequest request = new SwitchUserRequest();
1627 request.targetUser = halTargetUser;
1628 request.usersInfo = usersInfo;
1629 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001630 }
1631
Mayank Garg59f22192020-03-27 00:51:45 -07001632 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001633 * Checks if the User HAL is supported.
1634 */
1635 public boolean isUserHalSupported() {
1636 return mHal.isSupported();
1637 }
1638
Mayank Garg587f1942020-05-06 01:41:34 -07001639 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001640 * Checks if the User HAL user association is supported.
1641 */
1642 @Override
1643 public boolean isUserHalUserAssociationSupported() {
1644 return mHal.isUserAssociationSupported();
1645 }
1646
1647 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001648 * Sets a callback which is invoked before user switch.
1649 *
1650 * <p>
1651 * This method should only be called by the Car System UI. The purpose of this call is to notify
1652 * Car System UI to show the user switch UI before the user switch.
1653 */
1654 @Override
1655 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001656 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001657
1658 // Confirm that caller is system UI.
1659 String systemUiPackageName = getSystemUiPackageName();
1660 if (systemUiPackageName == null) {
1661 throw new IllegalStateException("System UI package not found.");
1662 }
1663
1664 try {
1665 int systemUiUid = mContext
1666 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1667 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1668 int callerUid = Binder.getCallingUid();
1669 if (systemUiUid != callerUid) {
1670 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1671 + " is allowed to make this call");
1672 }
1673 } catch (NameNotFoundException e) {
1674 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1675 }
1676
Mayank Garg587f1942020-05-06 01:41:34 -07001677 mUserSwitchUiReceiver = receiver;
1678 }
1679
Mayank Garga480dd92020-05-14 03:14:57 -07001680 // TODO(157082995): This information can be taken from
1681 // PackageManageInternalImpl.getSystemUiServiceComponent
1682 @Nullable
1683 private String getSystemUiPackageName() {
1684 try {
1685 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1686 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1687 return componentName.getPackageName();
1688 } catch (RuntimeException e) {
1689 Log.w(TAG_USER, "error while getting system UI package name.", e);
1690 return null;
1691 }
1692 }
1693
Keun young Park13a7a822019-04-04 15:53:08 -07001694 private void updateDefaultUserRestriction() {
1695 // We want to set restrictions on system and guest users only once. These are persisted
1696 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1697 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001698 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1699 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001700 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001701 // Only apply the system user restrictions if the system user is headless.
1702 if (UserManager.isHeadlessSystemUserMode()) {
1703 setSystemUserRestrictions();
1704 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001705 Settings.Global.putInt(mContext.getContentResolver(),
1706 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001707 }
1708
Eric Jeong1545f3b2019-09-16 13:56:52 -07001709 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001710 return !mUserManager.getUserInfo(userId).isEphemeral();
1711 }
1712
Antonio Kantekc8114752020-03-05 21:37:39 -08001713 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001714 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1715 */
1716 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1717 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001718 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001719 }
1720
1721 /**
1722 * Removes previously added {@link UserLifecycleListener}.
1723 */
1724 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1725 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001726 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001727 }
1728
Eric Jeongc91f9452019-08-30 15:04:21 -07001729 /** Adds callback to listen to passenger activity events. */
1730 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001731 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001732 mPassengerCallbacks.add(callback);
1733 }
1734
1735 /** Removes previously added callback to listen passenger events. */
1736 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001737 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001738 mPassengerCallbacks.remove(callback);
1739 }
1740
1741 /** Sets the implementation of ZoneUserBindingHelper. */
1742 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1743 synchronized (mLockHelper) {
1744 mZoneUserBindingHelper = helper;
1745 }
1746 }
1747
felipeal98900c82020-04-09 09:05:02 -07001748 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001749 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001750 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001751 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001752 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001753 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1754 updateDefaultUserRestriction();
1755 tasks = new ArrayList<>(mUser0UnlockTasks);
1756 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001757 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001758 }
1759 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001760 Integer user = userId;
1761 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001762 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001763 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001764 mBackgroundUsersToRestart.remove(user);
1765 mBackgroundUsersToRestart.add(0, user);
1766 }
1767 // -1 for user 0
1768 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001769 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001770 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001771 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001772 + ", dropping least recently user from restart list:" + userToDrop);
1773 // Drop the least recently used user.
1774 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1775 }
1776 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001777 }
1778 }
1779 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001780 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001781 for (Runnable r : tasks) {
1782 r.run();
1783 }
1784 }
1785 }
1786
1787 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001788 * Starts all background users that were active in system.
1789 *
Keun young Parkfb656372019-03-12 18:37:55 -07001790 * @return list of background users started successfully.
1791 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001792 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001793 public ArrayList<Integer> startAllBackgroundUsers() {
1794 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001795 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001796 users = new ArrayList<>(mBackgroundUsersToRestart);
1797 mBackgroundUsersRestartedHere.clear();
1798 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001799 }
1800 ArrayList<Integer> startedUsers = new ArrayList<>();
1801 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001802 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001803 continue;
1804 }
1805 try {
1806 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001807 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1808 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001809 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001810 } else if (mAm.unlockUser(user, null, null, null)) {
1811 startedUsers.add(user);
1812 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001813 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001814 if (mUserManager.isUserRunning(user)) {
1815 // add to started list so that it can be stopped later.
1816 startedUsers.add(user);
1817 }
Keun young Parkfb656372019-03-12 18:37:55 -07001818 }
1819 }
1820 } catch (RemoteException e) {
1821 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001822 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001823 }
1824 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001825 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001826 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001827 ArrayList<Integer> usersToRemove = new ArrayList<>();
1828 for (Integer user : mBackgroundUsersToRestart) {
1829 if (!startedUsers.contains(user)) {
1830 usersToRemove.add(user);
1831 }
1832 }
1833 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1834 }
Keun young Parkfb656372019-03-12 18:37:55 -07001835 return startedUsers;
1836 }
1837
1838 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001839 * Stops all background users that were active in system.
1840 *
1841 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001842 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001843 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001844 if (userId == UserHandle.USER_SYSTEM) {
1845 return false;
1846 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001847 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001848 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001849 return false;
1850 }
1851 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001852 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001853 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001854 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001855 Integer user = userId;
1856 mBackgroundUsersRestartedHere.remove(user);
1857 }
1858 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1859 return false;
1860 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001861 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001862 return false;
1863 }
1864 } catch (RemoteException e) {
1865 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001866 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001867 }
1868 return true;
1869 }
1870
1871 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001872 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001873 */
Mayank Gargccad8062020-08-30 15:05:10 -07001874 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType,
felipeale8c5dce2020-04-15 11:27:06 -07001875 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1876 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001877
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001878 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001879 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001880 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001881 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1882 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001883 }
1884
felipeale8c5dce2020-04-15 11:27:06 -07001885 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001886 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001887
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001888 mHandler.post(() -> {
1889 handleNotifyServiceUserLifecycleListeners(event);
1890 handleNotifyAppUserLifecycleListeners(event);
1891 });
felipeale8c5dce2020-04-15 11:27:06 -07001892 }
1893
Mayank Garg7a114c82020-04-08 21:25:06 -07001894 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001895 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001896 || mUserIdForUserSwitchInProcess != userId
1897 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001898 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1899 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1900 }
1901 return;
1902 }
felipealf7368962020-04-16 12:55:19 -07001903 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1904 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001905 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001906 }
1907
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001908 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1909 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001910 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001911 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1912 Log.d(TAG_USER, "No app listener to be notified of " + event);
1913 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001914 return;
1915 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001916 // Must use a different TimingsTraceLog because it's another thread
1917 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1918 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1919 }
felipeal2a84d512020-04-06 18:52:15 -07001920 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001921 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001922 int eventType = event.getEventType();
1923 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001924 for (int i = 0; i < listenersSize; i++) {
1925 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001926
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001927 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1928 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001929 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001930
felipealde1e16d2020-06-03 13:20:48 -07001931 int fromUserId = event.getPreviousUserId();
1932 if (fromUserId != UserHandle.USER_NULL) {
1933 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001934 }
1935
felipeal2a84d512020-04-06 18:52:15 -07001936 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001937 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001938 }
felipealde1e16d2020-06-03 13:20:48 -07001939 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1940 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001941 try {
felipealde1e16d2020-06-03 13:20:48 -07001942 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001943 listener.send(userId, data);
1944 } catch (RemoteException e) {
1945 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1946 } finally {
1947 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001948 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001949 }
1950 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001951 }
1952
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001953 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001954 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1955 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001956 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001957 return;
felipeal2a84d512020-04-06 18:52:15 -07001958 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1959 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1960 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001961 }
felipeal2a84d512020-04-06 18:52:15 -07001962
felipealde1e16d2020-06-03 13:20:48 -07001963 int userId = event.getUserId();
1964 int eventType = event.getEventType();
1965 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001966 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001967 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001968 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1969 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001970 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001971 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001972 listener.onEvent(event);
1973 } catch (RuntimeException e) {
1974 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001975 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001976 } finally {
1977 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001978 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001979 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001980 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001981 }
1982
Mayank Garge5de0f92020-04-23 21:38:38 -07001983 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001984 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001985 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001986 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001987
Mayank Garge5de0f92020-04-23 21:38:38 -07001988 // Switch HAL users if user switch is not requested by CarUserService
1989 notifyHalLegacySwitch(fromUserId, toUserId);
1990
Mayank Garge90a4082020-09-30 12:57:34 -07001991 mInitialUserSetter.setLastActiveUser(toUserId);
felipealbf327652020-06-03 11:33:29 -07001992
Eric Jeongc91f9452019-08-30 15:04:21 -07001993 if (mLastPassengerId != UserHandle.USER_NULL) {
1994 stopPassengerInternal(mLastPassengerId, false);
1995 }
1996 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1997 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001998 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001999 }
felipeal98900c82020-04-09 09:05:02 -07002000 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07002001 }
2002
Mayank Garge5de0f92020-04-23 21:38:38 -07002003 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
2004 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07002005 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
2006 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
2007 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
2008 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
2009 }
2010 return;
2011 }
Mayank Garge5de0f92020-04-23 21:38:38 -07002012 }
2013
Mayank Garg9ed099e2020-06-04 16:05:20 -07002014 if (!isUserHalSupported()) return;
2015
Mayank Garge5de0f92020-04-23 21:38:38 -07002016 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07002017 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07002018 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
2019 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07002020 }
2021
Pavel Maltsev17e81832019-04-04 14:38:41 -07002022 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07002023 * 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 -08002024 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07002025 *
Keun-young Parkd462a912019-02-11 08:53:42 -08002026 * @param r Runnable to run.
2027 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07002028 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00002029 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08002030 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07002031 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08002032 if (mUser0Unlocked) {
2033 runNow = true;
2034 } else {
2035 mUser0UnlockTasks.add(r);
2036 }
2037 }
2038 if (runNow) {
2039 r.run();
2040 }
2041 }
2042
Keun young Parkf3523cd2019-04-08 10:09:17 -07002043 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07002044 @NonNull
2045 ArrayList<Integer> getBackgroundUsersToRestart() {
2046 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07002047 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07002048 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
2049 }
2050 return backgroundUsersToRestart;
2051 }
2052
Ying Zheng1ab32b62018-06-26 12:47:26 -07002053 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07002054 // Disable Location service for system user.
2055 LocationManager locationManager =
2056 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08002057 locationManager.setLocationEnabledForUser(
2058 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07002059 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07002060
2061 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07002062 * Assigns a default icon to a user according to the user's id.
2063 *
2064 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07002065 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07002066 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07002067 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
2068 Bitmap bitmap = UserIcons.convertToBitmap(
2069 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
2070 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07002071 }
2072
Eric Jeong1545f3b2019-09-16 13:56:52 -07002073 private interface UserFilter {
2074 boolean isEligibleUser(UserInfo user);
2075 }
2076
2077 /** Returns all users who are matched by the given filter. */
2078 private List<UserInfo> getUsers(UserFilter filter) {
Colin Cross0df71ea2020-08-27 04:12:26 +00002079 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeong1545f3b2019-09-16 13:56:52 -07002080
2081 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
2082 UserInfo user = iterator.next();
2083 if (!filter.isEligibleUser(user)) {
2084 iterator.remove();
2085 }
2086 }
2087 return users;
2088 }
2089
felipeal2d0483c2019-11-02 14:07:22 -07002090 private static void checkManageUsersOrDumpPermission(String message) {
Felipe Leme55236722020-10-16 16:54:32 -07002091 checkHasAtLeastOnePermissionGranted(message,
felipeal2d0483c2019-11-02 14:07:22 -07002092 android.Manifest.permission.MANAGE_USERS,
2093 android.Manifest.permission.DUMP);
2094 }
2095
Felipe Leme5528ff72020-02-10 19:05:14 -08002096 private void checkInteractAcrossUsersPermission(String message) {
Felipe Leme55236722020-10-16 16:54:32 -07002097 checkHasAtLeastOnePermissionGranted(message,
2098 android.Manifest.permission.INTERACT_ACROSS_USERS,
Felipe Leme5528ff72020-02-10 19:05:14 -08002099 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
2100 }
2101
Eric Jeongc91f9452019-08-30 15:04:21 -07002102 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
Colin Cross0df71ea2020-08-27 04:12:26 +00002103 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeongc91f9452019-08-30 15:04:21 -07002104 // Count all users that are managed profiles of the given user.
2105 int managedProfilesCount = 0;
2106 for (UserInfo user : users) {
2107 if (user.isManagedProfile() && user.profileGroupId == userId) {
2108 managedProfilesCount++;
2109 }
2110 }
2111 return managedProfilesCount;
2112 }
2113
2114 /**
2115 * Starts the first passenger of the given driver and assigns the passenger to the front
2116 * passenger zone.
2117 *
2118 * @param driverId User id of the driver.
2119 * @return whether it succeeds.
2120 */
2121 private boolean startFirstPassenger(@UserIdInt int driverId) {
2122 int zoneId = getAvailablePassengerZone();
2123 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
2124 Log.w(TAG_USER, "passenger occupant zone is not found");
2125 return false;
2126 }
2127 List<UserInfo> passengers = getPassengers(driverId);
2128 if (passengers.size() < 1) {
2129 Log.w(TAG_USER, "passenger is not found");
2130 return false;
2131 }
2132 // Only one passenger is supported. If there are two or more passengers, the first passenger
2133 // is chosen.
2134 int passengerId = passengers.get(0).id;
2135 if (!startPassenger(passengerId, zoneId)) {
2136 Log.w(TAG_USER, "cannot start passenger " + passengerId);
2137 return false;
2138 }
2139 return true;
2140 }
2141
2142 private int getAvailablePassengerZone() {
2143 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
2144 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
2145 for (int occupantType : occupantTypes) {
2146 int zoneId = getZoneId(occupantType);
2147 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
2148 return zoneId;
2149 }
2150 }
2151 return OccupantZoneInfo.INVALID_ZONE_ID;
2152 }
2153
2154 /**
2155 * Creates a new passenger user when there is no passenger user.
2156 */
2157 private void setupPassengerUser() {
2158 int currentUser = ActivityManager.getCurrentUser();
2159 int profileCount = getNumberOfManagedProfiles(currentUser);
2160 if (profileCount > 0) {
2161 Log.w(TAG_USER, "max profile of user" + currentUser
2162 + " is exceeded: current profile count is " + profileCount);
2163 return;
2164 }
2165 // TODO(b/140311342): Use resource string for the default passenger name.
2166 UserInfo passenger = createPassenger("Passenger", currentUser);
2167 if (passenger == null) {
2168 // Couldn't create user, most likely because there are too many.
2169 Log.w(TAG_USER, "cannot create a passenger user");
2170 return;
2171 }
2172 }
2173
2174 @NonNull
2175 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
2176 ZoneUserBindingHelper helper = null;
2177 synchronized (mLockHelper) {
2178 if (mZoneUserBindingHelper == null) {
2179 Log.w(TAG_USER, "implementation is not delegated");
2180 return new ArrayList<OccupantZoneInfo>();
2181 }
2182 helper = mZoneUserBindingHelper;
2183 }
2184 return helper.getOccupantZones(occupantType);
2185 }
2186
2187 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
2188 ZoneUserBindingHelper helper = null;
2189 synchronized (mLockHelper) {
2190 if (mZoneUserBindingHelper == null) {
2191 Log.w(TAG_USER, "implementation is not delegated");
2192 return false;
2193 }
2194 helper = mZoneUserBindingHelper;
2195 }
2196 return helper.assignUserToOccupantZone(userId, zoneId);
2197 }
2198
2199 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
2200 ZoneUserBindingHelper helper = null;
2201 synchronized (mLockHelper) {
2202 if (mZoneUserBindingHelper == null) {
2203 Log.w(TAG_USER, "implementation is not delegated");
2204 return false;
2205 }
2206 helper = mZoneUserBindingHelper;
2207 }
2208 return helper.unassignUserFromOccupantZone(userId);
2209 }
2210
2211 private boolean isPassengerDisplayAvailable() {
2212 ZoneUserBindingHelper helper = null;
2213 synchronized (mLockHelper) {
2214 if (mZoneUserBindingHelper == null) {
2215 Log.w(TAG_USER, "implementation is not delegated");
2216 return false;
2217 }
2218 helper = mZoneUserBindingHelper;
2219 }
2220 return helper.isPassengerDisplayAvailable();
2221 }
2222
2223 /**
2224 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
2225 * zone is returned.
2226 *
2227 * @param occupantType The type of an occupant.
2228 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
2229 * if not found.
2230 */
2231 private int getZoneId(@OccupantTypeEnum int occupantType) {
2232 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
2233 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
2234 }
Mayank Garg9732d602020-08-09 21:02:40 -07002235
2236 /**
2237 * Manages the required number of pre-created users.
2238 */
2239 public void preCreateUsers() {
2240 mUserPreCreator.managePreCreatedUsers();
2241 }
Felipe Leme17799202020-09-03 12:55:53 -07002242
2243 // TODO(b/167698977): members below were copied from UserManagerService; it would be better to
2244 // move them to some internal android.os class instead.
2245
2246 private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
2247 UserInfo.FLAG_MANAGED_PROFILE
2248 | UserInfo.FLAG_PROFILE
2249 | UserInfo.FLAG_EPHEMERAL
2250 | UserInfo.FLAG_RESTRICTED
2251 | UserInfo.FLAG_GUEST
2252 | UserInfo.FLAG_DEMO
2253 | UserInfo.FLAG_FULL;
2254
2255 private static void checkManageUsersPermission(String message) {
2256 if (!hasManageUsersPermission()) {
2257 throw new SecurityException("You need " + MANAGE_USERS + " permission to: " + message);
2258 }
2259 }
2260
2261 private static void checkManageOrCreateUsersPermission(String message) {
2262 if (!hasManageOrCreateUsersPermission()) {
2263 throw new SecurityException(
2264 "You either need " + MANAGE_USERS + " or " + CREATE_USERS + " permission to: "
2265 + message);
2266 }
2267 }
2268
2269 private static void checkManageOrCreateUsersPermission(int creationFlags) {
2270 if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
2271 if (!hasManageOrCreateUsersPermission()) {
2272 throw new SecurityException("You either need " + MANAGE_USERS + " or "
2273 + CREATE_USERS + "permission to create a user with flags "
2274 + creationFlags);
2275 }
2276 } else if (!hasManageUsersPermission()) {
2277 throw new SecurityException("You need " + MANAGE_USERS + " permission to create a user"
2278 + " with flags " + creationFlags);
2279 }
2280 }
2281
2282 private static boolean hasManageUsersPermission() {
2283 final int callingUid = Binder.getCallingUid();
2284 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
2285 || callingUid == Process.ROOT_UID
2286 || hasPermissionGranted(MANAGE_USERS, callingUid);
2287 }
2288
2289 private static boolean hasManageUsersOrPermission(String alternativePermission) {
2290 final int callingUid = Binder.getCallingUid();
2291 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
2292 || callingUid == Process.ROOT_UID
2293 || hasPermissionGranted(MANAGE_USERS, callingUid)
2294 || hasPermissionGranted(alternativePermission, callingUid);
2295 }
2296
2297 private static boolean hasManageOrCreateUsersPermission() {
2298 return hasManageUsersOrPermission(CREATE_USERS);
2299 }
2300
2301 private static boolean hasPermissionGranted(String permission, int uid) {
2302 return ActivityManager.checkComponentPermission(permission, uid, /* owningUid= */ -1,
2303 /* exported= */ true) == PackageManager.PERMISSION_GRANTED;
2304 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002305}