blob: f26976febee99eb8f7cd1eb09672b2e2fc50430b [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.user;
18
Felipe Leme17799202020-09-03 12:55:53 -070019import static android.Manifest.permission.CREATE_USERS;
20import static android.Manifest.permission.MANAGE_USERS;
21
Eric Jeong1545f3b2019-09-16 13:56:52 -070022import static com.android.car.CarLog.TAG_USER;
23
24import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070025import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070026import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070027import android.app.ActivityManager;
Louis Chang3bf2f202020-08-18 13:04:28 +080028import android.app.ActivityTaskManager.RootTaskInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070029import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070030import android.car.CarOccupantZoneManager;
31import android.car.CarOccupantZoneManager.OccupantTypeEnum;
32import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070033import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070034import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080035import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080036import android.car.user.CarUserManager.UserLifecycleEvent;
37import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070038import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070039import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070040import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070041import android.car.user.UserSwitchResult;
felipeal19e3d732020-03-18 12:07:32 -070042import android.car.userlib.HalCallback;
43import android.car.userlib.UserHalHelper;
Mayank Garge90a4082020-09-30 12:57:34 -070044import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070046import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070047import android.content.pm.PackageManager;
48import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070049import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070050import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070051import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070052import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070053import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
54import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Mayank Garg70732a82020-08-05 20:17:47 -070055import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080056import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070057import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070058import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070059import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070062import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
63import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080064import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070065import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070066import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080067import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070068import android.os.Handler;
69import android.os.HandlerThread;
Felipe Leme17799202020-09-03 12:55:53 -070070import android.os.Process;
Keun young Parkfb656372019-03-12 18:37:55 -070071import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080072import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070073import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070074import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070075import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070076import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070077import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070078import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070079import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080080import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080081import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070082
83import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070084import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070085import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080086import com.android.car.hal.UserHalService;
Mayank Gargf59f95b2020-10-01 14:55:11 -070087import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
Mayank Garg801ea6a2020-09-29 15:43:49 -070088import com.android.car.internal.common.EventLogTags;
89import com.android.car.internal.common.UserHelperLite;
Mayank Garg4bdfbf72020-08-06 13:27:43 -070090import com.android.car.power.CarPowerManagementService;
Mayank Garg665c20b2020-08-07 16:19:28 -070091import com.android.car.user.InitialUserSetter.InitialUserInfo;
Keun-young Parkd462a912019-02-11 08:53:42 -080092import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070093import com.android.internal.annotations.VisibleForTesting;
felipeale5bf0322020-04-16 15:10:57 -070094import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080095import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070096import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070097import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070098import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070099import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700100
101import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -0800102import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -0700103import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700104import java.util.Iterator;
105import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000106import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700107import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700108import java.util.concurrent.CountDownLatch;
109import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700110
111/**
112 * User service for cars. Manages users at boot time. Including:
113 *
114 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700115 * <li> Creates a user used as driver.
116 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700117 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700118 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700119 * <ol/>
120 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700121public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800122
felipealf7368962020-04-16 12:55:19 -0700123 private static final String TAG = TAG_USER;
124
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800125 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700126 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800127 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700128 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800129 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Mayank Garg8f932822020-09-17 16:09:12 -0700130 public static final String BUNDLE_USER_NAME = "user.name";
felipeala68ecef2020-05-19 12:46:08 -0700131 /**
132 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
133 */
Mayank Garg8f932822020-09-17 16:09:12 -0700134 public static final String BUNDLE_USER_LOCALES = "user.locales";
felipeala68ecef2020-05-19 12:46:08 -0700135 /**
136 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
137 */
Mayank Garg8f932822020-09-17 16:09:12 -0700138 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800139
Mayank Garg9ed099e2020-06-04 16:05:20 -0700140 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
141
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700142 private final Context mContext;
Keun young Parkfb656372019-03-12 18:37:55 -0700143 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700144 private final UserManager mUserManager;
145 private final int mMaxRunningUsers;
Mayank Garg70732a82020-08-05 20:17:47 -0700146 private final InitialUserSetter mInitialUserSetter;
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 private final boolean mEnablePassengerSupport;
Mayank Garg9732d602020-08-09 21:02:40 -0700148 private final UserPreCreator mUserPreCreator;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700149
Eric Jeongc91f9452019-08-30 15:04:21 -0700150 private final Object mLockUser = new Object();
151 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800152 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700153 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800154 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700155 // Only one passenger is supported.
156 @GuardedBy("mLockUser")
157 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700158 /**
159 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800160 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700161 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700162 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700163 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
164 /**
165 * Keep the list of background users started here. This is wholly for debugging purpose.
166 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700167 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700168 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
169
Felipe Leme58412202020-01-09 13:45:33 -0800170 private final UserHalService mHal;
171
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700172 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700173 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
174 getClass().getSimpleName());
175 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700176
Felipe Leme5528ff72020-02-10 19:05:14 -0800177 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800178 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700179 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800180 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700181 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800182
183 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800184 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700185 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800186 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700187 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800188
Mayank Garg7a114c82020-04-08 21:25:06 -0700189 /**
190 * User Id for the user switch in process, if any.
191 */
192 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700193 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700194 /**
195 * Request Id for the user switch in process, if any.
196 */
197 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700198 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700199 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
200
Eric Jeongc91f9452019-08-30 15:04:21 -0700201 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
202 new CopyOnWriteArrayList<>();
203
Mayank Garg7e1450b2020-08-07 18:15:15 -0700204 // TODO(b/163566866): Use mSwitchGuestUserBeforeSleep for new create guest request
205 private final boolean mSwitchGuestUserBeforeSleep;
206
felipeal61ce3732020-04-03 11:01:00 -0700207 @Nullable
208 @GuardedBy("mLockUser")
209 private UserInfo mInitialUser;
210
Mayank Garg587f1942020-05-06 01:41:34 -0700211 private IResultReceiver mUserSwitchUiReceiver;
212
Eric Jeongc91f9452019-08-30 15:04:21 -0700213 /** Interface for callbaks related to passenger activities. */
214 public interface PassengerCallback {
215 /** Called when passenger is started at a certain zone. */
216 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
217 /** Called when passenger is stopped. */
218 void onPassengerStopped(@UserIdInt int passengerId);
219 }
220
221 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
222 public interface ZoneUserBindingHelper {
223 /** Gets occupant zones corresponding to the occupant type. */
224 @NonNull
225 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
226 /** Assigns the user to the occupant zone. */
227 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
228 /** Makes the occupant zone unoccupied. */
229 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
230 /** Returns whether there is a passenger display. */
231 boolean isPassengerDisplayAvailable();
232 }
233
234 private final Object mLockHelper = new Object();
235 @GuardedBy("mLockHelper")
236 private ZoneUserBindingHelper mZoneUserBindingHelper;
237
Felipe Leme58412202020-01-09 13:45:33 -0800238 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garge90a4082020-09-30 12:57:34 -0700239 @NonNull UserManager userManager,
Mayank Garg71661ea2020-04-29 01:25:03 -0700240 @NonNull IActivityManager am, int maxRunningUsers) {
Mayank Garge90a4082020-09-30 12:57:34 -0700241 this(context, hal, userManager, am, maxRunningUsers,
Mayank Garg1bb1c382020-09-03 17:11:11 -0700242 /* initialUserSetter= */ null, /* userPreCreator= */ null);
Mayank Garg71661ea2020-04-29 01:25:03 -0700243 }
244
245 @VisibleForTesting
246 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garge90a4082020-09-30 12:57:34 -0700247 @NonNull UserManager userManager,
Mayank Gargccad8062020-08-30 15:05:10 -0700248 @NonNull IActivityManager am, int maxRunningUsers,
Mayank Garg1bb1c382020-09-03 17:11:11 -0700249 @Nullable InitialUserSetter initialUserSetter,
250 @Nullable UserPreCreator userPreCreator) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700251 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
252 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700253 }
254 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800255 mHal = hal;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700256 mAm = am;
257 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700258 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700259 mLastPassengerId = UserHandle.USER_NULL;
Mayank Garg1bb1c382020-09-03 17:11:11 -0700260 mInitialUserSetter =
261 initialUserSetter == null ? new InitialUserSetter(context, (u) -> setInitialUser(u))
262 : initialUserSetter;
263 mUserPreCreator =
264 userPreCreator == null ? new UserPreCreator(mUserManager) : userPreCreator;
Mayank Garg7e1450b2020-08-07 18:15:15 -0700265 Resources resources = context.getResources();
266 mEnablePassengerSupport = resources.getBoolean(R.bool.enablePassengerSupport);
267 mSwitchGuestUserBeforeSleep = resources.getBoolean(
268 R.bool.config_switchGuestUserBeforeGoingSleep);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700269 }
270
271 @Override
272 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700273 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
274 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700275 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700276 }
277
278 @Override
279 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700280 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
281 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700282 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700283 }
284
285 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700286 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700287 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700288 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800289 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700290 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700291 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700292 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700293 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700294 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
295 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700296 }
297 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
298 List<UserInfo> allDrivers = getAllDrivers();
299 int driversSize = allDrivers.size();
300 writer.println("NumberOfDrivers: " + driversSize);
301 for (int i = 0; i < driversSize; i++) {
302 int driverId = allDrivers.get(i).id;
303 writer.print(indent + "#" + i + ": id=" + driverId);
304 List<UserInfo> passengers = getPassengers(driverId);
305 int passengersSize = passengers.size();
306 writer.print(" NumberPassengers: " + passengersSize);
307 if (passengersSize > 0) {
308 writer.print(" [");
309 for (int j = 0; j < passengersSize; j++) {
310 writer.print(passengers.get(j).id);
311 if (j < passengersSize - 1) {
312 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700313 }
felipeal2d0483c2019-11-02 14:07:22 -0700314 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700315 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700316 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700317 writer.println();
318 }
319 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
320 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
321 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700322
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700323 writer.println("Relevant overlayable properties");
324 Resources res = mContext.getResources();
325 writer.printf("%sowner_name=%s\n", indent,
326 res.getString(com.android.internal.R.string.owner_name));
327 writer.printf("%sdefault_guest_name=%s\n", indent,
328 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700329 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700330 writer.printf("Request Id for the user switch in process=%d\n ",
331 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700332 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700333
felipealbf327652020-06-03 11:33:29 -0700334 writer.println("Relevant Global settings");
335 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
336 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
337
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700338 mInitialUserSetter.dump(writer);
felipeale8c5dce2020-04-15 11:27:06 -0700339 }
340
felipealbf327652020-06-03 11:33:29 -0700341 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
342 String value = Settings.Global.getString(mContext.getContentResolver(), property);
343 writer.printf("%s%s=%s\n", indent, property, value);
344 }
345
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700346 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
347 CountDownLatch latch = new CountDownLatch(1);
348 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700349 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700350 handleDumpAppLifecycleListeners(writer, indent);
351 latch.countDown();
352 });
353 int timeout = 5;
354 try {
355 if (!latch.await(timeout, TimeUnit.SECONDS)) {
356 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
357 timeout);
358 }
359 } catch (InterruptedException e) {
360 Thread.currentThread().interrupt();
361 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
362 }
363 }
364
felipealde1e16d2020-06-03 13:20:48 -0700365 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700366 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700367 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700368 return;
369 }
felipealde1e16d2020-06-03 13:20:48 -0700370 int size = mUserLifecycleListeners.size();
371 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
372 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700373 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700374 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700375 }
376 }
377
378 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700379 int size = mAppLifecycleListeners.size();
380 if (size == 0) {
381 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700382 return;
383 }
felipealde1e16d2020-06-03 13:20:48 -0700384 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
385 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700386 int uid = mAppLifecycleListeners.keyAt(i);
387 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700388 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800389 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700390 }
391
392 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700393 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700394 */
395 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700396 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700397 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000398 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700399
400 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
401 @Override
402 protected void onCompleted(UserCreationResult result, Throwable err) {
403 if (result == null) {
404 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
405 } else {
406 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
407 assignDefaultIcon(result.getUser());
408 }
409 }
410 super.onCompleted(result, err);
411 };
412 };
413 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700414 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700415 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
416 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
417 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
418 return future;
419 }
420 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700421 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700422 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
423 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700424 }
425
426 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700427 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700428 */
429 @Override
430 @Nullable
431 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
432 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000433 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700434 UserInfo driver = mUserManager.getUserInfo(driverId);
435 if (driver == null) {
436 Log.w(TAG_USER, "the driver is invalid");
437 return null;
438 }
439 if (driver.isGuest()) {
440 Log.w(TAG_USER, "a guest driver cannot create a passenger");
441 return null;
442 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700443 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700444 UserInfo user = mUserManager.createProfileForUser(name,
445 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700446 if (user == null) {
447 // Couldn't create user, most likely because there are too many.
448 Log.w(TAG_USER, "can't create a profile for user" + driverId);
449 return null;
450 }
451 // Passenger user should be a non-admin user.
Mayank Garge90a4082020-09-30 12:57:34 -0700452 UserHelper.setDefaultNonAdminRestrictions(mContext, user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700453 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700454 return user;
455 }
456
457 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700458 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700459 */
460 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700461 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700462 checkManageUsersPermission("switchDriver");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700463 if (UserHelperLite.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700464 // System user doesn't associate with real person, can not be switched to.
465 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700466 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700467 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700468 }
469 int userSwitchable = mUserManager.getUserSwitchability();
470 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
471 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700472 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700473 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700475 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700476 }
477
478 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800479 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
480 *
481 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700482 */
483 @Override
484 @NonNull
485 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700486 checkManageUsersOrDumpPermission("getAllDrivers");
Mayank Garg94f3eb92020-08-12 12:38:58 -0700487 return getUsers((user) -> !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700488 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700489 }
490
491 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800492 * Returns all passengers under the given driver.
493 *
494 * @param driverId User id of a driver.
495 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700496 */
497 @Override
498 @NonNull
499 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700500 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700501 return getUsers((user) -> {
Mayank Garg94f3eb92020-08-12 12:38:58 -0700502 return !UserHelperLite.isHeadlessSystemUser(user.id) && user.isEnabled()
Eric Jeong40f8fa32020-05-12 12:23:33 -0700503 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700504 });
505 }
506
507 /**
508 * @see CarUserManager.startPassenger
509 */
510 @Override
511 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
512 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700513 synchronized (mLockUser) {
514 try {
515 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
516 Log.w(TAG_USER, "could not start passenger");
517 return false;
518 }
519 } catch (RemoteException e) {
520 // ignore
521 Log.w(TAG_USER, "error while starting passenger", e);
522 return false;
523 }
524 if (!assignUserToOccupantZone(passengerId, zoneId)) {
525 Log.w(TAG_USER, "could not assign passenger to zone");
526 return false;
527 }
528 mLastPassengerId = passengerId;
529 }
530 for (PassengerCallback callback : mPassengerCallbacks) {
531 callback.onPassengerStarted(passengerId, zoneId);
532 }
533 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700534 }
535
536 /**
537 * @see CarUserManager.stopPassenger
538 */
539 @Override
540 public boolean stopPassenger(@UserIdInt int passengerId) {
541 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700542 return stopPassengerInternal(passengerId, true);
543 }
544
545 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
546 synchronized (mLockUser) {
547 UserInfo passenger = mUserManager.getUserInfo(passengerId);
548 if (passenger == null) {
549 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
550 return false;
551 }
552 if (mLastPassengerId != passengerId) {
553 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
554 return true;
555 }
556 if (checkCurrentDriver) {
557 int currentUser = ActivityManager.getCurrentUser();
558 if (passenger.profileGroupId != currentUser) {
559 Log.w(TAG_USER, "passenger " + passengerId
560 + " is not a profile of the current user");
561 return false;
562 }
563 }
564 // Passenger is a profile, so cannot be stopped through activity manager.
565 // Instead, activities started by the passenger are stopped and the passenger is
566 // unassigned from the zone.
567 stopAllTasks(passengerId);
568 if (!unassignUserFromOccupantZone(passengerId)) {
569 Log.w(TAG_USER, "could not unassign user from occupant zone");
570 return false;
571 }
572 mLastPassengerId = UserHandle.USER_NULL;
573 }
574 for (PassengerCallback callback : mPassengerCallbacks) {
575 callback.onPassengerStopped(passengerId);
576 }
577 return true;
578 }
579
580 private void stopAllTasks(@UserIdInt int userId) {
581 try {
Louis Chang3bf2f202020-08-18 13:04:28 +0800582 for (RootTaskInfo info : mAm.getAllRootTaskInfos()) {
583 for (int i = 0; i < info.childTaskIds.length; i++) {
584 if (info.childTaskUserIds[i] == userId) {
585 int taskId = info.childTaskIds[i];
Eric Jeongc91f9452019-08-30 15:04:21 -0700586 if (!mAm.removeTask(taskId)) {
587 Log.w(TAG_USER, "could not remove task " + taskId);
588 }
589 }
590 }
591 }
592 } catch (RemoteException e) {
593 Log.e(TAG_USER, "could not get stack info", e);
594 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700595 }
596
Felipe Leme5528ff72020-02-10 19:05:14 -0800597 @Override
598 public void setLifecycleListenerForUid(IResultReceiver listener) {
599 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700600 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800601 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
602
603 try {
604 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
605 } catch (RemoteException e) {
606 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
607 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700608 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800609 }
610
611 private void onListenerDeath(int uid) {
612 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700613 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800614 }
615
616 @Override
617 public void resetLifecycleListenerForUid() {
618 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700619 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800620 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700621 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800622 }
623
Felipe Lemee3cab982020-03-12 11:39:29 -0700624 /**
felipeal61ce3732020-04-03 11:01:00 -0700625 * Gets the initial foreground user after the device boots or resumes from suspension.
626 *
627 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
628 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
629 * method returns {@code null}.
630 *
631 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
632 * (like switching to the last active user), and this method will return the result of such
633 * operation.
634 *
635 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
636 * {@code null}.
637 *
638 * @hide
639 */
640 @Nullable
641 public UserInfo getInitialUser() {
642 checkInteractAcrossUsersPermission("getInitialUser");
643 synchronized (mLockUser) {
644 return mInitialUser;
645 }
646 }
647
felipeal61ce3732020-04-03 11:01:00 -0700648 /**
649 * Sets the initial foreground user after the device boots or resumes from suspension.
650 */
651 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700652 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
653 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700654 synchronized (mLockUser) {
655 mInitialUser = user;
656 }
657 if (user == null) {
658 // This mean InitialUserSetter failed and could not fallback, so the initial user was
659 // not switched (and most likely is SYSTEM_USER).
660 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
661 Log.wtf(TAG_USER, "Initial user set to null");
662 }
663 }
664
Mayank Garg7e1450b2020-08-07 18:15:15 -0700665 private void initResumeReplaceGuest() {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700666 int currentUserId = ActivityManager.getCurrentUser();
667 UserInfo currentUser = mUserManager.getUserInfo(currentUserId);
668
669 if (!mInitialUserSetter.canReplaceGuestUser(currentUser)) return; // Not a guest
670
671 InitialUserInfo info =
672 new InitialUserSetter.Builder(InitialUserSetter.TYPE_REPLACE_GUEST).build();
673
674 mInitialUserSetter.set(info);
675 }
676
677 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700678 * Calls to switch user at the power suspend.
Mayank Garg7e1450b2020-08-07 18:15:15 -0700679 *
680 * <p><b>Note:</b> Should be used only by {@link CarPowerManagementService}
681 *
Mayank Garg7e1450b2020-08-07 18:15:15 -0700682 */
Mayank Garg0baf88a2020-08-30 21:57:36 -0700683 public void onSuspend() {
Mayank Garg7e1450b2020-08-07 18:15:15 -0700684 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Mayank Garg0baf88a2020-08-30 21:57:36 -0700685 Log.d(TAG_USER, "onSuspend called.");
Mayank Garg7e1450b2020-08-07 18:15:15 -0700686 }
687
Mayank Garg0baf88a2020-08-30 21:57:36 -0700688 if (mSwitchGuestUserBeforeSleep) {
689 initResumeReplaceGuest();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700690 }
Mayank Garg1bb1c382020-09-03 17:11:11 -0700691
692 preCreateUsers();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700693 }
694
695 /**
Mayank Garg0baf88a2020-08-30 21:57:36 -0700696 * Calls to switch user at the power resume.
697 *
698 * <p>
699 * <b>Note:</b> Should be used only by {@link CarPowerManagementService}
700 *
701 */
702 public void onResume() {
703 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
704 Log.d(TAG_USER, "onResume called.");
705 }
706
707 initBootUser(InitialUserInfoRequestType.RESUME);
708 }
709
710 /**
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700711 * Calls to start user at the android startup.
Mayank Garg70732a82020-08-05 20:17:47 -0700712 */
713 public void initBootUser() {
714 int requestType = getInitialUserInfoRequestType();
Mayank Garg7e1450b2020-08-07 18:15:15 -0700715 initBootUser(requestType);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700716 }
717
Mayank Garg7e1450b2020-08-07 18:15:15 -0700718 private void initBootUser(int requestType) {
719 boolean replaceGuest =
720 requestType == InitialUserInfoRequestType.RESUME && !mSwitchGuestUserBeforeSleep;
Mayank Garg70732a82020-08-05 20:17:47 -0700721 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
722 mHalTimeoutMs);
723 checkManageUsersPermission("startInitialUser");
724
725 if (!isUserHalSupported()) {
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700726 fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700727 return;
728 }
729
730 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
731 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, (status, resp) -> {
732 if (resp != null) {
733 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
734 status, resp.action, resp.userToSwitchOrCreate.userId,
735 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
736
737 String userLocales = resp.userLocales;
738 InitialUserInfo info;
739 switch (resp.action) {
740 case InitialUserInfoResponseAction.SWITCH:
741 int userId = resp.userToSwitchOrCreate.userId;
742 if (userId <= 0) {
743 Log.w(TAG, "invalid (or missing) user id sent by HAL: " + userId);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700744 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700745 break;
746 }
747 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_SWITCH)
748 .setUserLocales(userLocales)
749 .setSwitchUserId(userId)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700750 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700751 .build();
752 mInitialUserSetter.set(info);
753 break;
754
755 case InitialUserInfoResponseAction.CREATE:
756 int halFlags = resp.userToSwitchOrCreate.flags;
757 String userName = resp.userNameToCreate;
758 info = new InitialUserSetter.Builder(InitialUserSetter.TYPE_CREATE)
759 .setUserLocales(userLocales)
760 .setNewUserName(userName)
761 .setNewUserFlags(halFlags)
762 .build();
763 mInitialUserSetter.set(info);
764 break;
765
766 case InitialUserInfoResponseAction.DEFAULT:
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700767 fallbackToDefaultInitialUserBehavior(userLocales, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700768 break;
769 default:
770 Log.w(TAG_USER, "invalid response action on " + resp);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700771 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700772 break;
773
774 }
775 } else {
776 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700777 fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
Mayank Garg70732a82020-08-05 20:17:47 -0700778 }
779 });
780 }
781
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700782 private void fallbackToDefaultInitialUserBehavior(String userLocales, boolean replaceGuest) {
Mayank Garg70732a82020-08-05 20:17:47 -0700783 InitialUserInfo info = new InitialUserSetter.Builder(
784 InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
785 .setUserLocales(userLocales)
Mayank Garg4bdfbf72020-08-06 13:27:43 -0700786 .setReplaceGuest(replaceGuest)
Mayank Garg70732a82020-08-05 20:17:47 -0700787 .build();
788 mInitialUserSetter.set(info);
789 }
790
791 @VisibleForTesting
792 int getInitialUserInfoRequestType() {
Mayank Garge90a4082020-09-30 12:57:34 -0700793 if (!mInitialUserSetter.hasInitialUser()) {
Mayank Garg70732a82020-08-05 20:17:47 -0700794 return InitialUserInfoRequestType.FIRST_BOOT;
795 }
796 if (mContext.getPackageManager().isDeviceUpgrading()) {
797 return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
798 }
799 return InitialUserInfoRequestType.COLD_BOOT;
800 }
801
802 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700803 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
804 *
805 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700806 * When everything works well, the workflow is:
807 * <ol>
808 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
809 * type, current user id, target user id, and a callback.
810 * <li> HAL called back with SUCCESS.
811 * <li> {@link IActivityManager} is called for Android user switch.
812 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
813 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
814 * request type, current user id, and target user id. In this case, the current and target
815 * user IDs would be same.
816 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700817 *
818 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700819 * Corner cases:
820 * <ul>
821 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700822 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700823 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
824 * {@code STATUS_HAL_INTERNAL_FAILURE}.
825 * <li> If HAL user switch call is successful, but android user switch call fails,
826 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
827 * target user id, but in this case the current and target user IDs would be different.
828 * <li> If another user switch request for the same target user is received while previous
829 * request is in process, receiver would receive
830 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
831 * <li> If a user switch request is received while another user switch request for different
832 * target user is in process, the previous request would be abandoned and new request will be
833 * processed. No POST_SWITCH would be sent for the previous request.
834 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700835 *
Mayank Garge19c2922020-03-30 18:05:53 -0700836 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700837 * @param timeoutMs - timeout for HAL to wait
838 * @param receiver - receiver for the results
839 */
Mayank Garge19c2922020-03-30 18:05:53 -0700840 @Override
841 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700842 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700843 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Felipe Leme17799202020-09-03 12:55:53 -0700844 checkManageOrCreateUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700845 Objects.requireNonNull(receiver);
846 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700847 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700848
felipealf7368962020-04-16 12:55:19 -0700849 int currentUser = ActivityManager.getCurrentUser();
850 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700851 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
852 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
853 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700854 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700855 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700856 return;
857 }
858
Mayank Garg9ed099e2020-06-04 16:05:20 -0700859 // If User Hal is not supported, just android user switch.
860 if (!isUserHalSupported()) {
861 try {
862 if (mAm.switchUser(targetUserId)) {
863 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
864 return;
865 }
866 } catch (RemoteException e) {
867 // ignore
868 Log.w(TAG_USER,
869 "error while switching user " + targetUser.toFullString(), e);
870 }
871 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
872 return;
873 }
874
Mayank Garg7a114c82020-04-08 21:25:06 -0700875 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700876 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
877 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
878 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
879 }
880
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700881 // If there is another request for the same target user, return another request in
882 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
883 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
884 // user switch request in process for different target user, but that request is now
885 // ignored.
felipealf7368962020-04-16 12:55:19 -0700886 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700887 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
888 Log.d(TAG_USER,
889 "Another user switch request in process for the requested target user: "
890 + targetUserId);
891 }
892
893 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700894 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700895 return;
896 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700897 else {
898 mUserIdForUserSwitchInProcess = targetUserId;
899 mRequestIdForUserSwitchInProcess = 0;
900 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700901 }
902
felipealdfdf8512020-06-01 09:35:45 -0700903 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700904 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
905
906 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700907 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
908 Log.d(TAG, "switch response: status="
909 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
910 }
911
felipeale5bf0322020-04-16 15:10:57 -0700912 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700913
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700914 synchronized (mLockUser) {
915 if (status != HalCallback.STATUS_OK) {
916 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
917 Log.w(TAG, "invalid callback status ("
918 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
919 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700920 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700921 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
922 return;
923 }
felipealf7368962020-04-16 12:55:19 -0700924
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700925 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
926 resp.errorMessage);
927
928 if (mUserIdForUserSwitchInProcess != targetUserId) {
929 // Another user switch request received while HAL responded. No need to process
930 // this request further
931 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
932 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
933 + "abondoned for : " + targetUserId + ". Current user in process: "
934 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700935 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700936 resultStatus =
937 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700938 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700939 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
940 return;
941 }
942
943 switch (resp.status) {
944 case SwitchUserStatus.SUCCESS:
945 boolean switched;
946 try {
947 switched = mAm.switchUser(targetUserId);
948 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700949 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700950 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
951 mRequestIdForUserSwitchInProcess = resp.requestId;
952 } else {
953 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
954 postSwitchHalResponse(resp.requestId, targetUserId);
955 }
956 } catch (RemoteException e) {
957 // ignore
958 Log.w(TAG_USER,
959 "error while switching user " + targetUser.toFullString(), e);
960 }
961 break;
962 case SwitchUserStatus.FAILURE:
963 // HAL failed to switch user
964 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
965 break;
felipealdfdf8512020-06-01 09:35:45 -0700966 default:
967 // Shouldn't happen because UserHalService validates the status
968 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700969 }
970
971 if (mRequestIdForUserSwitchInProcess == 0) {
972 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
973 }
Mayank Garg59f22192020-03-27 00:51:45 -0700974 }
felipealdfdf8512020-06-01 09:35:45 -0700975 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700976 });
977 }
978
Mayank Garga55c3092020-05-28 03:19:24 -0700979 @Override
980 public UserRemovalResult removeUser(@UserIdInt int userId) {
Felipe Leme17799202020-09-03 12:55:53 -0700981 checkManageOrCreateUsersPermission("removeUser");
Mayank Garga55c3092020-05-28 03:19:24 -0700982 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
983 // If the requested user is the current user, return error.
984 if (ActivityManager.getCurrentUser() == userId) {
985 return logAndGetResults(userId,
986 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
987 }
988
989 // If requested user is the only admin user, return error.
990 UserInfo userInfo = mUserManager.getUserInfo(userId);
991 if (userInfo == null) {
992 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
993 }
994
995 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
996 new android.hardware.automotive.vehicle.V2_0.UserInfo();
997 halUser.userId = userInfo.id;
998 halUser.flags = UserHalHelper.convertFlags(userInfo);
999 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1000
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001001 // check if the user is last admin user.
1002 boolean isLastAdmin = false;
Mayank Garga55c3092020-05-28 03:19:24 -07001003 if (UserHalHelper.isAdmin(halUser.flags)) {
1004 int size = usersInfo.existingUsers.size();
1005 int totalAdminUsers = 0;
1006 for (int i = 0; i < size; i++) {
1007 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
1008 totalAdminUsers++;
1009 }
1010 }
1011 if (totalAdminUsers == 1) {
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001012 isLastAdmin = true;
Mayank Garga55c3092020-05-28 03:19:24 -07001013 }
1014 }
1015
1016 // First remove user from android and then remove from HAL because HAL remove user is one
1017 // way call.
1018 if (!mUserManager.removeUser(userId)) {
1019 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
1020 }
1021
Mayank Garg9ed099e2020-06-04 16:05:20 -07001022 if (isUserHalSupported()) {
1023 RemoveUserRequest request = new RemoveUserRequest();
1024 request.removedUserInfo = halUser;
Mayank Garg4adef862020-06-16 18:12:28 -07001025 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Garg9ed099e2020-06-04 16:05:20 -07001026 mHal.removeUser(request);
1027 }
1028
Mayank Garge9b7d2c2020-09-15 12:36:06 -07001029 if (isLastAdmin) {
1030 Log.w(TAG_USER, "Last admin user successfully removed. User Id: " + userId);
1031 }
1032
1033 return logAndGetResults(userId,
1034 isLastAdmin ? UserRemovalResult.STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED
1035 : UserRemovalResult.STATUS_SUCCESSFUL);
Mayank Garga55c3092020-05-28 03:19:24 -07001036 }
1037
1038 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
1039 @UserRemovalResult.Status int result) {
1040 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
1041 return new UserRemovalResult(result);
1042 }
1043
Mayank Garg587f1942020-05-06 01:41:34 -07001044 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
1045 if (mUserSwitchUiReceiver == null) {
1046 Log.w(TAG_USER, "No User switch UI receiver.");
1047 return;
1048 }
1049
felipealdfdf8512020-06-01 09:35:45 -07001050 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -07001051 try {
Mayank Garg587f1942020-05-06 01:41:34 -07001052 mUserSwitchUiReceiver.send(targetUserId, null);
1053 } catch (RemoteException e) {
1054 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
1055 }
1056 }
1057
felipeal5e3ede42020-04-23 18:04:07 -07001058 @Override
felipealdfdf8512020-06-01 09:35:45 -07001059 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
1060 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
1061 Objects.requireNonNull(userType, "user type cannot be null");
1062 Objects.requireNonNull(receiver, "receiver cannot be null");
Felipe Leme17799202020-09-03 12:55:53 -07001063 checkManageOrCreateUsersPermission(flags);
1064
Mayank Garg94f3eb92020-08-12 12:38:58 -07001065 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
1066 UserHelperLite.safeName(name), userType, flags, timeoutMs);
felipealdfdf8512020-06-01 09:35:45 -07001067
1068 UserInfo newUser;
1069 try {
1070 newUser = mUserManager.createUser(name, userType, flags);
1071 if (newUser == null) {
1072 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1073 + " and flags " + UserInfo.flagsToString(flags));
1074 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1075 return;
1076 }
1077 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1078 Log.d(TAG, "Created user: " + newUser.toFullString());
1079 }
1080 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
Mayank Garg94f3eb92020-08-12 12:38:58 -07001081 UserHelperLite.safeName(newUser.name), newUser.userType, newUser.flags);
felipealdfdf8512020-06-01 09:35:45 -07001082 } catch (RuntimeException e) {
1083 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1084 + UserInfo.flagsToString(flags), e);
1085 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1086 return;
1087 }
1088
Mayank Garg9ed099e2020-06-04 16:05:20 -07001089 if (!isUserHalSupported()) {
1090 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1091 return;
1092 }
1093
felipealdfdf8512020-06-01 09:35:45 -07001094 CreateUserRequest request = new CreateUserRequest();
1095 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1096 if (!TextUtils.isEmpty(name)) {
1097 request.newUserName = name;
1098 }
1099 request.newUserInfo.userId = newUser.id;
1100 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1101 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1102 Log.d(TAG, "Create user request: " + request);
1103 }
1104
1105 try {
1106 mHal.createUser(request, timeoutMs, (status, resp) -> {
1107 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1108 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1109 Log.d(TAG, "createUserResponse: status="
1110 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1111 }
1112 UserInfo user = null; // user returned in the result
1113 if (status != HalCallback.STATUS_OK) {
1114 Log.w(TAG, "invalid callback status ("
1115 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1116 + resp);
1117 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1118 resultStatus, resp.errorMessage);
1119 removeUser(newUser, "HAL call failed with "
1120 + UserHalHelper.halCallbackStatusToString(status));
1121 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1122 return;
1123 }
1124
1125 switch (resp.status) {
1126 case CreateUserStatus.SUCCESS:
1127 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1128 user = newUser;
1129 break;
1130 case CreateUserStatus.FAILURE:
1131 // HAL failed to switch user
1132 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1133 break;
1134 default:
1135 // Shouldn't happen because UserHalService validates the status
1136 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1137 }
1138 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1139 resultStatus, resp.errorMessage);
1140 if (user == null) {
1141 removeUser(newUser, "HAL returned "
1142 + UserCreationResult.statusToString(resultStatus));
1143 }
1144 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1145 });
1146 } catch (Exception e) {
1147 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1148 removeUser(newUser, "mHal.createUser() failed");
1149 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1150 }
1151 }
1152
1153 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1154 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1155 try {
1156 if (!mUserManager.removeUser(user.id)) {
1157 Log.w(TAG, "Failed to remove user " + user.toFullString());
1158 }
1159 } catch (Exception e) {
1160 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1161 }
1162 }
1163
1164 @Override
felipeal159a2a42020-05-08 10:32:11 -07001165 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001166 if (!isUserHalUserAssociationSupported()) {
1167 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1168 }
1169
felipeal5e3ede42020-04-23 18:04:07 -07001170 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
Felipe Leme17799202020-09-03 12:55:53 -07001171 checkManageOrCreateUsersPermission("getUserIdentificationAssociation");
felipeal5e3ede42020-04-23 18:04:07 -07001172
1173 int uid = getCallingUid();
1174 int userId = UserHandle.getUserId(uid);
1175 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1176
1177 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1178 request.userInfo.userId = userId;
1179 request.userInfo.flags = getHalUserInfoFlags(userId);
1180
1181 request.numberAssociationTypes = types.length;
1182 for (int i = 0; i < types.length; i++) {
1183 request.associationTypes.add(types[i]);
1184 }
1185
1186 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1187 if (halResponse == null) {
1188 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1189 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001190 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001191 }
1192
1193 int[] values = new int[halResponse.associations.size()];
1194 for (int i = 0; i < values.length; i++) {
1195 values[i] = halResponse.associations.get(i).value;
1196 }
1197 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1198
felipeal159a2a42020-05-08 10:32:11 -07001199 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1200 }
1201
1202 @Override
1203 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1204 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001205 if (!isUserHalUserAssociationSupported()) {
1206 result.complete(
1207 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1208 return;
1209 }
1210
felipeal159a2a42020-05-08 10:32:11 -07001211 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1212 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1213 if (types.length != values.length) {
1214 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1215 + Arrays.toString(values) + ") should have the same length");
1216 }
Felipe Leme17799202020-09-03 12:55:53 -07001217 checkManageOrCreateUsersPermission("setUserIdentificationAssociation");
felipeal159a2a42020-05-08 10:32:11 -07001218
1219 int uid = getCallingUid();
1220 int userId = UserHandle.getUserId(uid);
1221 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1222
1223 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1224 request.userInfo.userId = userId;
1225 request.userInfo.flags = getHalUserInfoFlags(userId);
1226
1227 request.numberAssociations = types.length;
1228 for (int i = 0; i < types.length; i++) {
1229 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1230 association.type = types[i];
1231 association.value = values[i];
1232 request.associations.add(association);
1233 }
1234
1235 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1236 if (status != HalCallback.STATUS_OK) {
1237 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1238 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1239 + resp);
1240 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1241 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1242 result.complete(UserIdentificationAssociationResponse.forFailure());
1243 return;
1244 }
1245 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1246 resp.errorMessage);
1247 result.complete(
1248 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1249 return;
1250 }
1251 int respSize = resp.associations.size();
1252 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1253 resp.errorMessage);
1254
1255 int[] responseTypes = new int[respSize];
1256 for (int i = 0; i < respSize; i++) {
1257 responseTypes[i] = resp.associations.get(i).value;
1258 }
1259 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1260 .forSuccess(responseTypes, resp.errorMessage);
1261 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1262 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1263 + ", converted=" + response);
1264 }
1265 result.complete(response);
1266 });
felipeal5e3ede42020-04-23 18:04:07 -07001267 }
1268
1269 /**
1270 * Gets the User HAL flags for the given user.
1271 *
1272 * @throws IllegalArgumentException if the user does not exist.
1273 */
1274 private int getHalUserInfoFlags(@UserIdInt int userId) {
1275 UserInfo user = mUserManager.getUserInfo(userId);
1276 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1277 return UserHalHelper.convertFlags(user);
1278 }
1279
Mayank Garg0e239142020-04-14 19:16:31 -07001280 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1281 @Nullable Bundle resultData) {
1282 try {
1283 receiver.send(resultCode, resultData);
1284 } catch (RemoteException e) {
1285 // ignore
1286 Log.w(TAG_USER, "error while sending results", e);
1287 }
1288 }
1289
felipealdfdf8512020-06-01 09:35:45 -07001290 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001291 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001292 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001293 }
1294
felipealdfdf8512020-06-01 09:35:45 -07001295 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001296 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1297 receiver.complete(new UserSwitchResult(status, errorMessage));
1298 }
1299
felipealdfdf8512020-06-01 09:35:45 -07001300 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1301 @UserCreationResult.Status int status) {
1302 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1303 }
1304
1305 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1306 @UserCreationResult.Status int status, @NonNull UserInfo user,
1307 @Nullable String errorMessage) {
1308 if (TextUtils.isEmpty(errorMessage)) {
1309 errorMessage = null;
1310 }
1311 receiver.complete(new UserCreationResult(status, user, errorMessage));
1312 }
1313
Mayank Garg6307fe42020-04-15 23:09:03 -07001314 /**
1315 * Calls activity manager for user switch.
1316 *
1317 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1318 *
1319 * @param requestId for the user switch request
1320 * @param targetUserId of the target user
1321 *
1322 * @hide
1323 */
1324 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1325 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1326 targetUserId);
1327 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1328
1329 try {
1330 boolean result = mAm.switchUser(targetUserId);
1331 if (result) {
1332 updateUserSwitchInProcess(requestId, targetUserId);
1333 } else {
1334 postSwitchHalResponse(requestId, targetUserId);
1335 }
1336 } catch (RemoteException e) {
1337 // ignore
1338 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1339 }
1340 }
1341
1342 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1343 synchronized (mLockUser) {
1344 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1345 // Some other user switch is in process.
1346 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1347 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1348 + " is in process. Abandoning it as a new user switch is requested"
1349 + " for the target user: " + targetUserId);
1350 }
1351 }
1352 mUserIdForUserSwitchInProcess = targetUserId;
1353 mRequestIdForUserSwitchInProcess = requestId;
1354 }
1355 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001356
Mayank Garg7a114c82020-04-08 21:25:06 -07001357 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001358 if (!isUserHalSupported()) return;
1359
felipealdfdf8512020-06-01 09:35:45 -07001360 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001361 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1362 targetUserId, usersInfo.currentUser.userId);
1363 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1364 request.requestId = requestId;
1365 mHal.postSwitchResponse(request);
1366 }
1367
1368 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1369 @NonNull UsersInfo usersInfo) {
1370 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001371 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1372 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1373 halTargetUser.userId = targetUser.id;
1374 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001375 SwitchUserRequest request = new SwitchUserRequest();
1376 request.targetUser = halTargetUser;
1377 request.usersInfo = usersInfo;
1378 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001379 }
1380
Mayank Garg59f22192020-03-27 00:51:45 -07001381 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001382 * Checks if the User HAL is supported.
1383 */
1384 public boolean isUserHalSupported() {
1385 return mHal.isSupported();
1386 }
1387
Mayank Garg587f1942020-05-06 01:41:34 -07001388 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001389 * Checks if the User HAL user association is supported.
1390 */
1391 @Override
1392 public boolean isUserHalUserAssociationSupported() {
1393 return mHal.isUserAssociationSupported();
1394 }
1395
1396 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001397 * Sets a callback which is invoked before user switch.
1398 *
1399 * <p>
1400 * This method should only be called by the Car System UI. The purpose of this call is to notify
1401 * Car System UI to show the user switch UI before the user switch.
1402 */
1403 @Override
1404 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001405 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001406
1407 // Confirm that caller is system UI.
1408 String systemUiPackageName = getSystemUiPackageName();
1409 if (systemUiPackageName == null) {
1410 throw new IllegalStateException("System UI package not found.");
1411 }
1412
1413 try {
1414 int systemUiUid = mContext
1415 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1416 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1417 int callerUid = Binder.getCallingUid();
1418 if (systemUiUid != callerUid) {
1419 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1420 + " is allowed to make this call");
1421 }
1422 } catch (NameNotFoundException e) {
1423 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1424 }
1425
Mayank Garg587f1942020-05-06 01:41:34 -07001426 mUserSwitchUiReceiver = receiver;
1427 }
1428
Mayank Garga480dd92020-05-14 03:14:57 -07001429 // TODO(157082995): This information can be taken from
1430 // PackageManageInternalImpl.getSystemUiServiceComponent
1431 @Nullable
1432 private String getSystemUiPackageName() {
1433 try {
1434 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1435 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1436 return componentName.getPackageName();
1437 } catch (RuntimeException e) {
1438 Log.w(TAG_USER, "error while getting system UI package name.", e);
1439 return null;
1440 }
1441 }
1442
Keun young Park13a7a822019-04-04 15:53:08 -07001443 private void updateDefaultUserRestriction() {
1444 // We want to set restrictions on system and guest users only once. These are persisted
1445 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1446 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001447 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1448 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001449 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001450 // Only apply the system user restrictions if the system user is headless.
1451 if (UserManager.isHeadlessSystemUserMode()) {
1452 setSystemUserRestrictions();
1453 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001454 Settings.Global.putInt(mContext.getContentResolver(),
1455 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001456 }
1457
Eric Jeong1545f3b2019-09-16 13:56:52 -07001458 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001459 return !mUserManager.getUserInfo(userId).isEphemeral();
1460 }
1461
Antonio Kantekc8114752020-03-05 21:37:39 -08001462 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001463 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1464 */
1465 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1466 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001467 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001468 }
1469
1470 /**
1471 * Removes previously added {@link UserLifecycleListener}.
1472 */
1473 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1474 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001475 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001476 }
1477
Eric Jeongc91f9452019-08-30 15:04:21 -07001478 /** Adds callback to listen to passenger activity events. */
1479 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001480 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001481 mPassengerCallbacks.add(callback);
1482 }
1483
1484 /** Removes previously added callback to listen passenger events. */
1485 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001486 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001487 mPassengerCallbacks.remove(callback);
1488 }
1489
1490 /** Sets the implementation of ZoneUserBindingHelper. */
1491 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1492 synchronized (mLockHelper) {
1493 mZoneUserBindingHelper = helper;
1494 }
1495 }
1496
felipeal98900c82020-04-09 09:05:02 -07001497 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001498 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001499 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001500 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001501 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001502 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1503 updateDefaultUserRestriction();
1504 tasks = new ArrayList<>(mUser0UnlockTasks);
1505 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001506 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001507 }
1508 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001509 Integer user = userId;
1510 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001511 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001512 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001513 mBackgroundUsersToRestart.remove(user);
1514 mBackgroundUsersToRestart.add(0, user);
1515 }
1516 // -1 for user 0
1517 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001518 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001519 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001520 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001521 + ", dropping least recently user from restart list:" + userToDrop);
1522 // Drop the least recently used user.
1523 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1524 }
1525 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001526 }
1527 }
1528 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001529 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001530 for (Runnable r : tasks) {
1531 r.run();
1532 }
1533 }
1534 }
1535
1536 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001537 * Starts all background users that were active in system.
1538 *
Keun young Parkfb656372019-03-12 18:37:55 -07001539 * @return list of background users started successfully.
1540 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001541 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001542 public ArrayList<Integer> startAllBackgroundUsers() {
1543 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001544 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001545 users = new ArrayList<>(mBackgroundUsersToRestart);
1546 mBackgroundUsersRestartedHere.clear();
1547 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001548 }
1549 ArrayList<Integer> startedUsers = new ArrayList<>();
1550 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001551 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001552 continue;
1553 }
1554 try {
1555 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001556 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1557 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001558 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001559 } else if (mAm.unlockUser(user, null, null, null)) {
1560 startedUsers.add(user);
1561 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001562 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001563 if (mUserManager.isUserRunning(user)) {
1564 // add to started list so that it can be stopped later.
1565 startedUsers.add(user);
1566 }
Keun young Parkfb656372019-03-12 18:37:55 -07001567 }
1568 }
1569 } catch (RemoteException e) {
1570 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001571 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001572 }
1573 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001574 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001575 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001576 ArrayList<Integer> usersToRemove = new ArrayList<>();
1577 for (Integer user : mBackgroundUsersToRestart) {
1578 if (!startedUsers.contains(user)) {
1579 usersToRemove.add(user);
1580 }
1581 }
1582 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1583 }
Keun young Parkfb656372019-03-12 18:37:55 -07001584 return startedUsers;
1585 }
1586
1587 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001588 * Stops all background users that were active in system.
1589 *
1590 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001591 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001592 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001593 if (userId == UserHandle.USER_SYSTEM) {
1594 return false;
1595 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001596 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001597 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001598 return false;
1599 }
1600 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001601 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001602 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001603 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001604 Integer user = userId;
1605 mBackgroundUsersRestartedHere.remove(user);
1606 }
1607 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1608 return false;
1609 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001610 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001611 return false;
1612 }
1613 } catch (RemoteException e) {
1614 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001615 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001616 }
1617 return true;
1618 }
1619
1620 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001621 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001622 */
Mayank Gargccad8062020-08-30 15:05:10 -07001623 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType,
felipeale8c5dce2020-04-15 11:27:06 -07001624 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1625 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001626
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001627 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001628 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001629 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001630 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1631 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001632 }
1633
felipeale8c5dce2020-04-15 11:27:06 -07001634 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001635 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001636
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001637 mHandler.post(() -> {
1638 handleNotifyServiceUserLifecycleListeners(event);
1639 handleNotifyAppUserLifecycleListeners(event);
1640 });
felipeale8c5dce2020-04-15 11:27:06 -07001641 }
1642
Mayank Garg7a114c82020-04-08 21:25:06 -07001643 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001644 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001645 || mUserIdForUserSwitchInProcess != userId
1646 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001647 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1648 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1649 }
1650 return;
1651 }
felipealf7368962020-04-16 12:55:19 -07001652 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1653 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001654 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001655 }
1656
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001657 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1658 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001659 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001660 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1661 Log.d(TAG_USER, "No app listener to be notified of " + event);
1662 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001663 return;
1664 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001665 // Must use a different TimingsTraceLog because it's another thread
1666 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1667 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1668 }
felipeal2a84d512020-04-06 18:52:15 -07001669 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001670 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001671 int eventType = event.getEventType();
1672 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001673 for (int i = 0; i < listenersSize; i++) {
1674 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001675
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001676 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1677 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001678 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001679
felipealde1e16d2020-06-03 13:20:48 -07001680 int fromUserId = event.getPreviousUserId();
1681 if (fromUserId != UserHandle.USER_NULL) {
1682 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001683 }
1684
felipeal2a84d512020-04-06 18:52:15 -07001685 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001686 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001687 }
felipealde1e16d2020-06-03 13:20:48 -07001688 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1689 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001690 try {
felipealde1e16d2020-06-03 13:20:48 -07001691 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001692 listener.send(userId, data);
1693 } catch (RemoteException e) {
1694 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1695 } finally {
1696 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001697 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001698 }
1699 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001700 }
1701
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001702 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001703 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1704 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001705 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001706 return;
felipeal2a84d512020-04-06 18:52:15 -07001707 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1708 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1709 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001710 }
felipeal2a84d512020-04-06 18:52:15 -07001711
felipealde1e16d2020-06-03 13:20:48 -07001712 int userId = event.getUserId();
1713 int eventType = event.getEventType();
1714 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001715 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001716 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001717 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1718 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001719 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001720 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001721 listener.onEvent(event);
1722 } catch (RuntimeException e) {
1723 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001724 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001725 } finally {
1726 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001727 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001728 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001729 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001730 }
1731
Mayank Garge5de0f92020-04-23 21:38:38 -07001732 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001733 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001734 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001735 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001736
Mayank Garge5de0f92020-04-23 21:38:38 -07001737 // Switch HAL users if user switch is not requested by CarUserService
1738 notifyHalLegacySwitch(fromUserId, toUserId);
1739
Mayank Garge90a4082020-09-30 12:57:34 -07001740 mInitialUserSetter.setLastActiveUser(toUserId);
felipealbf327652020-06-03 11:33:29 -07001741
Eric Jeongc91f9452019-08-30 15:04:21 -07001742 if (mLastPassengerId != UserHandle.USER_NULL) {
1743 stopPassengerInternal(mLastPassengerId, false);
1744 }
1745 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1746 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001747 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001748 }
felipeal98900c82020-04-09 09:05:02 -07001749 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001750 }
1751
Mayank Garge5de0f92020-04-23 21:38:38 -07001752 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1753 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001754 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1755 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1756 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1757 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1758 }
1759 return;
1760 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001761 }
1762
Mayank Garg9ed099e2020-06-04 16:05:20 -07001763 if (!isUserHalSupported()) return;
1764
Mayank Garge5de0f92020-04-23 21:38:38 -07001765 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001766 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001767 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1768 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001769 }
1770
Pavel Maltsev17e81832019-04-04 14:38:41 -07001771 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001772 * 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 -08001773 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001774 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001775 * @param r Runnable to run.
1776 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001777 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001778 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001779 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001780 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001781 if (mUser0Unlocked) {
1782 runNow = true;
1783 } else {
1784 mUser0UnlockTasks.add(r);
1785 }
1786 }
1787 if (runNow) {
1788 r.run();
1789 }
1790 }
1791
Keun young Parkf3523cd2019-04-08 10:09:17 -07001792 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001793 @NonNull
1794 ArrayList<Integer> getBackgroundUsersToRestart() {
1795 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001796 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001797 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1798 }
1799 return backgroundUsersToRestart;
1800 }
1801
Ying Zheng1ab32b62018-06-26 12:47:26 -07001802 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001803 // Disable Location service for system user.
1804 LocationManager locationManager =
1805 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001806 locationManager.setLocationEnabledForUser(
1807 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001808 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001809
1810 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001811 * Assigns a default icon to a user according to the user's id.
1812 *
1813 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001814 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001815 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001816 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1817 Bitmap bitmap = UserIcons.convertToBitmap(
1818 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1819 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001820 }
1821
Eric Jeong1545f3b2019-09-16 13:56:52 -07001822 private interface UserFilter {
1823 boolean isEligibleUser(UserInfo user);
1824 }
1825
1826 /** Returns all users who are matched by the given filter. */
1827 private List<UserInfo> getUsers(UserFilter filter) {
Colin Cross0df71ea2020-08-27 04:12:26 +00001828 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeong1545f3b2019-09-16 13:56:52 -07001829
1830 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1831 UserInfo user = iterator.next();
1832 if (!filter.isEligibleUser(user)) {
1833 iterator.remove();
1834 }
1835 }
1836 return users;
1837 }
1838
felipeal2d0483c2019-11-02 14:07:22 -07001839 private static void checkManageUsersOrDumpPermission(String message) {
1840 checkAtLeastOnePermission(message,
1841 android.Manifest.permission.MANAGE_USERS,
1842 android.Manifest.permission.DUMP);
1843 }
1844
Felipe Leme5528ff72020-02-10 19:05:14 -08001845 private void checkInteractAcrossUsersPermission(String message) {
1846 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1847 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1848 }
1849
felipeal2d0483c2019-11-02 14:07:22 -07001850 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001851 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001852 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1853 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001854 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001855 }
1856 }
1857
felipeal2d0483c2019-11-02 14:07:22 -07001858 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1859 for (String permission : permissions) {
1860 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1861 /* exported = */ true)
1862 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1863 return true;
1864 }
1865 }
1866 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001867 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001868
1869 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
Colin Cross0df71ea2020-08-27 04:12:26 +00001870 List<UserInfo> users = mUserManager.getAliveUsers();
Eric Jeongc91f9452019-08-30 15:04:21 -07001871 // Count all users that are managed profiles of the given user.
1872 int managedProfilesCount = 0;
1873 for (UserInfo user : users) {
1874 if (user.isManagedProfile() && user.profileGroupId == userId) {
1875 managedProfilesCount++;
1876 }
1877 }
1878 return managedProfilesCount;
1879 }
1880
1881 /**
1882 * Starts the first passenger of the given driver and assigns the passenger to the front
1883 * passenger zone.
1884 *
1885 * @param driverId User id of the driver.
1886 * @return whether it succeeds.
1887 */
1888 private boolean startFirstPassenger(@UserIdInt int driverId) {
1889 int zoneId = getAvailablePassengerZone();
1890 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1891 Log.w(TAG_USER, "passenger occupant zone is not found");
1892 return false;
1893 }
1894 List<UserInfo> passengers = getPassengers(driverId);
1895 if (passengers.size() < 1) {
1896 Log.w(TAG_USER, "passenger is not found");
1897 return false;
1898 }
1899 // Only one passenger is supported. If there are two or more passengers, the first passenger
1900 // is chosen.
1901 int passengerId = passengers.get(0).id;
1902 if (!startPassenger(passengerId, zoneId)) {
1903 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1904 return false;
1905 }
1906 return true;
1907 }
1908
1909 private int getAvailablePassengerZone() {
1910 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1911 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1912 for (int occupantType : occupantTypes) {
1913 int zoneId = getZoneId(occupantType);
1914 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1915 return zoneId;
1916 }
1917 }
1918 return OccupantZoneInfo.INVALID_ZONE_ID;
1919 }
1920
1921 /**
1922 * Creates a new passenger user when there is no passenger user.
1923 */
1924 private void setupPassengerUser() {
1925 int currentUser = ActivityManager.getCurrentUser();
1926 int profileCount = getNumberOfManagedProfiles(currentUser);
1927 if (profileCount > 0) {
1928 Log.w(TAG_USER, "max profile of user" + currentUser
1929 + " is exceeded: current profile count is " + profileCount);
1930 return;
1931 }
1932 // TODO(b/140311342): Use resource string for the default passenger name.
1933 UserInfo passenger = createPassenger("Passenger", currentUser);
1934 if (passenger == null) {
1935 // Couldn't create user, most likely because there are too many.
1936 Log.w(TAG_USER, "cannot create a passenger user");
1937 return;
1938 }
1939 }
1940
1941 @NonNull
1942 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1943 ZoneUserBindingHelper helper = null;
1944 synchronized (mLockHelper) {
1945 if (mZoneUserBindingHelper == null) {
1946 Log.w(TAG_USER, "implementation is not delegated");
1947 return new ArrayList<OccupantZoneInfo>();
1948 }
1949 helper = mZoneUserBindingHelper;
1950 }
1951 return helper.getOccupantZones(occupantType);
1952 }
1953
1954 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1955 ZoneUserBindingHelper helper = null;
1956 synchronized (mLockHelper) {
1957 if (mZoneUserBindingHelper == null) {
1958 Log.w(TAG_USER, "implementation is not delegated");
1959 return false;
1960 }
1961 helper = mZoneUserBindingHelper;
1962 }
1963 return helper.assignUserToOccupantZone(userId, zoneId);
1964 }
1965
1966 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1967 ZoneUserBindingHelper helper = null;
1968 synchronized (mLockHelper) {
1969 if (mZoneUserBindingHelper == null) {
1970 Log.w(TAG_USER, "implementation is not delegated");
1971 return false;
1972 }
1973 helper = mZoneUserBindingHelper;
1974 }
1975 return helper.unassignUserFromOccupantZone(userId);
1976 }
1977
1978 private boolean isPassengerDisplayAvailable() {
1979 ZoneUserBindingHelper helper = null;
1980 synchronized (mLockHelper) {
1981 if (mZoneUserBindingHelper == null) {
1982 Log.w(TAG_USER, "implementation is not delegated");
1983 return false;
1984 }
1985 helper = mZoneUserBindingHelper;
1986 }
1987 return helper.isPassengerDisplayAvailable();
1988 }
1989
1990 /**
1991 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1992 * zone is returned.
1993 *
1994 * @param occupantType The type of an occupant.
1995 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1996 * if not found.
1997 */
1998 private int getZoneId(@OccupantTypeEnum int occupantType) {
1999 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
2000 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
2001 }
Mayank Garg9732d602020-08-09 21:02:40 -07002002
2003 /**
2004 * Manages the required number of pre-created users.
2005 */
2006 public void preCreateUsers() {
2007 mUserPreCreator.managePreCreatedUsers();
2008 }
Felipe Leme17799202020-09-03 12:55:53 -07002009
2010 // TODO(b/167698977): members below were copied from UserManagerService; it would be better to
2011 // move them to some internal android.os class instead.
2012
2013 private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
2014 UserInfo.FLAG_MANAGED_PROFILE
2015 | UserInfo.FLAG_PROFILE
2016 | UserInfo.FLAG_EPHEMERAL
2017 | UserInfo.FLAG_RESTRICTED
2018 | UserInfo.FLAG_GUEST
2019 | UserInfo.FLAG_DEMO
2020 | UserInfo.FLAG_FULL;
2021
2022 private static void checkManageUsersPermission(String message) {
2023 if (!hasManageUsersPermission()) {
2024 throw new SecurityException("You need " + MANAGE_USERS + " permission to: " + message);
2025 }
2026 }
2027
2028 private static void checkManageOrCreateUsersPermission(String message) {
2029 if (!hasManageOrCreateUsersPermission()) {
2030 throw new SecurityException(
2031 "You either need " + MANAGE_USERS + " or " + CREATE_USERS + " permission to: "
2032 + message);
2033 }
2034 }
2035
2036 private static void checkManageOrCreateUsersPermission(int creationFlags) {
2037 if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
2038 if (!hasManageOrCreateUsersPermission()) {
2039 throw new SecurityException("You either need " + MANAGE_USERS + " or "
2040 + CREATE_USERS + "permission to create a user with flags "
2041 + creationFlags);
2042 }
2043 } else if (!hasManageUsersPermission()) {
2044 throw new SecurityException("You need " + MANAGE_USERS + " permission to create a user"
2045 + " with flags " + creationFlags);
2046 }
2047 }
2048
2049 private static boolean hasManageUsersPermission() {
2050 final int callingUid = Binder.getCallingUid();
2051 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
2052 || callingUid == Process.ROOT_UID
2053 || hasPermissionGranted(MANAGE_USERS, callingUid);
2054 }
2055
2056 private static boolean hasManageUsersOrPermission(String alternativePermission) {
2057 final int callingUid = Binder.getCallingUid();
2058 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
2059 || callingUid == Process.ROOT_UID
2060 || hasPermissionGranted(MANAGE_USERS, callingUid)
2061 || hasPermissionGranted(alternativePermission, callingUid);
2062 }
2063
2064 private static boolean hasManageOrCreateUsersPermission() {
2065 return hasManageUsersOrPermission(CREATE_USERS);
2066 }
2067
2068 private static boolean hasPermissionGranted(String permission, int uid) {
2069 return ActivityManager.checkComponentPermission(permission, uid, /* owningUid= */ -1,
2070 /* exported= */ true) == PackageManager.PERMISSION_GRANTED;
2071 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07002072}