blob: fd469e7513ade8fe848a3e56493b89693f32b6a7 [file] [log] [blame]
Ying Zhengd3cb98e2018-05-11 11:42:48 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.user;
18
Eric Jeong1545f3b2019-09-16 13:56:52 -070019import static com.android.car.CarLog.TAG_USER;
20
21import android.annotation.NonNull;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070022import android.annotation.Nullable;
Eric Jeong1545f3b2019-09-16 13:56:52 -070023import android.annotation.UserIdInt;
Keun young Parkfb656372019-03-12 18:37:55 -070024import android.app.ActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070025import android.app.ActivityManager.StackInfo;
Keun young Parkfb656372019-03-12 18:37:55 -070026import android.app.IActivityManager;
Eric Jeongc91f9452019-08-30 15:04:21 -070027import android.car.CarOccupantZoneManager;
28import android.car.CarOccupantZoneManager.OccupantTypeEnum;
29import android.car.CarOccupantZoneManager.OccupantZoneInfo;
Eric Jeong1545f3b2019-09-16 13:56:52 -070030import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070031import android.car.settings.CarSettings;
Felipe Leme5528ff72020-02-10 19:05:14 -080032import android.car.user.CarUserManager;
Antonio Kantekc8114752020-03-05 21:37:39 -080033import android.car.user.CarUserManager.UserLifecycleEvent;
felipeale8c5dce2020-04-15 11:27:06 -070034import android.car.user.CarUserManager.UserLifecycleEventType;
Antonio Kantekc8114752020-03-05 21:37:39 -080035import android.car.user.CarUserManager.UserLifecycleListener;
felipealdfdf8512020-06-01 09:35:45 -070036import android.car.user.UserCreationResult;
felipeal159a2a42020-05-08 10:32:11 -070037import android.car.user.UserIdentificationAssociationResponse;
Mayank Garga55c3092020-05-28 03:19:24 -070038import android.car.user.UserRemovalResult;
felipeale5bf0322020-04-16 15:10:57 -070039import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070040import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070041import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070042import android.car.userlib.HalCallback;
43import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070044import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070046import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070047import android.content.pm.PackageManager;
48import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070049import android.content.pm.UserInfo;
felipealdfdf8512020-06-01 09:35:45 -070050import android.content.pm.UserInfo.UserInfoFlag;
Felipe Leme315a53b2020-03-12 10:51:04 -070051import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070052import android.graphics.Bitmap;
felipealdfdf8512020-06-01 09:35:45 -070053import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
54import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
Felipe Lemee3cab982020-03-12 11:39:29 -070055import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080056import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garga55c3092020-05-28 03:19:24 -070057import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
Mayank Gargeb37d092020-06-02 14:37:57 -070058import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
Mayank Garg59f22192020-03-27 00:51:45 -070059import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070060import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
61import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070062import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
63import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080064import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070065import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070066import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080067import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070068import android.os.Handler;
69import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070070import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080071import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070072import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070073import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070074import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070075import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070076import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070077import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070078import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080079import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080080import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070081
82import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070083import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070084import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080085import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080086import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070087import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070088import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070089import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080090import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070091import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070092import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070093import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070094import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070095
96import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080097import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070098import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070099import java.util.Iterator;
100import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000101import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -0700102import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700103import java.util.concurrent.CountDownLatch;
104import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700105
106/**
107 * User service for cars. Manages users at boot time. Including:
108 *
109 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700110 * <li> Creates a user used as driver.
111 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700112 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700113 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114 * <ol/>
115 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700116public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800117
felipealf7368962020-04-16 12:55:19 -0700118 private static final String TAG = TAG_USER;
119
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800120 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700121 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800122 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700123 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800124 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700125 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
felipeala68ecef2020-05-19 12:46:08 -0700126 /**
127 * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
128 */
129 public static final String BUNDLE_USER_LOCALES =
130 CarUserServiceConstants.BUNDLE_USER_LOCALES;
131 /**
132 * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
133 */
felipeal1a9410d2020-05-06 13:30:05 -0700134 public static final String BUNDLE_INITIAL_INFO_ACTION =
135 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800136
Mayank Garg9ed099e2020-06-04 16:05:20 -0700137 public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
138
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700139 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700140 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700141 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700142 private final UserManager mUserManager;
143 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700144 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700145
Eric Jeongc91f9452019-08-30 15:04:21 -0700146 private final Object mLockUser = new Object();
147 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800148 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700149 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800150 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700151 // Only one passenger is supported.
152 @GuardedBy("mLockUser")
153 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700154 /**
155 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800156 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700157 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700158 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700159 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
160 /**
161 * Keep the list of background users started here. This is wholly for debugging purpose.
162 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700163 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700164 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
165
Felipe Leme58412202020-01-09 13:45:33 -0800166 private final UserHalService mHal;
167
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700168 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700169 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
170 getClass().getSimpleName());
171 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700172
Felipe Leme5528ff72020-02-10 19:05:14 -0800173 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800174 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700175 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800176 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700177 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800178
179 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800180 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700181 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800182 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700183 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800184
Mayank Garg7a114c82020-04-08 21:25:06 -0700185 /**
186 * User Id for the user switch in process, if any.
187 */
188 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700189 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700190 /**
191 * Request Id for the user switch in process, if any.
192 */
193 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700194 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700195 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
196
Eric Jeongc91f9452019-08-30 15:04:21 -0700197 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
198 new CopyOnWriteArrayList<>();
199
felipeal61ce3732020-04-03 11:01:00 -0700200 @Nullable
201 @GuardedBy("mLockUser")
202 private UserInfo mInitialUser;
203
Mayank Garg71661ea2020-04-29 01:25:03 -0700204 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700205
Mayank Garg587f1942020-05-06 01:41:34 -0700206 private IResultReceiver mUserSwitchUiReceiver;
207
Eric Jeongc91f9452019-08-30 15:04:21 -0700208 /** Interface for callbaks related to passenger activities. */
209 public interface PassengerCallback {
210 /** Called when passenger is started at a certain zone. */
211 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
212 /** Called when passenger is stopped. */
213 void onPassengerStopped(@UserIdInt int passengerId);
214 }
215
216 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
217 public interface ZoneUserBindingHelper {
218 /** Gets occupant zones corresponding to the occupant type. */
219 @NonNull
220 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
221 /** Assigns the user to the occupant zone. */
222 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
223 /** Makes the occupant zone unoccupied. */
224 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
225 /** Returns whether there is a passenger display. */
226 boolean isPassengerDisplayAvailable();
227 }
228
229 private final Object mLockHelper = new Object();
230 @GuardedBy("mLockHelper")
231 private ZoneUserBindingHelper mZoneUserBindingHelper;
232
Felipe Leme58412202020-01-09 13:45:33 -0800233 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700234 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
235 @NonNull IActivityManager am, int maxRunningUsers) {
236 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
237 new UserMetrics());
238 }
239
240 @VisibleForTesting
241 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
242 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
243 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700244 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
245 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700246 }
247 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800248 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700249 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700250 mAm = am;
251 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700252 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700253 mLastPassengerId = UserHandle.USER_NULL;
254 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700255 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700256 }
257
258 @Override
259 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700260 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
261 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700262 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700263 }
264
265 @Override
266 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700267 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
268 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700269 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700270 }
271
272 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700273 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700274 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700275 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800276 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700277 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700278 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700279 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700280 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700281 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
282 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700283 }
284 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
285 List<UserInfo> allDrivers = getAllDrivers();
286 int driversSize = allDrivers.size();
287 writer.println("NumberOfDrivers: " + driversSize);
288 for (int i = 0; i < driversSize; i++) {
289 int driverId = allDrivers.get(i).id;
290 writer.print(indent + "#" + i + ": id=" + driverId);
291 List<UserInfo> passengers = getPassengers(driverId);
292 int passengersSize = passengers.size();
293 writer.print(" NumberPassengers: " + passengersSize);
294 if (passengersSize > 0) {
295 writer.print(" [");
296 for (int j = 0; j < passengersSize; j++) {
297 writer.print(passengers.get(j).id);
298 if (j < passengersSize - 1) {
299 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700300 }
felipeal2d0483c2019-11-02 14:07:22 -0700301 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700302 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700303 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700304 writer.println();
305 }
306 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
307 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
308 writer.printf("Initial user: %s\n", mInitialUser);
felipealbf327652020-06-03 11:33:29 -0700309
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700310 writer.println("Relevant overlayable properties");
311 Resources res = mContext.getResources();
312 writer.printf("%sowner_name=%s\n", indent,
313 res.getString(com.android.internal.R.string.owner_name));
314 writer.printf("%sdefault_guest_name=%s\n", indent,
315 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700316 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700317 writer.printf("Request Id for the user switch in process=%d\n ",
318 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700319 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700320
felipealbf327652020-06-03 11:33:29 -0700321 writer.println("Relevant Global settings");
322 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
323 dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
324
felipeale8c5dce2020-04-15 11:27:06 -0700325 dumpUserMetrics(writer);
326 }
327
felipealbf327652020-06-03 11:33:29 -0700328 private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
329 String value = Settings.Global.getString(mContext.getContentResolver(), property);
330 writer.printf("%s%s=%s\n", indent, property, value);
331 }
332
felipeale8c5dce2020-04-15 11:27:06 -0700333 /**
334 * Dumps user metrics.
335 */
336 public void dumpUserMetrics(@NonNull PrintWriter writer) {
337 mUserMetrics.dump(writer);
338 }
339
340 /**
341 * Dumps first user unlocking time.
342 */
343 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
344 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700345 }
346
347 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
348 CountDownLatch latch = new CountDownLatch(1);
349 mHandler.post(() -> {
felipealde1e16d2020-06-03 13:20:48 -0700350 handleDumpServiceLifecycleListeners(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700351 handleDumpAppLifecycleListeners(writer, indent);
352 latch.countDown();
353 });
354 int timeout = 5;
355 try {
356 if (!latch.await(timeout, TimeUnit.SECONDS)) {
357 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
358 timeout);
359 }
360 } catch (InterruptedException e) {
361 Thread.currentThread().interrupt();
362 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
363 }
364 }
365
felipealde1e16d2020-06-03 13:20:48 -0700366 private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700367 if (mUserLifecycleListeners.isEmpty()) {
felipealde1e16d2020-06-03 13:20:48 -0700368 writer.println("No lifecycle listeners for internal services");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700369 return;
370 }
felipealde1e16d2020-06-03 13:20:48 -0700371 int size = mUserLifecycleListeners.size();
372 writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
373 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700374 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipealde1e16d2020-06-03 13:20:48 -0700375 writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700376 }
377 }
378
379 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
felipealde1e16d2020-06-03 13:20:48 -0700380 int size = mAppLifecycleListeners.size();
381 if (size == 0) {
382 writer.println("No lifecycle listeners for apps");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700383 return;
384 }
felipealde1e16d2020-06-03 13:20:48 -0700385 writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
386 for (int i = 0; i < size; i++) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700387 int uid = mAppLifecycleListeners.keyAt(i);
388 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
felipealde1e16d2020-06-03 13:20:48 -0700389 writer.printf("%suid: %d\n", indent, uid);
Keun-young Parkd462a912019-02-11 08:53:42 -0800390 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700391 }
392
393 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700394 * @see ExperimentalCarUserManager.createDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700395 */
396 @Override
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700397 public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700398 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000399 Objects.requireNonNull(name, "name cannot be null");
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700400
401 AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
402 @Override
403 protected void onCompleted(UserCreationResult result, Throwable err) {
404 if (result == null) {
405 Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
406 } else {
407 if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
408 assignDefaultIcon(result.getUser());
409 }
410 }
411 super.onCompleted(result, err);
412 };
413 };
414 int flags = 0;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700415 if (admin) {
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700416 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
417 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
418 sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
419 return future;
420 }
421 flags = UserInfo.FLAG_ADMIN;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700422 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700423 createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
424 return future;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700425 }
426
427 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700428 * @see ExperimentalCarUserManager.createPassenger
Eric Jeong1545f3b2019-09-16 13:56:52 -0700429 */
430 @Override
431 @Nullable
432 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
433 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000434 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700435 UserInfo driver = mUserManager.getUserInfo(driverId);
436 if (driver == null) {
437 Log.w(TAG_USER, "the driver is invalid");
438 return null;
439 }
440 if (driver.isGuest()) {
441 Log.w(TAG_USER, "a guest driver cannot create a passenger");
442 return null;
443 }
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700444 // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
Bookatz42fb1a62019-10-30 11:45:01 -0700445 UserInfo user = mUserManager.createProfileForUser(name,
446 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 if (user == null) {
448 // Couldn't create user, most likely because there are too many.
449 Log.w(TAG_USER, "can't create a profile for user" + driverId);
450 return null;
451 }
452 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700453 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700454 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700455 return user;
456 }
457
458 /**
Eric Jeongb2dc6ff2020-06-05 17:00:26 -0700459 * @see ExperimentalCarUserManager.switchDriver
Eric Jeong1545f3b2019-09-16 13:56:52 -0700460 */
461 @Override
Eric Jeong25666cf2020-05-14 15:16:27 -0700462 public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700463 checkManageUsersPermission("switchDriver");
Eric Jeong25666cf2020-05-14 15:16:27 -0700464 if (UserHelper.isHeadlessSystemUser(driverId)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700465 // System user doesn't associate with real person, can not be switched to.
466 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
felipealdfdf8512020-06-01 09:35:45 -0700467 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700468 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700469 }
470 int userSwitchable = mUserManager.getUserSwitchability();
471 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
472 Log.w(TAG_USER, "current process is not allowed to switch user");
felipealdfdf8512020-06-01 09:35:45 -0700473 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
Eric Jeong25666cf2020-05-14 15:16:27 -0700474 return;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700475 }
Eric Jeong25666cf2020-05-14 15:16:27 -0700476 switchUser(driverId, mHalTimeoutMs, receiver);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700477 }
478
479 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800480 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
481 *
482 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700483 */
484 @Override
485 @NonNull
486 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700487 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700488 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700489 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700490 }
491
492 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800493 * Returns all passengers under the given driver.
494 *
495 * @param driverId User id of a driver.
496 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700497 */
498 @Override
499 @NonNull
500 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700501 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700502 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700503 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
504 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700505 });
506 }
507
508 /**
509 * @see CarUserManager.startPassenger
510 */
511 @Override
512 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
513 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700514 synchronized (mLockUser) {
515 try {
516 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
517 Log.w(TAG_USER, "could not start passenger");
518 return false;
519 }
520 } catch (RemoteException e) {
521 // ignore
522 Log.w(TAG_USER, "error while starting passenger", e);
523 return false;
524 }
525 if (!assignUserToOccupantZone(passengerId, zoneId)) {
526 Log.w(TAG_USER, "could not assign passenger to zone");
527 return false;
528 }
529 mLastPassengerId = passengerId;
530 }
531 for (PassengerCallback callback : mPassengerCallbacks) {
532 callback.onPassengerStarted(passengerId, zoneId);
533 }
534 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700535 }
536
537 /**
538 * @see CarUserManager.stopPassenger
539 */
540 @Override
541 public boolean stopPassenger(@UserIdInt int passengerId) {
542 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700543 return stopPassengerInternal(passengerId, true);
544 }
545
546 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
547 synchronized (mLockUser) {
548 UserInfo passenger = mUserManager.getUserInfo(passengerId);
549 if (passenger == null) {
550 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
551 return false;
552 }
553 if (mLastPassengerId != passengerId) {
554 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
555 return true;
556 }
557 if (checkCurrentDriver) {
558 int currentUser = ActivityManager.getCurrentUser();
559 if (passenger.profileGroupId != currentUser) {
560 Log.w(TAG_USER, "passenger " + passengerId
561 + " is not a profile of the current user");
562 return false;
563 }
564 }
565 // Passenger is a profile, so cannot be stopped through activity manager.
566 // Instead, activities started by the passenger are stopped and the passenger is
567 // unassigned from the zone.
568 stopAllTasks(passengerId);
569 if (!unassignUserFromOccupantZone(passengerId)) {
570 Log.w(TAG_USER, "could not unassign user from occupant zone");
571 return false;
572 }
573 mLastPassengerId = UserHandle.USER_NULL;
574 }
575 for (PassengerCallback callback : mPassengerCallbacks) {
576 callback.onPassengerStopped(passengerId);
577 }
578 return true;
579 }
580
581 private void stopAllTasks(@UserIdInt int userId) {
582 try {
583 for (StackInfo info : mAm.getAllStackInfos()) {
584 for (int i = 0; i < info.taskIds.length; i++) {
585 if (info.taskUserIds[i] == userId) {
586 int taskId = info.taskIds[i];
587 if (!mAm.removeTask(taskId)) {
588 Log.w(TAG_USER, "could not remove task " + taskId);
589 }
590 }
591 }
592 }
593 } catch (RemoteException e) {
594 Log.e(TAG_USER, "could not get stack info", e);
595 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700596 }
597
Felipe Leme5528ff72020-02-10 19:05:14 -0800598 @Override
599 public void setLifecycleListenerForUid(IResultReceiver listener) {
600 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700601 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800602 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
603
604 try {
605 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
606 } catch (RemoteException e) {
607 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
608 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700609 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800610 }
611
612 private void onListenerDeath(int uid) {
613 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700614 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800615 }
616
617 @Override
618 public void resetLifecycleListenerForUid() {
619 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700620 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800621 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700622 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800623 }
624
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800625 @Override
626 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800627 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700628 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
629 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800630 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700631 checkManageUsersPermission("getInitialInfo");
Mayank Garg9ed099e2020-06-04 16:05:20 -0700632 if (!isUserHalSupported()) {
633 sendResult(receiver, HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
634 return;
635 }
felipealdfdf8512020-06-01 09:35:45 -0700636 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800637 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700638 Bundle resultData = null;
639 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700640 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
641 status, resp.action, resp.userToSwitchOrCreate.userId,
felipeala68ecef2020-05-19 12:46:08 -0700642 resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
Mayank Garg0e239142020-04-14 19:16:31 -0700643 switch (resp.action) {
644 case InitialUserInfoResponseAction.SWITCH:
645 resultData = new Bundle();
646 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
647 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
648 break;
649 case InitialUserInfoResponseAction.CREATE:
650 resultData = new Bundle();
651 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
652 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
653 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
654 break;
655 case InitialUserInfoResponseAction.DEFAULT:
656 resultData = new Bundle();
657 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
658 break;
659 default:
660 // That's ok, it will be the same as DEFAULT...
661 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800662 }
felipeal312416a2020-04-14 12:28:24 -0700663 } else {
664 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800665 }
felipeala68ecef2020-05-19 12:46:08 -0700666 if (resultData != null && !TextUtils.isEmpty(resp.userLocales)) {
667 resultData.putString(BUNDLE_USER_LOCALES, resp.userLocales);
668 }
669
Mayank Garg0e239142020-04-14 19:16:31 -0700670 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800671 });
672 }
673
Felipe Lemee3cab982020-03-12 11:39:29 -0700674 /**
felipeal61ce3732020-04-03 11:01:00 -0700675 * Gets the initial foreground user after the device boots or resumes from suspension.
676 *
677 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
678 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
679 * method returns {@code null}.
680 *
681 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
682 * (like switching to the last active user), and this method will return the result of such
683 * operation.
684 *
685 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
686 * {@code null}.
687 *
688 * @hide
689 */
690 @Nullable
691 public UserInfo getInitialUser() {
692 checkInteractAcrossUsersPermission("getInitialUser");
693 synchronized (mLockUser) {
694 return mInitialUser;
695 }
696 }
697
698 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
699 // some reason passing the whole UserInfo through a raw binder transaction is not working.
700 /**
701 * Sets the initial foreground user after the device boots or resumes from suspension.
702 */
703 public void setInitialUser(@UserIdInt int userId) {
704 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
705 : mUserManager.getUserInfo(userId);
706 setInitialUser(initialUser);
707 }
708
709 /**
710 * Sets the initial foreground user after the device boots or resumes from suspension.
711 */
712 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700713 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
714 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700715 synchronized (mLockUser) {
716 mInitialUser = user;
717 }
718 if (user == null) {
719 // This mean InitialUserSetter failed and could not fallback, so the initial user was
720 // not switched (and most likely is SYSTEM_USER).
721 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
722 Log.wtf(TAG_USER, "Initial user set to null");
723 }
724 }
725
726 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700727 * Calls the User HAL to get the initial user info.
728 *
729 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
730 * @param callback callback to receive the results.
731 */
732 public void getInitialUserInfo(int requestType,
733 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700734 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
735 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700736 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700737 checkManageUsersPermission("getInitialUserInfo");
Mayank Garg9ed099e2020-06-04 16:05:20 -0700738 if (!isUserHalSupported()) {
739 callback.onResponse(HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
740 return;
741 }
felipealdfdf8512020-06-01 09:35:45 -0700742 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Felipe Lemee3cab982020-03-12 11:39:29 -0700743 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
744 }
745
746 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700747 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
748 *
749 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700750 * When everything works well, the workflow is:
751 * <ol>
752 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
753 * type, current user id, target user id, and a callback.
754 * <li> HAL called back with SUCCESS.
755 * <li> {@link IActivityManager} is called for Android user switch.
756 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
757 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
758 * request type, current user id, and target user id. In this case, the current and target
759 * user IDs would be same.
760 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700761 *
762 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700763 * Corner cases:
764 * <ul>
765 * <li> If target user is already the current user, no user switch is performed and receiver
Mayank Gargef1b9332020-06-11 17:36:56 -0700766 * would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
Mayank Gargb08f6772020-05-01 18:06:48 -0700767 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
768 * {@code STATUS_HAL_INTERNAL_FAILURE}.
769 * <li> If HAL user switch call is successful, but android user switch call fails,
770 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
771 * target user id, but in this case the current and target user IDs would be different.
772 * <li> If another user switch request for the same target user is received while previous
773 * request is in process, receiver would receive
774 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
775 * <li> If a user switch request is received while another user switch request for different
776 * target user is in process, the previous request would be abandoned and new request will be
777 * processed. No POST_SWITCH would be sent for the previous request.
778 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700779 *
Mayank Garge19c2922020-03-30 18:05:53 -0700780 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700781 * @param timeoutMs - timeout for HAL to wait
782 * @param receiver - receiver for the results
783 */
Mayank Garge19c2922020-03-30 18:05:53 -0700784 @Override
785 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700786 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700787 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700788 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700789 Objects.requireNonNull(receiver);
790 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700791 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700792
felipealf7368962020-04-16 12:55:19 -0700793 int currentUser = ActivityManager.getCurrentUser();
794 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700795 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
796 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
797 }
Mayank Gargef1b9332020-06-11 17:36:56 -0700798 int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
felipealdfdf8512020-06-01 09:35:45 -0700799 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700800 return;
801 }
802
Mayank Garg9ed099e2020-06-04 16:05:20 -0700803 // If User Hal is not supported, just android user switch.
804 if (!isUserHalSupported()) {
805 try {
806 if (mAm.switchUser(targetUserId)) {
807 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
808 return;
809 }
810 } catch (RemoteException e) {
811 // ignore
812 Log.w(TAG_USER,
813 "error while switching user " + targetUser.toFullString(), e);
814 }
815 sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
816 return;
817 }
818
Mayank Garg7a114c82020-04-08 21:25:06 -0700819 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700820 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
821 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
822 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
823 }
824
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700825 // If there is another request for the same target user, return another request in
826 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
827 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
828 // user switch request in process for different target user, but that request is now
829 // ignored.
felipealf7368962020-04-16 12:55:19 -0700830 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700831 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
832 Log.d(TAG_USER,
833 "Another user switch request in process for the requested target user: "
834 + targetUserId);
835 }
836
837 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipealdfdf8512020-06-01 09:35:45 -0700838 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700839 return;
840 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700841 else {
842 mUserIdForUserSwitchInProcess = targetUserId;
843 mRequestIdForUserSwitchInProcess = 0;
844 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700845 }
846
felipealdfdf8512020-06-01 09:35:45 -0700847 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -0700848 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
849
850 mHal.switchUser(request, timeoutMs, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700851 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
852 Log.d(TAG, "switch response: status="
853 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
854 }
855
felipeale5bf0322020-04-16 15:10:57 -0700856 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700857
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700858 synchronized (mLockUser) {
859 if (status != HalCallback.STATUS_OK) {
860 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
861 Log.w(TAG, "invalid callback status ("
862 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
863 + resp);
felipealdfdf8512020-06-01 09:35:45 -0700864 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700865 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
866 return;
867 }
felipealf7368962020-04-16 12:55:19 -0700868
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700869 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
870 resp.errorMessage);
871
872 if (mUserIdForUserSwitchInProcess != targetUserId) {
873 // Another user switch request received while HAL responded. No need to process
874 // this request further
875 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
876 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
877 + "abondoned for : " + targetUserId + ". Current user in process: "
878 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700879 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700880 resultStatus =
881 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
felipealdfdf8512020-06-01 09:35:45 -0700882 sendUserSwitchResult(receiver, resultStatus);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700883 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
884 return;
885 }
886
887 switch (resp.status) {
888 case SwitchUserStatus.SUCCESS:
889 boolean switched;
890 try {
891 switched = mAm.switchUser(targetUserId);
892 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700893 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700894 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
895 mRequestIdForUserSwitchInProcess = resp.requestId;
896 } else {
897 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
898 postSwitchHalResponse(resp.requestId, targetUserId);
899 }
900 } catch (RemoteException e) {
901 // ignore
902 Log.w(TAG_USER,
903 "error while switching user " + targetUser.toFullString(), e);
904 }
905 break;
906 case SwitchUserStatus.FAILURE:
907 // HAL failed to switch user
908 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
909 break;
felipealdfdf8512020-06-01 09:35:45 -0700910 default:
911 // Shouldn't happen because UserHalService validates the status
912 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700913 }
914
915 if (mRequestIdForUserSwitchInProcess == 0) {
916 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
917 }
Mayank Garg59f22192020-03-27 00:51:45 -0700918 }
felipealdfdf8512020-06-01 09:35:45 -0700919 sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700920 });
921 }
922
Mayank Garga55c3092020-05-28 03:19:24 -0700923 @Override
924 public UserRemovalResult removeUser(@UserIdInt int userId) {
925 checkManageUsersPermission("removeUser");
926 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
927 // If the requested user is the current user, return error.
928 if (ActivityManager.getCurrentUser() == userId) {
929 return logAndGetResults(userId,
930 UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
931 }
932
933 // If requested user is the only admin user, return error.
934 UserInfo userInfo = mUserManager.getUserInfo(userId);
935 if (userInfo == null) {
936 return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
937 }
938
939 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
940 new android.hardware.automotive.vehicle.V2_0.UserInfo();
941 halUser.userId = userInfo.id;
942 halUser.flags = UserHalHelper.convertFlags(userInfo);
943 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
944
945 // Do not delete last admin user.
946 if (UserHalHelper.isAdmin(halUser.flags)) {
947 int size = usersInfo.existingUsers.size();
948 int totalAdminUsers = 0;
949 for (int i = 0; i < size; i++) {
950 if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
951 totalAdminUsers++;
952 }
953 }
954 if (totalAdminUsers == 1) {
955 return logAndGetResults(userId,
956 UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
957 }
958 }
959
960 // First remove user from android and then remove from HAL because HAL remove user is one
961 // way call.
962 if (!mUserManager.removeUser(userId)) {
963 return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
964 }
965
Mayank Garg9ed099e2020-06-04 16:05:20 -0700966 if (isUserHalSupported()) {
967 RemoveUserRequest request = new RemoveUserRequest();
968 request.removedUserInfo = halUser;
969 request.usersInfo = usersInfo;
970 mHal.removeUser(request);
971 }
972
Mayank Garga55c3092020-05-28 03:19:24 -0700973 return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
974 }
975
976 private UserRemovalResult logAndGetResults(@UserIdInt int userId,
977 @UserRemovalResult.Status int result) {
978 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
979 return new UserRemovalResult(result);
980 }
981
Mayank Garg587f1942020-05-06 01:41:34 -0700982 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
983 if (mUserSwitchUiReceiver == null) {
984 Log.w(TAG_USER, "No User switch UI receiver.");
985 return;
986 }
987
felipealdfdf8512020-06-01 09:35:45 -0700988 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
Mayank Garg587f1942020-05-06 01:41:34 -0700989 try {
Mayank Garg587f1942020-05-06 01:41:34 -0700990 mUserSwitchUiReceiver.send(targetUserId, null);
991 } catch (RemoteException e) {
992 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
993 }
994 }
995
felipeal5e3ede42020-04-23 18:04:07 -0700996 @Override
felipealdfdf8512020-06-01 09:35:45 -0700997 public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
998 int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
999 Objects.requireNonNull(userType, "user type cannot be null");
1000 Objects.requireNonNull(receiver, "receiver cannot be null");
1001 checkManageOrCreateUsersPermission("createUser");
1002 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
1003 userType, flags, timeoutMs);
1004
1005 UserInfo newUser;
1006 try {
1007 newUser = mUserManager.createUser(name, userType, flags);
1008 if (newUser == null) {
1009 Log.w(TAG, "um.createUser() returned null for user of type " + userType
1010 + " and flags " + UserInfo.flagsToString(flags));
1011 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1012 return;
1013 }
1014 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1015 Log.d(TAG, "Created user: " + newUser.toFullString());
1016 }
1017 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
1018 UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
1019 } catch (RuntimeException e) {
1020 Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
1021 + UserInfo.flagsToString(flags), e);
1022 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
1023 return;
1024 }
1025
Mayank Garg9ed099e2020-06-04 16:05:20 -07001026 if (!isUserHalSupported()) {
1027 sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
1028 return;
1029 }
1030
felipealdfdf8512020-06-01 09:35:45 -07001031 CreateUserRequest request = new CreateUserRequest();
1032 request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
1033 if (!TextUtils.isEmpty(name)) {
1034 request.newUserName = name;
1035 }
1036 request.newUserInfo.userId = newUser.id;
1037 request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
1038 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1039 Log.d(TAG, "Create user request: " + request);
1040 }
1041
1042 try {
1043 mHal.createUser(request, timeoutMs, (status, resp) -> {
1044 int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
1045 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1046 Log.d(TAG, "createUserResponse: status="
1047 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
1048 }
1049 UserInfo user = null; // user returned in the result
1050 if (status != HalCallback.STATUS_OK) {
1051 Log.w(TAG, "invalid callback status ("
1052 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1053 + resp);
1054 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1055 resultStatus, resp.errorMessage);
1056 removeUser(newUser, "HAL call failed with "
1057 + UserHalHelper.halCallbackStatusToString(status));
1058 sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
1059 return;
1060 }
1061
1062 switch (resp.status) {
1063 case CreateUserStatus.SUCCESS:
1064 resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
1065 user = newUser;
1066 break;
1067 case CreateUserStatus.FAILURE:
1068 // HAL failed to switch user
1069 resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
1070 break;
1071 default:
1072 // Shouldn't happen because UserHalService validates the status
1073 Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
1074 }
1075 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
1076 resultStatus, resp.errorMessage);
1077 if (user == null) {
1078 removeUser(newUser, "HAL returned "
1079 + UserCreationResult.statusToString(resultStatus));
1080 }
1081 sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
1082 });
1083 } catch (Exception e) {
1084 Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
1085 removeUser(newUser, "mHal.createUser() failed");
1086 sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
1087 }
1088 }
1089
1090 private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
1091 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
1092 try {
1093 if (!mUserManager.removeUser(user.id)) {
1094 Log.w(TAG, "Failed to remove user " + user.toFullString());
1095 }
1096 } catch (Exception e) {
1097 Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
1098 }
1099 }
1100
1101 @Override
felipeal159a2a42020-05-08 10:32:11 -07001102 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001103 if (!isUserHalUserAssociationSupported()) {
1104 return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
1105 }
1106
felipeal5e3ede42020-04-23 18:04:07 -07001107 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1108 checkManageUsersPermission("getUserIdentificationAssociation");
1109
1110 int uid = getCallingUid();
1111 int userId = UserHandle.getUserId(uid);
1112 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
1113
1114 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
1115 request.userInfo.userId = userId;
1116 request.userInfo.flags = getHalUserInfoFlags(userId);
1117
1118 request.numberAssociationTypes = types.length;
1119 for (int i = 0; i < types.length; i++) {
1120 request.associationTypes.add(types[i]);
1121 }
1122
1123 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
1124 if (halResponse == null) {
1125 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
1126 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -07001127 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -07001128 }
1129
1130 int[] values = new int[halResponse.associations.size()];
1131 for (int i = 0; i < values.length; i++) {
1132 values[i] = halResponse.associations.get(i).value;
1133 }
1134 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
1135
felipeal159a2a42020-05-08 10:32:11 -07001136 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
1137 }
1138
1139 @Override
1140 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
1141 AndroidFuture<UserIdentificationAssociationResponse> result) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001142 if (!isUserHalUserAssociationSupported()) {
1143 result.complete(
1144 UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
1145 return;
1146 }
1147
felipeal159a2a42020-05-08 10:32:11 -07001148 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
1149 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
1150 if (types.length != values.length) {
1151 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
1152 + Arrays.toString(values) + ") should have the same length");
1153 }
1154 checkManageUsersPermission("setUserIdentificationAssociation");
1155
1156 int uid = getCallingUid();
1157 int userId = UserHandle.getUserId(uid);
1158 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
1159
1160 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
1161 request.userInfo.userId = userId;
1162 request.userInfo.flags = getHalUserInfoFlags(userId);
1163
1164 request.numberAssociations = types.length;
1165 for (int i = 0; i < types.length; i++) {
1166 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
1167 association.type = types[i];
1168 association.value = values[i];
1169 request.associations.add(association);
1170 }
1171
1172 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
1173 if (status != HalCallback.STATUS_OK) {
1174 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
1175 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
1176 + resp);
1177 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
1178 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
1179 result.complete(UserIdentificationAssociationResponse.forFailure());
1180 return;
1181 }
1182 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
1183 resp.errorMessage);
1184 result.complete(
1185 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
1186 return;
1187 }
1188 int respSize = resp.associations.size();
1189 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
1190 resp.errorMessage);
1191
1192 int[] responseTypes = new int[respSize];
1193 for (int i = 0; i < respSize; i++) {
1194 responseTypes[i] = resp.associations.get(i).value;
1195 }
1196 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
1197 .forSuccess(responseTypes, resp.errorMessage);
1198 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1199 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
1200 + ", converted=" + response);
1201 }
1202 result.complete(response);
1203 });
felipeal5e3ede42020-04-23 18:04:07 -07001204 }
1205
1206 /**
1207 * Gets the User HAL flags for the given user.
1208 *
1209 * @throws IllegalArgumentException if the user does not exist.
1210 */
1211 private int getHalUserInfoFlags(@UserIdInt int userId) {
1212 UserInfo user = mUserManager.getUserInfo(userId);
1213 Preconditions.checkArgument(user != null, "no user for id %d", userId);
1214 return UserHalHelper.convertFlags(user);
1215 }
1216
Mayank Garg0e239142020-04-14 19:16:31 -07001217 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
1218 @Nullable Bundle resultData) {
1219 try {
1220 receiver.send(resultCode, resultData);
1221 } catch (RemoteException e) {
1222 // ignore
1223 Log.w(TAG_USER, "error while sending results", e);
1224 }
1225 }
1226
felipealdfdf8512020-06-01 09:35:45 -07001227 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001228 @UserSwitchResult.Status int status) {
felipealdfdf8512020-06-01 09:35:45 -07001229 sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
felipeale5bf0322020-04-16 15:10:57 -07001230 }
1231
felipealdfdf8512020-06-01 09:35:45 -07001232 private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
felipeale5bf0322020-04-16 15:10:57 -07001233 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1234 receiver.complete(new UserSwitchResult(status, errorMessage));
1235 }
1236
felipealdfdf8512020-06-01 09:35:45 -07001237 private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
1238 @UserCreationResult.Status int status) {
1239 sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
1240 }
1241
1242 private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
1243 @UserCreationResult.Status int status, @NonNull UserInfo user,
1244 @Nullable String errorMessage) {
1245 if (TextUtils.isEmpty(errorMessage)) {
1246 errorMessage = null;
1247 }
1248 receiver.complete(new UserCreationResult(status, user, errorMessage));
1249 }
1250
Mayank Garg6307fe42020-04-15 23:09:03 -07001251 /**
1252 * Calls activity manager for user switch.
1253 *
1254 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1255 *
1256 * @param requestId for the user switch request
1257 * @param targetUserId of the target user
1258 *
1259 * @hide
1260 */
1261 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1262 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1263 targetUserId);
1264 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1265
1266 try {
1267 boolean result = mAm.switchUser(targetUserId);
1268 if (result) {
1269 updateUserSwitchInProcess(requestId, targetUserId);
1270 } else {
1271 postSwitchHalResponse(requestId, targetUserId);
1272 }
1273 } catch (RemoteException e) {
1274 // ignore
1275 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1276 }
1277 }
1278
1279 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1280 synchronized (mLockUser) {
1281 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1282 // Some other user switch is in process.
1283 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1284 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1285 + " is in process. Abandoning it as a new user switch is requested"
1286 + " for the target user: " + targetUserId);
1287 }
1288 }
1289 mUserIdForUserSwitchInProcess = targetUserId;
1290 mRequestIdForUserSwitchInProcess = requestId;
1291 }
1292 }
Mayank Garg9ed099e2020-06-04 16:05:20 -07001293
Mayank Garg7a114c82020-04-08 21:25:06 -07001294 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
Mayank Garg9ed099e2020-06-04 16:05:20 -07001295 if (!isUserHalSupported()) return;
1296
felipealdfdf8512020-06-01 09:35:45 -07001297 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
Mayank Gargeb37d092020-06-02 14:37:57 -07001298 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1299 targetUserId, usersInfo.currentUser.userId);
1300 SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
1301 request.requestId = requestId;
1302 mHal.postSwitchResponse(request);
1303 }
1304
1305 private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
1306 @NonNull UsersInfo usersInfo) {
1307 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001308 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1309 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1310 halTargetUser.userId = targetUser.id;
1311 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
Mayank Gargeb37d092020-06-02 14:37:57 -07001312 SwitchUserRequest request = new SwitchUserRequest();
1313 request.targetUser = halTargetUser;
1314 request.usersInfo = usersInfo;
1315 return request;
Mayank Garg7a114c82020-04-08 21:25:06 -07001316 }
1317
Mayank Garg59f22192020-03-27 00:51:45 -07001318 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001319 * Checks if the User HAL is supported.
1320 */
1321 public boolean isUserHalSupported() {
1322 return mHal.isSupported();
1323 }
1324
Mayank Garg587f1942020-05-06 01:41:34 -07001325 /**
Mayank Garg9ed099e2020-06-04 16:05:20 -07001326 * Checks if the User HAL user association is supported.
1327 */
1328 @Override
1329 public boolean isUserHalUserAssociationSupported() {
1330 return mHal.isUserAssociationSupported();
1331 }
1332
1333 /**
Mayank Garg587f1942020-05-06 01:41:34 -07001334 * Sets a callback which is invoked before user switch.
1335 *
1336 * <p>
1337 * This method should only be called by the Car System UI. The purpose of this call is to notify
1338 * Car System UI to show the user switch UI before the user switch.
1339 */
1340 @Override
1341 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001342 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001343
1344 // Confirm that caller is system UI.
1345 String systemUiPackageName = getSystemUiPackageName();
1346 if (systemUiPackageName == null) {
1347 throw new IllegalStateException("System UI package not found.");
1348 }
1349
1350 try {
1351 int systemUiUid = mContext
1352 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1353 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1354 int callerUid = Binder.getCallingUid();
1355 if (systemUiUid != callerUid) {
1356 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1357 + " is allowed to make this call");
1358 }
1359 } catch (NameNotFoundException e) {
1360 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1361 }
1362
Mayank Garg587f1942020-05-06 01:41:34 -07001363 mUserSwitchUiReceiver = receiver;
1364 }
1365
Mayank Garga480dd92020-05-14 03:14:57 -07001366 // TODO(157082995): This information can be taken from
1367 // PackageManageInternalImpl.getSystemUiServiceComponent
1368 @Nullable
1369 private String getSystemUiPackageName() {
1370 try {
1371 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1372 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1373 return componentName.getPackageName();
1374 } catch (RuntimeException e) {
1375 Log.w(TAG_USER, "error while getting system UI package name.", e);
1376 return null;
1377 }
1378 }
1379
Keun young Park13a7a822019-04-04 15:53:08 -07001380 private void updateDefaultUserRestriction() {
1381 // We want to set restrictions on system and guest users only once. These are persisted
1382 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1383 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001384 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1385 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001386 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001387 // Only apply the system user restrictions if the system user is headless.
1388 if (UserManager.isHeadlessSystemUserMode()) {
1389 setSystemUserRestrictions();
1390 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001391 Settings.Global.putInt(mContext.getContentResolver(),
1392 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001393 }
1394
Eric Jeong1545f3b2019-09-16 13:56:52 -07001395 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001396 return !mUserManager.getUserInfo(userId).isEphemeral();
1397 }
1398
Antonio Kantekc8114752020-03-05 21:37:39 -08001399 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001400 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1401 */
1402 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1403 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001404 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001405 }
1406
1407 /**
1408 * Removes previously added {@link UserLifecycleListener}.
1409 */
1410 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1411 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001412 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001413 }
1414
Eric Jeongc91f9452019-08-30 15:04:21 -07001415 /** Adds callback to listen to passenger activity events. */
1416 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001417 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001418 mPassengerCallbacks.add(callback);
1419 }
1420
1421 /** Removes previously added callback to listen passenger events. */
1422 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001423 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001424 mPassengerCallbacks.remove(callback);
1425 }
1426
1427 /** Sets the implementation of ZoneUserBindingHelper. */
1428 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1429 synchronized (mLockHelper) {
1430 mZoneUserBindingHelper = helper;
1431 }
1432 }
1433
felipeal98900c82020-04-09 09:05:02 -07001434 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001435 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001436 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001437 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001438 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001439 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1440 updateDefaultUserRestriction();
1441 tasks = new ArrayList<>(mUser0UnlockTasks);
1442 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001443 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001444 }
1445 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001446 Integer user = userId;
1447 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001448 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001449 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001450 mBackgroundUsersToRestart.remove(user);
1451 mBackgroundUsersToRestart.add(0, user);
1452 }
1453 // -1 for user 0
1454 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001455 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001456 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001457 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001458 + ", dropping least recently user from restart list:" + userToDrop);
1459 // Drop the least recently used user.
1460 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1461 }
1462 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001463 }
1464 }
1465 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001466 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001467 for (Runnable r : tasks) {
1468 r.run();
1469 }
1470 }
1471 }
1472
1473 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001474 * Starts all background users that were active in system.
1475 *
Keun young Parkfb656372019-03-12 18:37:55 -07001476 * @return list of background users started successfully.
1477 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001478 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001479 public ArrayList<Integer> startAllBackgroundUsers() {
1480 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001481 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001482 users = new ArrayList<>(mBackgroundUsersToRestart);
1483 mBackgroundUsersRestartedHere.clear();
1484 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001485 }
1486 ArrayList<Integer> startedUsers = new ArrayList<>();
1487 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001488 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001489 continue;
1490 }
1491 try {
1492 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001493 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1494 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001495 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001496 } else if (mAm.unlockUser(user, null, null, null)) {
1497 startedUsers.add(user);
1498 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001499 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001500 if (mUserManager.isUserRunning(user)) {
1501 // add to started list so that it can be stopped later.
1502 startedUsers.add(user);
1503 }
Keun young Parkfb656372019-03-12 18:37:55 -07001504 }
1505 }
1506 } catch (RemoteException e) {
1507 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001508 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001509 }
1510 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001511 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001512 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001513 ArrayList<Integer> usersToRemove = new ArrayList<>();
1514 for (Integer user : mBackgroundUsersToRestart) {
1515 if (!startedUsers.contains(user)) {
1516 usersToRemove.add(user);
1517 }
1518 }
1519 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1520 }
Keun young Parkfb656372019-03-12 18:37:55 -07001521 return startedUsers;
1522 }
1523
1524 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001525 * Stops all background users that were active in system.
1526 *
1527 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001528 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001529 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001530 if (userId == UserHandle.USER_SYSTEM) {
1531 return false;
1532 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001533 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001534 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001535 return false;
1536 }
1537 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001538 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001539 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001540 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001541 Integer user = userId;
1542 mBackgroundUsersRestartedHere.remove(user);
1543 }
1544 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1545 return false;
1546 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001547 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001548 return false;
1549 }
1550 } catch (RemoteException e) {
1551 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001552 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001553 }
1554 return true;
1555 }
1556
1557 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001558 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001559 */
felipeale8c5dce2020-04-15 11:27:06 -07001560 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1561 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1562 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001563
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001564 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001565 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001566 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001567 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1568 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001569 }
1570
felipeale8c5dce2020-04-15 11:27:06 -07001571 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001572 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001573
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001574 mHandler.post(() -> {
1575 handleNotifyServiceUserLifecycleListeners(event);
1576 handleNotifyAppUserLifecycleListeners(event);
1577 });
felipeale8c5dce2020-04-15 11:27:06 -07001578
Keun young Park1fced442020-05-29 09:26:29 -07001579 if (timestampMs != 0) {
1580 // Finally, update metrics.
1581 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1582 }
felipeale8c5dce2020-04-15 11:27:06 -07001583 }
1584
1585 /**
1586 * Sets the first user unlocking metrics.
1587 */
1588 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1589 int halResponseTime) {
1590 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001591 }
1592
Mayank Garg7a114c82020-04-08 21:25:06 -07001593 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001594 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001595 || mUserIdForUserSwitchInProcess != userId
1596 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001597 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1598 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1599 }
1600 return;
1601 }
felipealf7368962020-04-16 12:55:19 -07001602 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1603 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001604 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001605 }
1606
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001607 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1608 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001609 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001610 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1611 Log.d(TAG_USER, "No app listener to be notified of " + event);
1612 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001613 return;
1614 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001615 // Must use a different TimingsTraceLog because it's another thread
1616 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1617 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1618 }
felipeal2a84d512020-04-06 18:52:15 -07001619 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001620 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipealde1e16d2020-06-03 13:20:48 -07001621 int eventType = event.getEventType();
1622 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001623 for (int i = 0; i < listenersSize; i++) {
1624 int uid = mAppLifecycleListeners.keyAt(i);
felipealde1e16d2020-06-03 13:20:48 -07001625
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001626 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1627 Bundle data = new Bundle();
felipealde1e16d2020-06-03 13:20:48 -07001628 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
Yan Zhue7921522020-04-16 15:59:25 -07001629
felipealde1e16d2020-06-03 13:20:48 -07001630 int fromUserId = event.getPreviousUserId();
1631 if (fromUserId != UserHandle.USER_NULL) {
1632 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
Yan Zhue7921522020-04-16 15:59:25 -07001633 }
1634
felipeal2a84d512020-04-06 18:52:15 -07001635 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001636 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001637 }
felipealde1e16d2020-06-03 13:20:48 -07001638 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
1639 uid, eventType, fromUserId, userId);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001640 try {
felipealde1e16d2020-06-03 13:20:48 -07001641 t.traceBegin("notify-app-listener-uid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001642 listener.send(userId, data);
1643 } catch (RemoteException e) {
1644 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1645 } finally {
1646 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001647 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001648 }
1649 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001650 }
1651
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001652 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001653 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1654 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001655 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001656 return;
felipeal2a84d512020-04-06 18:52:15 -07001657 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1658 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1659 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001660 }
felipeal2a84d512020-04-06 18:52:15 -07001661
felipealde1e16d2020-06-03 13:20:48 -07001662 int userId = event.getUserId();
1663 int eventType = event.getEventType();
1664 t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001665 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001666 String listenerName = FunctionalUtils.getLambdaName(listener);
felipealde1e16d2020-06-03 13:20:48 -07001667 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
1668 listenerName, eventType, event.getPreviousUserId(), userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001669 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001670 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001671 listener.onEvent(event);
1672 } catch (RuntimeException e) {
1673 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001674 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001675 } finally {
1676 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001677 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001678 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001679 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001680 }
1681
Mayank Garge5de0f92020-04-23 21:38:38 -07001682 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001683 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001684 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001685 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001686
Mayank Garge5de0f92020-04-23 21:38:38 -07001687 // Switch HAL users if user switch is not requested by CarUserService
1688 notifyHalLegacySwitch(fromUserId, toUserId);
1689
felipealbf327652020-06-03 11:33:29 -07001690 mCarUserManagerHelper.setLastActiveUser(toUserId);
1691
Eric Jeongc91f9452019-08-30 15:04:21 -07001692 if (mLastPassengerId != UserHandle.USER_NULL) {
1693 stopPassengerInternal(mLastPassengerId, false);
1694 }
1695 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1696 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001697 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001698 }
felipeal98900c82020-04-09 09:05:02 -07001699 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001700 }
1701
Mayank Garge5de0f92020-04-23 21:38:38 -07001702 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1703 synchronized (mLockUser) {
felipeal7d12ee22020-06-05 09:30:19 -07001704 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1705 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1706 Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
1707 + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
1708 }
1709 return;
1710 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001711 }
1712
Mayank Garg9ed099e2020-06-04 16:05:20 -07001713 if (!isUserHalSupported()) return;
1714
Mayank Garge5de0f92020-04-23 21:38:38 -07001715 // switch HAL user
felipeal7d12ee22020-06-05 09:30:19 -07001716 UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
Mayank Gargeb37d092020-06-02 14:37:57 -07001717 SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
1718 mHal.legacyUserSwitch(request);
Mayank Garge5de0f92020-04-23 21:38:38 -07001719 }
1720
Pavel Maltsev17e81832019-04-04 14:38:41 -07001721 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001722 * 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 -08001723 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001724 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001725 * @param r Runnable to run.
1726 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001727 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001728 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001729 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001730 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001731 if (mUser0Unlocked) {
1732 runNow = true;
1733 } else {
1734 mUser0UnlockTasks.add(r);
1735 }
1736 }
1737 if (runNow) {
1738 r.run();
1739 }
1740 }
1741
Keun young Parkf3523cd2019-04-08 10:09:17 -07001742 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001743 @NonNull
1744 ArrayList<Integer> getBackgroundUsersToRestart() {
1745 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001746 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001747 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1748 }
1749 return backgroundUsersToRestart;
1750 }
1751
Ying Zheng1ab32b62018-06-26 12:47:26 -07001752 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001753 // Disable Location service for system user.
1754 LocationManager locationManager =
1755 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001756 locationManager.setLocationEnabledForUser(
1757 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001758 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001759
1760 /**
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001761 * Assigns a default icon to a user according to the user's id.
1762 *
1763 * @param userInfo User whose avatar is set to default icon.
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001764 */
Eric Jeongb2dc6ff2020-06-05 17:00:26 -07001765 private void assignDefaultIcon(UserInfo userInfo) {
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001766 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1767 Bitmap bitmap = UserIcons.convertToBitmap(
1768 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1769 mUserManager.setUserIcon(userInfo.id, bitmap);
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001770 }
1771
Eric Jeong1545f3b2019-09-16 13:56:52 -07001772 private interface UserFilter {
1773 boolean isEligibleUser(UserInfo user);
1774 }
1775
1776 /** Returns all users who are matched by the given filter. */
1777 private List<UserInfo> getUsers(UserFilter filter) {
1778 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1779
1780 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1781 UserInfo user = iterator.next();
1782 if (!filter.isEligibleUser(user)) {
1783 iterator.remove();
1784 }
1785 }
1786 return users;
1787 }
1788
1789 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001790 * Enforces that apps which have the
1791 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1792 * can make certain calls to the CarUserManager.
1793 *
1794 * @param message used as message if SecurityException is thrown.
1795 * @throws SecurityException if the caller is not system or root.
1796 */
1797 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001798 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1799 }
1800
felipealdfdf8512020-06-01 09:35:45 -07001801 private static void checkManageOrCreateUsersPermission(String message) {
1802 checkAtLeastOnePermission(message,
1803 android.Manifest.permission.MANAGE_USERS,
1804 android.Manifest.permission.CREATE_USERS);
1805 }
1806
felipeal2d0483c2019-11-02 14:07:22 -07001807 private static void checkManageUsersOrDumpPermission(String message) {
1808 checkAtLeastOnePermission(message,
1809 android.Manifest.permission.MANAGE_USERS,
1810 android.Manifest.permission.DUMP);
1811 }
1812
Felipe Leme5528ff72020-02-10 19:05:14 -08001813 private void checkInteractAcrossUsersPermission(String message) {
1814 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1815 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1816 }
1817
felipeal2d0483c2019-11-02 14:07:22 -07001818 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001819 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001820 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1821 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001822 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001823 }
1824 }
1825
felipeal2d0483c2019-11-02 14:07:22 -07001826 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1827 for (String permission : permissions) {
1828 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1829 /* exported = */ true)
1830 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1831 return true;
1832 }
1833 }
1834 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001835 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001836
1837 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1838 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1839 // Count all users that are managed profiles of the given user.
1840 int managedProfilesCount = 0;
1841 for (UserInfo user : users) {
1842 if (user.isManagedProfile() && user.profileGroupId == userId) {
1843 managedProfilesCount++;
1844 }
1845 }
1846 return managedProfilesCount;
1847 }
1848
1849 /**
1850 * Starts the first passenger of the given driver and assigns the passenger to the front
1851 * passenger zone.
1852 *
1853 * @param driverId User id of the driver.
1854 * @return whether it succeeds.
1855 */
1856 private boolean startFirstPassenger(@UserIdInt int driverId) {
1857 int zoneId = getAvailablePassengerZone();
1858 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1859 Log.w(TAG_USER, "passenger occupant zone is not found");
1860 return false;
1861 }
1862 List<UserInfo> passengers = getPassengers(driverId);
1863 if (passengers.size() < 1) {
1864 Log.w(TAG_USER, "passenger is not found");
1865 return false;
1866 }
1867 // Only one passenger is supported. If there are two or more passengers, the first passenger
1868 // is chosen.
1869 int passengerId = passengers.get(0).id;
1870 if (!startPassenger(passengerId, zoneId)) {
1871 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1872 return false;
1873 }
1874 return true;
1875 }
1876
1877 private int getAvailablePassengerZone() {
1878 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1879 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1880 for (int occupantType : occupantTypes) {
1881 int zoneId = getZoneId(occupantType);
1882 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1883 return zoneId;
1884 }
1885 }
1886 return OccupantZoneInfo.INVALID_ZONE_ID;
1887 }
1888
1889 /**
1890 * Creates a new passenger user when there is no passenger user.
1891 */
1892 private void setupPassengerUser() {
1893 int currentUser = ActivityManager.getCurrentUser();
1894 int profileCount = getNumberOfManagedProfiles(currentUser);
1895 if (profileCount > 0) {
1896 Log.w(TAG_USER, "max profile of user" + currentUser
1897 + " is exceeded: current profile count is " + profileCount);
1898 return;
1899 }
1900 // TODO(b/140311342): Use resource string for the default passenger name.
1901 UserInfo passenger = createPassenger("Passenger", currentUser);
1902 if (passenger == null) {
1903 // Couldn't create user, most likely because there are too many.
1904 Log.w(TAG_USER, "cannot create a passenger user");
1905 return;
1906 }
1907 }
1908
1909 @NonNull
1910 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1911 ZoneUserBindingHelper helper = null;
1912 synchronized (mLockHelper) {
1913 if (mZoneUserBindingHelper == null) {
1914 Log.w(TAG_USER, "implementation is not delegated");
1915 return new ArrayList<OccupantZoneInfo>();
1916 }
1917 helper = mZoneUserBindingHelper;
1918 }
1919 return helper.getOccupantZones(occupantType);
1920 }
1921
1922 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1923 ZoneUserBindingHelper helper = null;
1924 synchronized (mLockHelper) {
1925 if (mZoneUserBindingHelper == null) {
1926 Log.w(TAG_USER, "implementation is not delegated");
1927 return false;
1928 }
1929 helper = mZoneUserBindingHelper;
1930 }
1931 return helper.assignUserToOccupantZone(userId, zoneId);
1932 }
1933
1934 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1935 ZoneUserBindingHelper helper = null;
1936 synchronized (mLockHelper) {
1937 if (mZoneUserBindingHelper == null) {
1938 Log.w(TAG_USER, "implementation is not delegated");
1939 return false;
1940 }
1941 helper = mZoneUserBindingHelper;
1942 }
1943 return helper.unassignUserFromOccupantZone(userId);
1944 }
1945
1946 private boolean isPassengerDisplayAvailable() {
1947 ZoneUserBindingHelper helper = null;
1948 synchronized (mLockHelper) {
1949 if (mZoneUserBindingHelper == null) {
1950 Log.w(TAG_USER, "implementation is not delegated");
1951 return false;
1952 }
1953 helper = mZoneUserBindingHelper;
1954 }
1955 return helper.isPassengerDisplayAvailable();
1956 }
1957
1958 /**
1959 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1960 * zone is returned.
1961 *
1962 * @param occupantType The type of an occupant.
1963 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1964 * if not found.
1965 */
1966 private int getZoneId(@OccupantTypeEnum int occupantType) {
1967 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1968 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1969 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001970}