blob: ef372fcfc23c0288a7b8e7cebf3cfbac2a3cdec8 [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.user;
18
Eric Jeong1545f3b2019-09-16 13:56:52 -070019import static com.android.car.CarLog.TAG_USER;
20
21import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070022import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070024import android.app.ActivityManager;
Louis Chang3bf2f202020-08-18 13:04:28 +080025import android.app.ActivityTaskManager.RootTaskInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070026import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070027import android.car.CarOccupantZoneManager;
28import android.car.CarOccupantZoneManager.OccupantTypeEnum;
29import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070030import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070031import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080032import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080033import android.car.user.CarUserManager.UserLifecycleEvent;
felipeale8c5dce2020-04-15 11:27:06 -070034import android.car.user.CarUserManager.UserLifecycleEventType;
Antonio Kantekc8114752020-03-05 21:37:39 -080035import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070036import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070037import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070038import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070039import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070040import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070041import android.car.userlib.HalCallback;
42import android.car.userlib.UserHalHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070043import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070044import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.pm.PackageManager;
46import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070047import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070048import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070049import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070050import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070051import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
52import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070053import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080054import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070055import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070056import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070057import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070058import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
59import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080062import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070063import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070064import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080065import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070066import android.os.Handler;
67import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070068import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080069import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070070import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070071import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070072import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070073import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070074import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070075import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070076import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080077import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080078import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070079
80import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070081import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070082import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080083import com.android.car.hal.UserHalService;
Mayank Garg94f3eb92020-08-12 12:38:58 -070084import com.android.car.internal.EventLogTags;
85import com.android.car.internal.UserHelperLite;
Mayank Garg4bdfbf72020-08-06 13:27:43 -070086import com.android.car.power.CarPowerManagementService;
Mayank Garg665c20b2020-08-07 16:19:28 -070087import com.android.car.user.InitialUserSetter.InitialUserInfo;
Keun-young Parkd462a912019-02-11 08:53:42 -080088import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070089import com.android.internal.annotations.VisibleForTesting;
felipeale5bf0322020-04-16 15:10:57 -070090import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080091import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070092import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070093import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070094import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070095import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070096
97import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080098import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070099import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700100import java.util.Iterator;
101import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000102import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700103import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700104import java.util.concurrent.CountDownLatch;
105import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700106
107/**
108 * User service for cars. Manages users at boot time. Including:
109 *
110 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700111 * <li> Creates a user used as driver.
112 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700113 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700114 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700115 * <ol/>
116 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700117public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800118
felipealf7368962020-04-16 12:55:19 -0700119 private static final String TAG = TAG_USER;
120
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800121 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700122 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800123 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700124 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800125 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700126 public static final String BUNDLE_USER_NAME = "user.name";
felipeala68ecef2020-05-19 12:46:08 -0700127 /**
128 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
129 */
Mayank Garg8f932822020-09-17 16:09:12 -0700130 public static final String BUNDLE_USER_LOCALES = "user.locales";
felipeala68ecef2020-05-19 12:46:08 -0700131 /**
132 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
133 */
Mayank Garg8f932822020-09-17 16:09:12 -0700134 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800135
Mayank Garg9ed099e2020-06-04 16:05:20 -0700136 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
137
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700138 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700139 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700140 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700141 private final UserManager mUserManager;
142 private final int mMaxRunningUsers;
Mayank Garg70732a82020-08-05 20:17:47 -0700143 private final InitialUserSetter mInitialUserSetter;
Eric Jeongc91f9452019-08-30 15:04:21 -0700144 private final boolean mEnablePassengerSupport;
Mayank Garg9732d602020-08-09 21:02:40 -0700145 private final UserPreCreator mUserPreCreator;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700146
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 private final Object mLockUser = new Object();
148 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800149 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700150 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800151 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700152 // Only one passenger is supported.
153 @GuardedBy("mLockUser")
154 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700155 /**
156 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800157 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700158 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700159 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700160 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
161 /**
162 * Keep the list of background users started here. This is wholly for debugging purpose.
163 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700164 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700165 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
166
Felipe Leme58412202020-01-09 13:45:33 -0800167 private final UserHalService mHal;
168
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700169 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700170 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
171 getClass().getSimpleName());
172 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700173
Felipe Leme5528ff72020-02-10 19:05:14 -0800174 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800175 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700176 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800177 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700178 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800179
180 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800181 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700182 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800183 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700184 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800185
Mayank Garg7a114c82020-04-08 21:25:06 -0700186 /**
187 * User Id for the user switch in process, if any.
188 */
189 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700190 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700191 /**
192 * Request Id for the user switch in process, if any.
193 */
194 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700195 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700196 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
197
Eric Jeongc91f9452019-08-30 15:04:21 -0700198 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
199 new CopyOnWriteArrayList<>();
200
Mayank Garg7e1450b2020-08-07 18:15:15 -0700201 // TODO(b/163566866): Use mSwitchGuestUserBeforeSleep for new create guest request
202 private final boolean mSwitchGuestUserBeforeSleep;
203
felipeal61ce3732020-04-03 11:01:00 -0700204 @Nullable
205 @GuardedBy("mLockUser")
206 private UserInfo mInitialUser;
207
Mayank Garg587f1942020-05-06 01:41:34 -0700208 private IResultReceiver mUserSwitchUiReceiver;
209
Eric Jeongc91f9452019-08-30 15:04:21 -0700210 /** Interface for callbaks related to passenger activities. */
211 public interface PassengerCallback {
212 /** Called when passenger is started at a certain zone. */
213 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
214 /** Called when passenger is stopped. */
215 void onPassengerStopped(@UserIdInt int passengerId);
216 }
217
218 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
219 public interface ZoneUserBindingHelper {
220 /** Gets occupant zones corresponding to the occupant type. */
221 @NonNull
222 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
223 /** Assigns the user to the occupant zone. */
224 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
225 /** Makes the occupant zone unoccupied. */
226 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
227 /** Returns whether there is a passenger display. */
228 boolean isPassengerDisplayAvailable();
229 }
230
231 private final Object mLockHelper = new Object();
232 @GuardedBy("mLockHelper")
233 private ZoneUserBindingHelper mZoneUserBindingHelper;
234
Felipe Leme58412202020-01-09 13:45:33 -0800235 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700236 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
237 @NonNull IActivityManager am, int maxRunningUsers) {
238 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
Mayank Garg1bb1c382020-09-03 17:11:11 -0700239 /* initialUserSetter= */ null, /* userPreCreator= */ null);
Mayank Garg71661ea2020-04-29 01:25:03 -0700240 }
241
242 @VisibleForTesting
243 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
244 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
Mayank Gargccad8062020-08-30 15:05:10 -0700245 @NonNull IActivityManager am, int maxRunningUsers,
Mayank Garg1bb1c382020-09-03 17:11:11 -0700246 @Nullable InitialUserSetter initialUserSetter,
247 @Nullable UserPreCreator userPreCreator) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
249 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700250 }
251 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800252 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700253 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700254 mAm = am;
255 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700256 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700257 mLastPassengerId = UserHandle.USER_NULL;
Mayank Garg1bb1c382020-09-03 17:11:11 -0700258 mInitialUserSetter =
259 initialUserSetter == null ? new InitialUserSetter(context, (u) -> setInitialUser(u))
260 : initialUserSetter;
261 mUserPreCreator =
262 userPreCreator == null ? new UserPreCreator(mUserManager) : userPreCreator;
Mayank Garg7e1450b2020-08-07 18:15:15 -0700263 Resources resources = context.getResources();
264 mEnablePassengerSupport = resources.getBoolean(R.bool.enablePassengerSupport);
265 mSwitchGuestUserBeforeSleep = resources.getBoolean(
266 R.bool.config_switchGuestUserBeforeGoingSleep);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700267 }
268
269 @Override
270 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700271 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
272 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700273 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700274 }
275
276 @Override
277 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700278 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
279 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700280 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700281 }
282
283 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700284 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700285 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700286 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800287 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700288 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700289 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700290 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700291 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700292 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
293 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700294 }
295 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
296 List<UserInfo> allDrivers = getAllDrivers();
297 int driversSize = allDrivers.size();
298 writer.println("NumberOfDrivers: " + driversSize);
299 for (int i = 0; i < driversSize; i++) {
300 int driverId = allDrivers.get(i).id;
301 writer.print(indent + "#" + i + ": id=" + driverId);
302 List<UserInfo> passengers = getPassengers(driverId);
303 int passengersSize = passengers.size();
304 writer.print(" NumberPassengers: " + passengersSize);
305 if (passengersSize > 0) {
306 writer.print(" [");
307 for (int j = 0; j < passengersSize; j++) {
308 writer.print(passengers.get(j).id);
309 if (j < passengersSize - 1) {
310 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700311 }
felipeal2d0483c2019-11-02 14:07:22 -0700312 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700313 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700314 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700315 writer.println();
316 }
317 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
318 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
319 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700320
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700321 writer.println("Relevant overlayable properties");
322 Resources res = mContext.getResources();
323 writer.printf("%sowner_name=%s\n", indent,
324 res.getString(com.android.internal.R.string.owner_name));
325 writer.printf("%sdefault_guest_name=%s\n", indent,
326 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700327 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700328 writer.printf("Request Id for the user switch in process=%d\n ",
329 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700330 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700331
felipealbf327652020-06-03 11:33:29 -0700332 writer.println("Relevant Global settings");
333 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
334 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
335
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700336 mInitialUserSetter.dump(writer);
felipeale8c5dce2020-04-15 11:27:06 -0700337 }
338
felipealbf327652020-06-03 11:33:29 -0700339 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
340 String value = Settings.Global.getString(mContext.getContentResolver(), property);
341 writer.printf("%s%s=%s\n", indent, property, value);
342 }
343
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700344 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
345 CountDownLatch latch = new CountDownLatch(1);
346 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700347 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700348 handleDumpAppLifecycleListeners(writer, indent);
349 latch.countDown();
350 });
351 int timeout = 5;
352 try {
353 if (!latch.await(timeout, TimeUnit.SECONDS)) {
354 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
355 timeout);
356 }
357 } catch (InterruptedException e) {
358 Thread.currentThread().interrupt();
359 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
360 }
361 }
362
felipealde1e16d2020-06-03 13:20:48 -0700363 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700364 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700365 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700366 return;
367 }
felipealde1e16d2020-06-03 13:20:48 -0700368 int size = mUserLifecycleListeners.size();
369 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
370 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700371 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700372 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700373 }
374 }
375
376 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700377 int size = mAppLifecycleListeners.size();
378 if (size == 0) {
379 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700380 return;
381 }
felipealde1e16d2020-06-03 13:20:48 -0700382 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
383 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700384 int uid = mAppLifecycleListeners.keyAt(i);
385 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700386 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800387 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700388 }
389
390 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700391 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700392 */
393 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700394 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700395 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000396 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700397
398 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
399 @Override
400 protected void onCompleted(UserCreationResult result, Throwable err) {
401 if (result == null) {
402 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
403 } else {
404 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
405 assignDefaultIcon(result.getUser());
406 }
407 }
408 super.onCompleted(result, err);
409 };
410 };
411 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700412 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700413 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
414 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
415 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
416 return future;
417 }
418 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700419 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700420 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
421 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700422 }
423
424 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700425 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700426 */
427 @Override
428 @Nullable
429 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
430 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000431 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700432 UserInfo driver = mUserManager.getUserInfo(driverId);
433 if (driver == null) {
434 Log.w(TAG_USER, "the driver is invalid");
435 return null;
436 }
437 if (driver.isGuest()) {
438 Log.w(TAG_USER, "a guest driver cannot create a passenger");
439 return null;
440 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700441 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700442 UserInfo user = mUserManager.createProfileForUser(name,
443 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700444 if (user == null) {
445 // Couldn't create user, most likely because there are too many.
446 Log.w(TAG_USER, "can't create a profile for user" + driverId);
447 return null;
448 }
449 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700450 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700451 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700452 return user;
453 }
454
455 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700456 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700457 */
458 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700459 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700460 checkManageUsersPermission("switchDriver");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700461 if (UserHelperLite.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700462 // System user doesn't associate with real person, can not be switched to.
463 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700464 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700465 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700466 }
467 int userSwitchable = mUserManager.getUserSwitchability();
468 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
469 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700470 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700471 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700472 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700473 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 }
475
476 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800477 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
478 *
479 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700480 */
481 @Override
482 @NonNull
483 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700484 checkManageUsersOrDumpPermission("getAllDrivers");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700485 return getUsers((user) -> !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700486 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700487 }
488
489 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800490 * Returns all passengers under the given driver.
491 *
492 * @param driverId User id of a driver.
493 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700494 */
495 @Override
496 @NonNull
497 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700498 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700499 return getUsers((user) -> {
Mayank Garg94f3eb92020-08-12 12:38:58 -0700500 return !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Eric Jeong40f8fa32020-05-12 12:23:33 -0700501 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700502 });
503 }
504
505 /**
506 * @see CarUserManager.startPassenger
507 */
508 @Override
509 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
510 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700511 synchronized (mLockUser) {
512 try {
513 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
514 Log.w(TAG_USER, "could not start passenger");
515 return false;
516 }
517 } catch (RemoteException e) {
518 // ignore
519 Log.w(TAG_USER, "error while starting passenger", e);
520 return false;
521 }
522 if (!assignUserToOccupantZone(passengerId, zoneId)) {
523 Log.w(TAG_USER, "could not assign passenger to zone");
524 return false;
525 }
526 mLastPassengerId = passengerId;
527 }
528 for (PassengerCallback callback : mPassengerCallbacks) {
529 callback.onPassengerStarted(passengerId, zoneId);
530 }
531 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700532 }
533
534 /**
535 * @see CarUserManager.stopPassenger
536 */
537 @Override
538 public boolean stopPassenger(@UserIdInt int passengerId) {
539 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700540 return stopPassengerInternal(passengerId, true);
541 }
542
543 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
544 synchronized (mLockUser) {
545 UserInfo passenger = mUserManager.getUserInfo(passengerId);
546 if (passenger == null) {
547 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
548 return false;
549 }
550 if (mLastPassengerId != passengerId) {
551 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
552 return true;
553 }
554 if (checkCurrentDriver) {
555 int currentUser = ActivityManager.getCurrentUser();
556 if (passenger.profileGroupId != currentUser) {
557 Log.w(TAG_USER, "passenger " + passengerId
558 + " is not a profile of the current user");
559 return false;
560 }
561 }
562 // Passenger is a profile, so cannot be stopped through activity manager.
563 // Instead, activities started by the passenger are stopped and the passenger is
564 // unassigned from the zone.
565 stopAllTasks(passengerId);
566 if (!unassignUserFromOccupantZone(passengerId)) {
567 Log.w(TAG_USER, "could not unassign user from occupant zone");
568 return false;
569 }
570 mLastPassengerId = UserHandle.USER_NULL;
571 }
572 for (PassengerCallback callback : mPassengerCallbacks) {
573 callback.onPassengerStopped(passengerId);
574 }
575 return true;
576 }
577
578 private void stopAllTasks(@UserIdInt int userId) {
579 try {
Louis Chang3bf2f202020-08-18 13:04:28 +0800580 for (RootTaskInfo info : mAm.getAllRootTaskInfos()) {
581 for (int i = 0; i < info.childTaskIds.length; i++) {
582 if (info.childTaskUserIds[i] == userId) {
583 int taskId = info.childTaskIds[i];
Eric Jeongc91f9452019-08-30 15:04:21 -0700584 if (!mAm.removeTask(taskId)) {
585 Log.w(TAG_USER, "could not remove task " + taskId);
586 }
587 }
588 }
589 }
590 } catch (RemoteException e) {
591 Log.e(TAG_USER, "could not get stack info", e);
592 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700593 }
594
Felipe Leme5528ff72020-02-10 19:05:14 -0800595 @Override
596 public void setLifecycleListenerForUid(IResultReceiver listener) {
597 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700598 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800599 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
600
601 try {
602 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
603 } catch (RemoteException e) {
604 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
605 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700606 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800607 }
608
609 private void onListenerDeath(int uid) {
610 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700611 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800612 }
613
614 @Override
615 public void resetLifecycleListenerForUid() {
616 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700617 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800618 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700619 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800620 }
621
Felipe Lemee3cab982020-03-12 11:39:29 -0700622 /**
felipeal61ce3732020-04-03 11:01:00 -0700623 * Gets the initial foreground user after the device boots or resumes from suspension.
624 *
625 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
626 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
627 * method returns {@code null}.
628 *
629 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
630 * (like switching to the last active user), and this method will return the result of such
631 * operation.
632 *
633 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
634 * {@code null}.
635 *
636 * @hide
637 */
638 @Nullable
639 public UserInfo getInitialUser() {
640 checkInteractAcrossUsersPermission("getInitialUser");
641 synchronized (mLockUser) {
642 return mInitialUser;
643 }
644 }
645
felipeal61ce3732020-04-03 11:01:00 -0700646 /**
647 * Sets the initial foreground user after the device boots or resumes from suspension.
648 */
649 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700650 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
651 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700652 synchronized (mLockUser) {
653 mInitialUser = user;
654 }
655 if (user == null) {
656 // This mean InitialUserSetter failed and could not fallback, so the initial user was
657 // not switched (and most likely is SYSTEM_USER).
658 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
659 Log.wtf(TAG_USER, "Initial user set to null");
660 }
661 }
662
Mayank Garg7e1450b2020-08-07 18:15:15 -0700663 private void initResumeReplaceGuest() {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700664 int currentUserId = ActivityManager.getCurrentUser();
665 UserInfo currentUser = mUserManager.getUserInfo(currentUserId);
666
667 if (!mInitialUserSetter.canReplaceGuestUser(currentUser)) return; // Not a guest
668
669 InitialUserInfo info =
670 new InitialUserSetter.Builder(InitialUserSetter.TYPE_REPLACE_GUEST).build();
671
672 mInitialUserSetter.set(info);
673 }
674
675 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700676 * Calls to switch user at the power suspend.
Mayank Garg7e1450b2020-08-07 18:15:15 -0700677 *
678 * <p><b>Note:</b> Should be used only by {@link CarPowerManagementService}
679 *
Mayank Garg7e1450b2020-08-07 18:15:15 -0700680 */
Mayank Garg0baf88a2020-08-30 21:57:36 -0700681 public void onSuspend() {
Mayank Garg7e1450b2020-08-07 18:15:15 -0700682 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Mayank Garg0baf88a2020-08-30 21:57:36 -0700683 Log.d(TAG_USER, "onSuspend called.");
Mayank Garg7e1450b2020-08-07 18:15:15 -0700684 }
685
Mayank Garg0baf88a2020-08-30 21:57:36 -0700686 if (mSwitchGuestUserBeforeSleep) {
687 initResumeReplaceGuest();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700688 }
Mayank Garg1bb1c382020-09-03 17:11:11 -0700689
690 preCreateUsers();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700691 }
692
693 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700694 * Calls to switch user at the power resume.
695 *
696 * <p>
697 * <b>Note:</b> Should be used only by {@link CarPowerManagementService}
698 *
699 */
700 public void onResume() {
701 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
702 Log.d(TAG_USER, "onResume called.");
703 }
704
705 initBootUser(InitialUserInfoRequestType.RESUME);
706 }
707
708 /**
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700709 * Calls to start user at the android startup.
Mayank Garg70732a82020-08-05 20:17:47 -0700710 */
711 public void initBootUser() {
712 int requestType = getInitialUserInfoRequestType();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700713 initBootUser(requestType);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700714 }
715
Mayank Garg7e1450b2020-08-07 18:15:15 -0700716 private void initBootUser(int requestType) {
717 boolean replaceGuest =
718 requestType == InitialUserInfoRequestType.RESUME && !mSwitchGuestUserBeforeSleep;
Mayank Garg70732a82020-08-05 20:17:47 -0700719 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
720 mHalTimeoutMs);
721 checkManageUsersPermission("startInitialUser");
722
723 if (!isUserHalSupported()) {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700724 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700725 return;
726 }
727
728 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
729 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
730 if (resp != null) {
731 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
732 status, resp.action, resp.userToSwitchOrCreate.userId,
733 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
734
735 String userLocales = resp.userLocales;
736 InitialUserInfo info;
737 switch (resp.action) {
738 case InitialUserInfoResponseAction.SWITCH:
739 int userId = resp.userToSwitchOrCreate.userId;
740 if (userId <= 0) {
741 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700742 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700743 break;
744 }
745 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
746 .setUserLocales(userLocales)
747 .setSwitchUserId(userId)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700748 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700749 .build();
750 mInitialUserSetter.set(info);
751 break;
752
753 case InitialUserInfoResponseAction.CREATE:
754 int halFlags = resp.userToSwitchOrCreate.flags;
755 String userName = resp.userNameToCreate;
756 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
757 .setUserLocales(userLocales)
758 .setNewUserName(userName)
759 .setNewUserFlags(halFlags)
760 .build();
761 mInitialUserSetter.set(info);
762 break;
763
764 case InitialUserInfoResponseAction.DEFAULT:
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700765 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700766 break;
767 default:
768 Log.w(TAG_USER, "invalid response action on " + resp);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700769 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700770 break;
771
772 }
773 } else {
774 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700775 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700776 }
777 });
778 }
779
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700780 private void fallbackToDefaultInitialUserBehavior(String userLocales, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700781 InitialUserInfo info = new InitialUserSetter.Builder(
782 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
783 .setUserLocales(userLocales)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700784 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700785 .build();
786 mInitialUserSetter.set(info);
787 }
788
789 @VisibleForTesting
790 int getInitialUserInfoRequestType() {
791 if (!mCarUserManagerHelper.hasInitialUser()) {
792 return InitialUserInfoRequestType.FIRST_BOOT;
793 }
794 if (mContext.getPackageManager().isDeviceUpgrading()) {
795 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
796 }
797 return InitialUserInfoRequestType.COLD_BOOT;
798 }
799
800 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700801 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
802 *
803 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700804 * When everything works well, the workflow is:
805 * <ol>
806 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
807 * type, current user id, target user id, and a callback.
808 * <li> HAL called back with SUCCESS.
809 * <li> {@link IActivityManager} is called for Android user switch.
810 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
811 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
812 * request type, current user id, and target user id. In this case, the current and target
813 * user IDs would be same.
814 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700815 *
816 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700817 * Corner cases:
818 * <ul>
819 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700820 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700821 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
822 * {@code STATUS_HAL_INTERNAL_FAILURE}.
823 * <li> If HAL user switch call is successful, but android user switch call fails,
824 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
825 * target user id, but in this case the current and target user IDs would be different.
826 * <li> If another user switch request for the same target user is received while previous
827 * request is in process, receiver would receive
828 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
829 * <li> If a user switch request is received while another user switch request for different
830 * target user is in process, the previous request would be abandoned and new request will be
831 * processed. No POST_SWITCH would be sent for the previous request.
832 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700833 *
Mayank Garge19c2922020-03-30 18:05:53 -0700834 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700835 * @param timeoutMs - timeout for HAL to wait
836 * @param receiver - receiver for the results
837 */
Mayank Garge19c2922020-03-30 18:05:53 -0700838 @Override
839 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700840 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700841 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700842 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700843 Objects.requireNonNull(receiver);
844 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700845 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700846
felipealf7368962020-04-16 12:55:19 -0700847 int currentUser = ActivityManager.getCurrentUser();
848 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700849 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
850 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
851 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700852 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700853 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700854 return;
855 }
856
Mayank Garg9ed099e2020-06-04 16:05:20 -0700857 // If User Hal is not supported, just android user switch.
858 if (!isUserHalSupported()) {
859 try {
860 if (mAm.switchUser(targetUserId)) {
861 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
862 return;
863 }
864 } catch (RemoteException e) {
865 // ignore
866 Log.w(TAG_USER,
867 "error while switching user " + targetUser.toFullString(), e);
868 }
869 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
870 return;
871 }
872
Mayank Garg7a114c82020-04-08 21:25:06 -0700873 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700874 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
875 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
876 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
877 }
878
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700879 // If there is another request for the same target user, return another request in
880 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
881 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
882 // user switch request in process for different target user, but that request is now
883 // ignored.
felipealf7368962020-04-16 12:55:19 -0700884 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700885 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
886 Log.d(TAG_USER,
887 "Another user switch request in process for the requested target user: "
888 + targetUserId);
889 }
890
891 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700892 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700893 return;
894 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700895 else {
896 mUserIdForUserSwitchInProcess = targetUserId;
897 mRequestIdForUserSwitchInProcess = 0;
898 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700899 }
900
felipealdfdf8512020-06-01 09:35:45 -0700901 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700902 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
903
904 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700905 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
906 Log.d(TAG, "switch response: status="
907 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
908 }
909
felipeale5bf0322020-04-16 15:10:57 -0700910 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700911
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700912 synchronized (mLockUser) {
913 if (status != HalCallback.STATUS_OK) {
914 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
915 Log.w(TAG, "invalid callback status ("
916 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
917 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700918 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700919 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
920 return;
921 }
felipealf7368962020-04-16 12:55:19 -0700922
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700923 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
924 resp.errorMessage);
925
926 if (mUserIdForUserSwitchInProcess != targetUserId) {
927 // Another user switch request received while HAL responded. No need to process
928 // this request further
929 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
930 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
931 + "abondoned for : " + targetUserId + ". Current user in process: "
932 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700933 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700934 resultStatus =
935 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700936 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700937 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
938 return;
939 }
940
941 switch (resp.status) {
942 case SwitchUserStatus.SUCCESS:
943 boolean switched;
944 try {
945 switched = mAm.switchUser(targetUserId);
946 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700947 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700948 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
949 mRequestIdForUserSwitchInProcess = resp.requestId;
950 } else {
951 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
952 postSwitchHalResponse(resp.requestId, targetUserId);
953 }
954 } catch (RemoteException e) {
955 // ignore
956 Log.w(TAG_USER,
957 "error while switching user " + targetUser.toFullString(), e);
958 }
959 break;
960 case SwitchUserStatus.FAILURE:
961 // HAL failed to switch user
962 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
963 break;
felipealdfdf8512020-06-01 09:35:45 -0700964 default:
965 // Shouldn't happen because UserHalService validates the status
966 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700967 }
968
969 if (mRequestIdForUserSwitchInProcess == 0) {
970 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
971 }
Mayank Garg59f22192020-03-27 00:51:45 -0700972 }
felipealdfdf8512020-06-01 09:35:45 -0700973 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700974 });
975 }
976
Mayank Garga55c3092020-05-28 03:19:24 -0700977 @Override
978 public UserRemovalResult removeUser(@UserIdInt int userId) {
979 checkManageUsersPermission("removeUser");
980 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
981 // If the requested user is the current user, return error.
982 if (ActivityManager.getCurrentUser() == userId) {
983 return logAndGetResults(userId,
984 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
985 }
986
987 // If requested user is the only admin user, return error.
988 UserInfo userInfo = mUserManager.getUserInfo(userId);
989 if (userInfo == null) {
990 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
991 }
992
993 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
994 new android.hardware.automotive.vehicle.V2_0.UserInfo();
995 halUser.userId = userInfo.id;
996 halUser.flags = UserHalHelper.convertFlags(userInfo);
997 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
998
Mayank Garge9b7d2c2020-09-15 12:36:06 -0700999 // check if the user is last admin user.
1000 boolean isLastAdmin = false;
Mayank Garga55c3092020-05-28 03:19:24 -07001001 if (UserHalHelper.isAdmin(halUser.flags)) {
1002 int size = usersInfo.existingUsers.size();
1003 int totalAdminUsers = 0;
1004 for (int i = 0; i < size; i++) {
1005 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
1006 totalAdminUsers++;
1007 }
1008 }
1009 if (totalAdminUsers == 1) {
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001010 isLastAdmin = true;
Mayank Garga55c3092020-05-28 03:19:24 -07001011 }
1012 }
1013
1014 // First remove user from android and then remove from HAL because HAL remove user is one
1015 // way call.
1016 if (!mUserManager.removeUser(userId)) {
1017 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1018 }
1019
Mayank Garg9ed099e2020-06-04 16:05:20 -07001020 if (isUserHalSupported()) {
1021 RemoveUserRequest request = new RemoveUserRequest();
1022 request.removedUserInfo = halUser;
Mayank Garg4adef862020-06-16 18:12:28 -07001023 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg9ed099e2020-06-04 16:05:20 -07001024 mHal.removeUser(request);
1025 }
1026
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001027 if (isLastAdmin) {
1028 Log.w(TAG_USER, "Last admin user successfully removed. User Id: " + userId);
1029 }
1030
1031 return logAndGetResults(userId,
1032 isLastAdmin ? UserRemovalResult.STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED
1033 : UserRemovalResult.STATUS_SUCCESSFUL);
Mayank Garga55c3092020-05-28 03:19:24 -07001034 }
1035
1036 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1037 @UserRemovalResult.Status int result) {
1038 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1039 return new UserRemovalResult(result);
1040 }
1041
Mayank Garg587f1942020-05-06 01:41:34 -07001042 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1043 if (mUserSwitchUiReceiver == null) {
1044 Log.w(TAG_USER, "No User switch UI receiver.");
1045 return;
1046 }
1047
felipealdfdf8512020-06-01 09:35:45 -07001048 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001049 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001050 mUserSwitchUiReceiver.send(targetUserId, null);
1051 } catch (RemoteException e) {
1052 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1053 }
1054 }
1055
felipeal5e3ede42020-04-23 18:04:07 -07001056 @Override
felipealdfdf8512020-06-01 09:35:45 -07001057 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1058 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
1059 Objects.requireNonNull(userType, "user type cannot be null");
1060 Objects.requireNonNull(receiver, "receiver cannot be null");
1061 checkManageOrCreateUsersPermission("createUser");
Mayank Garg94f3eb92020-08-12 12:38:58 -07001062 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
1063 UserHelperLite.safeName(name), userType, flags, timeoutMs);
felipealdfdf8512020-06-01 09:35:45 -07001064
1065 UserInfo newUser;
1066 try {
1067 newUser = mUserManager.createUser(name, userType, flags);
1068 if (newUser == null) {
1069 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1070 + " and flags " + UserInfo.flagsToString(flags));
1071 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1072 return;
1073 }
1074 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1075 Log.d(TAG, "Created user: " + newUser.toFullString());
1076 }
1077 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
Mayank Garg94f3eb92020-08-12 12:38:58 -07001078 UserHelperLite.safeName(newUser.name), newUser.userType, newUser.flags);
felipealdfdf8512020-06-01 09:35:45 -07001079 } catch (RuntimeException e) {
1080 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1081 + UserInfo.flagsToString(flags), e);
1082 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1083 return;
1084 }
1085
Mayank Garg9ed099e2020-06-04 16:05:20 -07001086 if (!isUserHalSupported()) {
1087 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1088 return;
1089 }
1090
felipealdfdf8512020-06-01 09:35:45 -07001091 CreateUserRequest request = new CreateUserRequest();
1092 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1093 if (!TextUtils.isEmpty(name)) {
1094 request.newUserName = name;
1095 }
1096 request.newUserInfo.userId = newUser.id;
1097 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1098 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1099 Log.d(TAG, "Create user request: " + request);
1100 }
1101
1102 try {
1103 mHal.createUser(request, timeoutMs, (status, resp) -> {
1104 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1105 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1106 Log.d(TAG, "createUserResponse: status="
1107 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1108 }
1109 UserInfo user = null; // user returned in the result
1110 if (status != HalCallback.STATUS_OK) {
1111 Log.w(TAG, "invalid callback status ("
1112 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1113 + resp);
1114 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1115 resultStatus, resp.errorMessage);
1116 removeUser(newUser, "HAL call failed with "
1117 + UserHalHelper.halCallbackStatusToString(status));
1118 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1119 return;
1120 }
1121
1122 switch (resp.status) {
1123 case CreateUserStatus.SUCCESS:
1124 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1125 user = newUser;
1126 break;
1127 case CreateUserStatus.FAILURE:
1128 // HAL failed to switch user
1129 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1130 break;
1131 default:
1132 // Shouldn't happen because UserHalService validates the status
1133 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1134 }
1135 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1136 resultStatus, resp.errorMessage);
1137 if (user == null) {
1138 removeUser(newUser, "HAL returned "
1139 + UserCreationResult.statusToString(resultStatus));
1140 }
1141 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1142 });
1143 } catch (Exception e) {
1144 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1145 removeUser(newUser, "mHal.createUser() failed");
1146 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1147 }
1148 }
1149
1150 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1151 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1152 try {
1153 if (!mUserManager.removeUser(user.id)) {
1154 Log.w(TAG, "Failed to remove user " + user.toFullString());
1155 }
1156 } catch (Exception e) {
1157 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1158 }
1159 }
1160
1161 @Override
felipeal159a2a42020-05-08 10:32:11 -07001162 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001163 if (!isUserHalUserAssociationSupported()) {
1164 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1165 }
1166
felipeal5e3ede42020-04-23 18:04:07 -07001167 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1168 checkManageUsersPermission("getUserIdentificationAssociation");
1169
1170 int uid = getCallingUid();
1171 int userId = UserHandle.getUserId(uid);
1172 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1173
1174 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1175 request.userInfo.userId = userId;
1176 request.userInfo.flags = getHalUserInfoFlags(userId);
1177
1178 request.numberAssociationTypes = types.length;
1179 for (int i = 0; i < types.length; i++) {
1180 request.associationTypes.add(types[i]);
1181 }
1182
1183 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1184 if (halResponse == null) {
1185 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1186 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001187 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001188 }
1189
1190 int[] values = new int[halResponse.associations.size()];
1191 for (int i = 0; i < values.length; i++) {
1192 values[i] = halResponse.associations.get(i).value;
1193 }
1194 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1195
felipeal159a2a42020-05-08 10:32:11 -07001196 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1197 }
1198
1199 @Override
1200 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1201 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001202 if (!isUserHalUserAssociationSupported()) {
1203 result.complete(
1204 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1205 return;
1206 }
1207
felipeal159a2a42020-05-08 10:32:11 -07001208 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1209 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1210 if (types.length != values.length) {
1211 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1212 + Arrays.toString(values) + ") should have the same length");
1213 }
1214 checkManageUsersPermission("setUserIdentificationAssociation");
1215
1216 int uid = getCallingUid();
1217 int userId = UserHandle.getUserId(uid);
1218 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1219
1220 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1221 request.userInfo.userId = userId;
1222 request.userInfo.flags = getHalUserInfoFlags(userId);
1223
1224 request.numberAssociations = types.length;
1225 for (int i = 0; i < types.length; i++) {
1226 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1227 association.type = types[i];
1228 association.value = values[i];
1229 request.associations.add(association);
1230 }
1231
1232 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1233 if (status != HalCallback.STATUS_OK) {
1234 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1235 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1236 + resp);
1237 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1238 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1239 result.complete(UserIdentificationAssociationResponse.forFailure());
1240 return;
1241 }
1242 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1243 resp.errorMessage);
1244 result.complete(
1245 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1246 return;
1247 }
1248 int respSize = resp.associations.size();
1249 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1250 resp.errorMessage);
1251
1252 int[] responseTypes = new int[respSize];
1253 for (int i = 0; i < respSize; i++) {
1254 responseTypes[i] = resp.associations.get(i).value;
1255 }
1256 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1257 .forSuccess(responseTypes, resp.errorMessage);
1258 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1259 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1260 + ", converted=" + response);
1261 }
1262 result.complete(response);
1263 });
felipeal5e3ede42020-04-23 18:04:07 -07001264 }
1265
1266 /**
1267 * Gets the User HAL flags for the given user.
1268 *
1269 * @throws IllegalArgumentException if the user does not exist.
1270 */
1271 private int getHalUserInfoFlags(@UserIdInt int userId) {
1272 UserInfo user = mUserManager.getUserInfo(userId);
1273 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1274 return UserHalHelper.convertFlags(user);
1275 }
1276
Mayank Garg0e239142020-04-14 19:16:31 -07001277 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1278 @Nullable Bundle resultData) {
1279 try {
1280 receiver.send(resultCode, resultData);
1281 } catch (RemoteException e) {
1282 // ignore
1283 Log.w(TAG_USER, "error while sending results", e);
1284 }
1285 }
1286
felipealdfdf8512020-06-01 09:35:45 -07001287 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001288 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001289 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001290 }
1291
felipealdfdf8512020-06-01 09:35:45 -07001292 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001293 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1294 receiver.complete(new UserSwitchResult(status, errorMessage));
1295 }
1296
felipealdfdf8512020-06-01 09:35:45 -07001297 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1298 @UserCreationResult.Status int status) {
1299 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1300 }
1301
1302 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1303 @UserCreationResult.Status int status, @NonNull UserInfo user,
1304 @Nullable String errorMessage) {
1305 if (TextUtils.isEmpty(errorMessage)) {
1306 errorMessage = null;
1307 }
1308 receiver.complete(new UserCreationResult(status, user, errorMessage));
1309 }
1310
Mayank Garg6307fe42020-04-15 23:09:03 -07001311 /**
1312 * Calls activity manager for user switch.
1313 *
1314 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1315 *
1316 * @param requestId for the user switch request
1317 * @param targetUserId of the target user
1318 *
1319 * @hide
1320 */
1321 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1322 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1323 targetUserId);
1324 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1325
1326 try {
1327 boolean result = mAm.switchUser(targetUserId);
1328 if (result) {
1329 updateUserSwitchInProcess(requestId, targetUserId);
1330 } else {
1331 postSwitchHalResponse(requestId, targetUserId);
1332 }
1333 } catch (RemoteException e) {
1334 // ignore
1335 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1336 }
1337 }
1338
1339 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1340 synchronized (mLockUser) {
1341 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1342 // Some other user switch is in process.
1343 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1344 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1345 + " is in process. Abandoning it as a new user switch is requested"
1346 + " for the target user: " + targetUserId);
1347 }
1348 }
1349 mUserIdForUserSwitchInProcess = targetUserId;
1350 mRequestIdForUserSwitchInProcess = requestId;
1351 }
1352 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001353
Mayank Garg7a114c82020-04-08 21:25:06 -07001354 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001355 if (!isUserHalSupported()) return;
1356
felipealdfdf8512020-06-01 09:35:45 -07001357 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001358 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1359 targetUserId, usersInfo.currentUser.userId);
1360 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1361 request.requestId = requestId;
1362 mHal.postSwitchResponse(request);
1363 }
1364
1365 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1366 @NonNull UsersInfo usersInfo) {
1367 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001368 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1369 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1370 halTargetUser.userId = targetUser.id;
1371 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001372 SwitchUserRequest request = new SwitchUserRequest();
1373 request.targetUser = halTargetUser;
1374 request.usersInfo = usersInfo;
1375 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001376 }
1377
Mayank Garg59f22192020-03-27 00:51:45 -07001378 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001379 * Checks if the User HAL is supported.
1380 */
1381 public boolean isUserHalSupported() {
1382 return mHal.isSupported();
1383 }
1384
Mayank Garg587f1942020-05-06 01:41:34 -07001385 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001386 * Checks if the User HAL user association is supported.
1387 */
1388 @Override
1389 public boolean isUserHalUserAssociationSupported() {
1390 return mHal.isUserAssociationSupported();
1391 }
1392
1393 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001394 * Sets a callback which is invoked before user switch.
1395 *
1396 * <p>
1397 * This method should only be called by the Car System UI. The purpose of this call is to notify
1398 * Car System UI to show the user switch UI before the user switch.
1399 */
1400 @Override
1401 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001402 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001403
1404 // Confirm that caller is system UI.
1405 String systemUiPackageName = getSystemUiPackageName();
1406 if (systemUiPackageName == null) {
1407 throw new IllegalStateException("System UI package not found.");
1408 }
1409
1410 try {
1411 int systemUiUid = mContext
1412 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1413 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1414 int callerUid = Binder.getCallingUid();
1415 if (systemUiUid != callerUid) {
1416 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1417 + " is allowed to make this call");
1418 }
1419 } catch (NameNotFoundException e) {
1420 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1421 }
1422
Mayank Garg587f1942020-05-06 01:41:34 -07001423 mUserSwitchUiReceiver = receiver;
1424 }
1425
Mayank Garga480dd92020-05-14 03:14:57 -07001426 // TODO(157082995): This information can be taken from
1427 // PackageManageInternalImpl.getSystemUiServiceComponent
1428 @Nullable
1429 private String getSystemUiPackageName() {
1430 try {
1431 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1432 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1433 return componentName.getPackageName();
1434 } catch (RuntimeException e) {
1435 Log.w(TAG_USER, "error while getting system UI package name.", e);
1436 return null;
1437 }
1438 }
1439
Keun young Park13a7a822019-04-04 15:53:08 -07001440 private void updateDefaultUserRestriction() {
1441 // We want to set restrictions on system and guest users only once. These are persisted
1442 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1443 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001444 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1445 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001446 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001447 // Only apply the system user restrictions if the system user is headless.
1448 if (UserManager.isHeadlessSystemUserMode()) {
1449 setSystemUserRestrictions();
1450 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001451 Settings.Global.putInt(mContext.getContentResolver(),
1452 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001453 }
1454
Eric Jeong1545f3b2019-09-16 13:56:52 -07001455 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001456 return !mUserManager.getUserInfo(userId).isEphemeral();
1457 }
1458
Antonio Kantekc8114752020-03-05 21:37:39 -08001459 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001460 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1461 */
1462 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1463 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001464 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001465 }
1466
1467 /**
1468 * Removes previously added {@link UserLifecycleListener}.
1469 */
1470 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1471 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001472 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001473 }
1474
Eric Jeongc91f9452019-08-30 15:04:21 -07001475 /** Adds callback to listen to passenger activity events. */
1476 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001477 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001478 mPassengerCallbacks.add(callback);
1479 }
1480
1481 /** Removes previously added callback to listen passenger events. */
1482 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001483 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001484 mPassengerCallbacks.remove(callback);
1485 }
1486
1487 /** Sets the implementation of ZoneUserBindingHelper. */
1488 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1489 synchronized (mLockHelper) {
1490 mZoneUserBindingHelper = helper;
1491 }
1492 }
1493
felipeal98900c82020-04-09 09:05:02 -07001494 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001495 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001496 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001497 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001498 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001499 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1500 updateDefaultUserRestriction();
1501 tasks = new ArrayList<>(mUser0UnlockTasks);
1502 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001503 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001504 }
1505 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001506 Integer user = userId;
1507 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001508 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001509 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001510 mBackgroundUsersToRestart.remove(user);
1511 mBackgroundUsersToRestart.add(0, user);
1512 }
1513 // -1 for user 0
1514 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001515 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001516 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001517 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001518 + ", dropping least recently user from restart list:" + userToDrop);
1519 // Drop the least recently used user.
1520 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1521 }
1522 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001523 }
1524 }
1525 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001526 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001527 for (Runnable r : tasks) {
1528 r.run();
1529 }
1530 }
1531 }
1532
1533 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001534 * Starts all background users that were active in system.
1535 *
Keun young Parkfb656372019-03-12 18:37:55 -07001536 * @return list of background users started successfully.
1537 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001538 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001539 public ArrayList<Integer> startAllBackgroundUsers() {
1540 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001541 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001542 users = new ArrayList<>(mBackgroundUsersToRestart);
1543 mBackgroundUsersRestartedHere.clear();
1544 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001545 }
1546 ArrayList<Integer> startedUsers = new ArrayList<>();
1547 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001548 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001549 continue;
1550 }
1551 try {
1552 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001553 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1554 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001555 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001556 } else if (mAm.unlockUser(user, null, null, null)) {
1557 startedUsers.add(user);
1558 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001559 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001560 if (mUserManager.isUserRunning(user)) {
1561 // add to started list so that it can be stopped later.
1562 startedUsers.add(user);
1563 }
Keun young Parkfb656372019-03-12 18:37:55 -07001564 }
1565 }
1566 } catch (RemoteException e) {
1567 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001568 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001569 }
1570 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001571 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001572 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001573 ArrayList<Integer> usersToRemove = new ArrayList<>();
1574 for (Integer user : mBackgroundUsersToRestart) {
1575 if (!startedUsers.contains(user)) {
1576 usersToRemove.add(user);
1577 }
1578 }
1579 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1580 }
Keun young Parkfb656372019-03-12 18:37:55 -07001581 return startedUsers;
1582 }
1583
1584 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001585 * Stops all background users that were active in system.
1586 *
1587 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001588 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001589 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001590 if (userId == UserHandle.USER_SYSTEM) {
1591 return false;
1592 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001593 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001594 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001595 return false;
1596 }
1597 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001598 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001599 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001600 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001601 Integer user = userId;
1602 mBackgroundUsersRestartedHere.remove(user);
1603 }
1604 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1605 return false;
1606 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001607 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001608 return false;
1609 }
1610 } catch (RemoteException e) {
1611 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001612 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001613 }
1614 return true;
1615 }
1616
1617 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001618 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001619 */
Mayank Gargccad8062020-08-30 15:05:10 -07001620 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType,
felipeale8c5dce2020-04-15 11:27:06 -07001621 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1622 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001623
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001624 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001625 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001626 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001627 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1628 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001629 }
1630
felipeale8c5dce2020-04-15 11:27:06 -07001631 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001632 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001633
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001634 mHandler.post(() -> {
1635 handleNotifyServiceUserLifecycleListeners(event);
1636 handleNotifyAppUserLifecycleListeners(event);
1637 });
felipeale8c5dce2020-04-15 11:27:06 -07001638 }
1639
Mayank Garg7a114c82020-04-08 21:25:06 -07001640 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001641 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001642 || mUserIdForUserSwitchInProcess != userId
1643 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001644 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1645 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1646 }
1647 return;
1648 }
felipealf7368962020-04-16 12:55:19 -07001649 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1650 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001651 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001652 }
1653
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001654 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1655 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001656 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001657 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1658 Log.d(TAG_USER, "No app listener to be notified of " + event);
1659 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001660 return;
1661 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001662 // Must use a different TimingsTraceLog because it's another thread
1663 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1664 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1665 }
felipeal2a84d512020-04-06 18:52:15 -07001666 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001667 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001668 int eventType = event.getEventType();
1669 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001670 for (int i = 0; i < listenersSize; i++) {
1671 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001672
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001673 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1674 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001675 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001676
felipealde1e16d2020-06-03 13:20:48 -07001677 int fromUserId = event.getPreviousUserId();
1678 if (fromUserId != UserHandle.USER_NULL) {
1679 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001680 }
1681
felipeal2a84d512020-04-06 18:52:15 -07001682 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001683 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001684 }
felipealde1e16d2020-06-03 13:20:48 -07001685 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1686 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001687 try {
felipealde1e16d2020-06-03 13:20:48 -07001688 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001689 listener.send(userId, data);
1690 } catch (RemoteException e) {
1691 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1692 } finally {
1693 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001694 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001695 }
1696 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001697 }
1698
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001699 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001700 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1701 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001702 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001703 return;
felipeal2a84d512020-04-06 18:52:15 -07001704 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1705 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1706 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001707 }
felipeal2a84d512020-04-06 18:52:15 -07001708
felipealde1e16d2020-06-03 13:20:48 -07001709 int userId = event.getUserId();
1710 int eventType = event.getEventType();
1711 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001712 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001713 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001714 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1715 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001716 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001717 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001718 listener.onEvent(event);
1719 } catch (RuntimeException e) {
1720 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001721 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001722 } finally {
1723 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001724 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001725 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001726 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001727 }
1728
Mayank Garge5de0f92020-04-23 21:38:38 -07001729 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001730 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001731 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001732 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001733
Mayank Garge5de0f92020-04-23 21:38:38 -07001734 // Switch HAL users if user switch is not requested by CarUserService
1735 notifyHalLegacySwitch(fromUserId, toUserId);
1736
felipealbf327652020-06-03 11:33:29 -07001737 mCarUserManagerHelper.setLastActiveUser(toUserId);
1738
Eric Jeongc91f9452019-08-30 15:04:21 -07001739 if (mLastPassengerId != UserHandle.USER_NULL) {
1740 stopPassengerInternal(mLastPassengerId, false);
1741 }
1742 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1743 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001744 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001745 }
felipeal98900c82020-04-09 09:05:02 -07001746 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001747 }
1748
Mayank Garge5de0f92020-04-23 21:38:38 -07001749 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1750 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001751 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1752 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1753 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1754 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1755 }
1756 return;
1757 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001758 }
1759
Mayank Garg9ed099e2020-06-04 16:05:20 -07001760 if (!isUserHalSupported()) return;
1761
Mayank Garge5de0f92020-04-23 21:38:38 -07001762 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001763 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001764 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1765 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001766 }
1767
Pavel Maltsev17e81832019-04-04 14:38:41 -07001768 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001769 * 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 -08001770 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001771 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001772 * @param r Runnable to run.
1773 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001774 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001775 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001776 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001777 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001778 if (mUser0Unlocked) {
1779 runNow = true;
1780 } else {
1781 mUser0UnlockTasks.add(r);
1782 }
1783 }
1784 if (runNow) {
1785 r.run();
1786 }
1787 }
1788
Keun young Parkf3523cd2019-04-08 10:09:17 -07001789 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001790 @NonNull
1791 ArrayList<Integer> getBackgroundUsersToRestart() {
1792 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001793 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001794 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1795 }
1796 return backgroundUsersToRestart;
1797 }
1798
Ying Zheng1ab32b62018-06-26 12:47:26 -07001799 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001800 // Disable Location service for system user.
1801 LocationManager locationManager =
1802 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001803 locationManager.setLocationEnabledForUser(
1804 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001805 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001806
1807 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001808 * Assigns a default icon to a user according to the user's id.
1809 *
1810 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001811 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001812 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001813 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1814 Bitmap bitmap = UserIcons.convertToBitmap(
1815 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1816 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001817 }
1818
Eric Jeong1545f3b2019-09-16 13:56:52 -07001819 private interface UserFilter {
1820 boolean isEligibleUser(UserInfo user);
1821 }
1822
1823 /** Returns all users who are matched by the given filter. */
1824 private List<UserInfo> getUsers(UserFilter filter) {
Colin Cross0df71ea2020-08-27 04:12:26 +00001825 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeong1545f3b2019-09-16 13:56:52 -07001826
1827 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1828 UserInfo user = iterator.next();
1829 if (!filter.isEligibleUser(user)) {
1830 iterator.remove();
1831 }
1832 }
1833 return users;
1834 }
1835
1836 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001837 * Enforces that apps which have the
1838 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1839 * can make certain calls to the CarUserManager.
1840 *
1841 * @param message used as message if SecurityException is thrown.
1842 * @throws SecurityException if the caller is not system or root.
1843 */
1844 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001845 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1846 }
1847
felipealdfdf8512020-06-01 09:35:45 -07001848 private static void checkManageOrCreateUsersPermission(String message) {
1849 checkAtLeastOnePermission(message,
1850 android.Manifest.permission.MANAGE_USERS,
1851 android.Manifest.permission.CREATE_USERS);
1852 }
1853
felipeal2d0483c2019-11-02 14:07:22 -07001854 private static void checkManageUsersOrDumpPermission(String message) {
1855 checkAtLeastOnePermission(message,
1856 android.Manifest.permission.MANAGE_USERS,
1857 android.Manifest.permission.DUMP);
1858 }
1859
Felipe Leme5528ff72020-02-10 19:05:14 -08001860 private void checkInteractAcrossUsersPermission(String message) {
1861 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1862 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1863 }
1864
felipeal2d0483c2019-11-02 14:07:22 -07001865 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001866 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001867 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1868 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001869 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001870 }
1871 }
1872
felipeal2d0483c2019-11-02 14:07:22 -07001873 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1874 for (String permission : permissions) {
1875 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1876 /* exported = */ true)
1877 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1878 return true;
1879 }
1880 }
1881 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001882 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001883
1884 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
Colin Cross0df71ea2020-08-27 04:12:26 +00001885 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeongc91f9452019-08-30 15:04:21 -07001886 // Count all users that are managed profiles of the given user.
1887 int managedProfilesCount = 0;
1888 for (UserInfo user : users) {
1889 if (user.isManagedProfile() && user.profileGroupId == userId) {
1890 managedProfilesCount++;
1891 }
1892 }
1893 return managedProfilesCount;
1894 }
1895
1896 /**
1897 * Starts the first passenger of the given driver and assigns the passenger to the front
1898 * passenger zone.
1899 *
1900 * @param driverId User id of the driver.
1901 * @return whether it succeeds.
1902 */
1903 private boolean startFirstPassenger(@UserIdInt int driverId) {
1904 int zoneId = getAvailablePassengerZone();
1905 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1906 Log.w(TAG_USER, "passenger occupant zone is not found");
1907 return false;
1908 }
1909 List<UserInfo> passengers = getPassengers(driverId);
1910 if (passengers.size() < 1) {
1911 Log.w(TAG_USER, "passenger is not found");
1912 return false;
1913 }
1914 // Only one passenger is supported. If there are two or more passengers, the first passenger
1915 // is chosen.
1916 int passengerId = passengers.get(0).id;
1917 if (!startPassenger(passengerId, zoneId)) {
1918 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1919 return false;
1920 }
1921 return true;
1922 }
1923
1924 private int getAvailablePassengerZone() {
1925 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1926 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1927 for (int occupantType : occupantTypes) {
1928 int zoneId = getZoneId(occupantType);
1929 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1930 return zoneId;
1931 }
1932 }
1933 return OccupantZoneInfo.INVALID_ZONE_ID;
1934 }
1935
1936 /**
1937 * Creates a new passenger user when there is no passenger user.
1938 */
1939 private void setupPassengerUser() {
1940 int currentUser = ActivityManager.getCurrentUser();
1941 int profileCount = getNumberOfManagedProfiles(currentUser);
1942 if (profileCount > 0) {
1943 Log.w(TAG_USER, "max profile of user" + currentUser
1944 + " is exceeded: current profile count is " + profileCount);
1945 return;
1946 }
1947 // TODO(b/140311342): Use resource string for the default passenger name.
1948 UserInfo passenger = createPassenger("Passenger", currentUser);
1949 if (passenger == null) {
1950 // Couldn't create user, most likely because there are too many.
1951 Log.w(TAG_USER, "cannot create a passenger user");
1952 return;
1953 }
1954 }
1955
1956 @NonNull
1957 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1958 ZoneUserBindingHelper helper = null;
1959 synchronized (mLockHelper) {
1960 if (mZoneUserBindingHelper == null) {
1961 Log.w(TAG_USER, "implementation is not delegated");
1962 return new ArrayList<OccupantZoneInfo>();
1963 }
1964 helper = mZoneUserBindingHelper;
1965 }
1966 return helper.getOccupantZones(occupantType);
1967 }
1968
1969 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1970 ZoneUserBindingHelper helper = null;
1971 synchronized (mLockHelper) {
1972 if (mZoneUserBindingHelper == null) {
1973 Log.w(TAG_USER, "implementation is not delegated");
1974 return false;
1975 }
1976 helper = mZoneUserBindingHelper;
1977 }
1978 return helper.assignUserToOccupantZone(userId, zoneId);
1979 }
1980
1981 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1982 ZoneUserBindingHelper helper = null;
1983 synchronized (mLockHelper) {
1984 if (mZoneUserBindingHelper == null) {
1985 Log.w(TAG_USER, "implementation is not delegated");
1986 return false;
1987 }
1988 helper = mZoneUserBindingHelper;
1989 }
1990 return helper.unassignUserFromOccupantZone(userId);
1991 }
1992
1993 private boolean isPassengerDisplayAvailable() {
1994 ZoneUserBindingHelper helper = null;
1995 synchronized (mLockHelper) {
1996 if (mZoneUserBindingHelper == null) {
1997 Log.w(TAG_USER, "implementation is not delegated");
1998 return false;
1999 }
2000 helper = mZoneUserBindingHelper;
2001 }
2002 return helper.isPassengerDisplayAvailable();
2003 }
2004
2005 /**
2006 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
2007 * zone is returned.
2008 *
2009 * @param occupantType The type of an occupant.
2010 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
2011 * if not found.
2012 */
2013 private int getZoneId(@OccupantTypeEnum int occupantType) {
2014 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
2015 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
2016 }
Mayank Garg9732d602020-08-09 21:02:40 -07002017
2018 /**
2019 * Manages the required number of pre-created users.
2020 */
2021 public void preCreateUsers() {
2022 mUserPreCreator.managePreCreatedUsers();
2023 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002024}