blob: 81922dc9d700a68d5a45d9b8713099fa4f3f56e8 [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;
felipeal159a2a42020-05-08 10:32:11 -070036import android.car.user.UserIdentificationAssociationResponse;
felipeale5bf0322020-04-16 15:10:57 -070037import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070038import android.car.userlib.CarUserManagerHelper;
felipeal1a9410d2020-05-06 13:30:05 -070039import android.car.userlib.CommonConstants.CarUserServiceConstants;
felipeal19e3d732020-03-18 12:07:32 -070040import android.car.userlib.HalCallback;
41import android.car.userlib.UserHalHelper;
Felipe Lemeaba246c2020-05-11 15:02:52 -070042import android.car.userlib.UserHelper;
Mayank Garga480dd92020-05-14 03:14:57 -070043import android.content.ComponentName;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070044import android.content.Context;
Mayank Garga480dd92020-05-14 03:14:57 -070045import android.content.pm.PackageManager;
46import android.content.pm.PackageManager.NameNotFoundException;
Eric Jeong1545f3b2019-09-16 13:56:52 -070047import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070048import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070049import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070050import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080051import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070052import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070053import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
54import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
felipeal159a2a42020-05-08 10:32:11 -070055import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
56import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080057import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070058import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070059import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080060import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070061import android.os.Handler;
62import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070063import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080064import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070065import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070066import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070067import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070068import android.sysprop.CarProperties;
felipeal159a2a42020-05-08 10:32:11 -070069import android.text.TextUtils;
felipeal312416a2020-04-14 12:28:24 -070070import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070071import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080072import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080073import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070074
75import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070076import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070077import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080078import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080079import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070080import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070081import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070082import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080083import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070084import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070085import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070086import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070087import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070088
89import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080090import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070091import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070092import java.util.Iterator;
93import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000094import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070095import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070096import java.util.concurrent.CountDownLatch;
97import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070098
99/**
100 * User service for cars. Manages users at boot time. Including:
101 *
102 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -0700103 * <li> Creates a user used as driver.
104 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700105 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700106 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700107 * <ol/>
108 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700109public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800110
felipealf7368962020-04-16 12:55:19 -0700111 private static final String TAG = TAG_USER;
112
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800113 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700114 public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800115 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700116 public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800117 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700118 public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800119 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
felipeal1a9410d2020-05-06 13:30:05 -0700120 public static final String BUNDLE_INITIAL_INFO_ACTION =
121 CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
Felipe Leme5528ff72020-02-10 19:05:14 -0800122
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700123 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700124 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700125 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700126 private final UserManager mUserManager;
127 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700128 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700129
Eric Jeongc91f9452019-08-30 15:04:21 -0700130 private final Object mLockUser = new Object();
131 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800132 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700133 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800134 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700135 // Only one passenger is supported.
136 @GuardedBy("mLockUser")
137 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700138 /**
139 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800140 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700141 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700142 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700143 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
144 /**
145 * Keep the list of background users started here. This is wholly for debugging purpose.
146 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700147 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700148 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
149
Felipe Leme58412202020-01-09 13:45:33 -0800150 private final UserHalService mHal;
151
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700152 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700153 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
154 getClass().getSimpleName());
155 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700156
Felipe Leme5528ff72020-02-10 19:05:14 -0800157 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800158 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700159 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800160 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700161 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800162
163 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800164 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700165 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800166 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700167 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800168
Mayank Garg7a114c82020-04-08 21:25:06 -0700169 /**
170 * User Id for the user switch in process, if any.
171 */
172 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700173 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700174 /**
175 * Request Id for the user switch in process, if any.
176 */
177 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700178 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700179 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
180
Eric Jeongc91f9452019-08-30 15:04:21 -0700181 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
182 new CopyOnWriteArrayList<>();
183
felipeal61ce3732020-04-03 11:01:00 -0700184 @Nullable
185 @GuardedBy("mLockUser")
186 private UserInfo mInitialUser;
187
Mayank Garg71661ea2020-04-29 01:25:03 -0700188 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700189
Mayank Garg587f1942020-05-06 01:41:34 -0700190 private IResultReceiver mUserSwitchUiReceiver;
191
Eric Jeongc91f9452019-08-30 15:04:21 -0700192 /** Interface for callbaks related to passenger activities. */
193 public interface PassengerCallback {
194 /** Called when passenger is started at a certain zone. */
195 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
196 /** Called when passenger is stopped. */
197 void onPassengerStopped(@UserIdInt int passengerId);
198 }
199
200 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
201 public interface ZoneUserBindingHelper {
202 /** Gets occupant zones corresponding to the occupant type. */
203 @NonNull
204 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
205 /** Assigns the user to the occupant zone. */
206 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
207 /** Makes the occupant zone unoccupied. */
208 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
209 /** Returns whether there is a passenger display. */
210 boolean isPassengerDisplayAvailable();
211 }
212
213 private final Object mLockHelper = new Object();
214 @GuardedBy("mLockHelper")
215 private ZoneUserBindingHelper mZoneUserBindingHelper;
216
Felipe Leme58412202020-01-09 13:45:33 -0800217 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700218 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
219 @NonNull IActivityManager am, int maxRunningUsers) {
220 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
221 new UserMetrics());
222 }
223
224 @VisibleForTesting
225 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
226 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
227 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700228 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
229 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700230 }
231 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800232 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700233 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700234 mAm = am;
235 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700236 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700237 mLastPassengerId = UserHandle.USER_NULL;
238 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700239 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700240 }
241
242 @Override
243 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700244 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
245 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700246 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700247 }
248
249 @Override
250 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700251 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
252 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700253 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700254 }
255
256 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700257 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700258 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700259 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800260 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700261 handleDumpListeners(writer, indent);
Mayank Garg587f1942020-05-06 01:41:34 -0700262 writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
Eric Jeongc91f9452019-08-30 15:04:21 -0700263 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700264 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700265 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
266 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700267 }
268 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
269 List<UserInfo> allDrivers = getAllDrivers();
270 int driversSize = allDrivers.size();
271 writer.println("NumberOfDrivers: " + driversSize);
272 for (int i = 0; i < driversSize; i++) {
273 int driverId = allDrivers.get(i).id;
274 writer.print(indent + "#" + i + ": id=" + driverId);
275 List<UserInfo> passengers = getPassengers(driverId);
276 int passengersSize = passengers.size();
277 writer.print(" NumberPassengers: " + passengersSize);
278 if (passengersSize > 0) {
279 writer.print(" [");
280 for (int j = 0; j < passengersSize; j++) {
281 writer.print(passengers.get(j).id);
282 if (j < passengersSize - 1) {
283 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700284 }
felipeal2d0483c2019-11-02 14:07:22 -0700285 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700286 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700287 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700288 writer.println();
289 }
290 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
291 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
292 writer.printf("Initial user: %s\n", mInitialUser);
293 writer.println("Relevant overlayable properties");
294 Resources res = mContext.getResources();
295 writer.printf("%sowner_name=%s\n", indent,
296 res.getString(com.android.internal.R.string.owner_name));
297 writer.printf("%sdefault_guest_name=%s\n", indent,
298 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700299 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700300 writer.printf("Request Id for the user switch in process=%d\n ",
301 mRequestIdForUserSwitchInProcess);
Mayank Garga480dd92020-05-14 03:14:57 -0700302 writer.printf("System UI package name=%s\n", getSystemUiPackageName());
felipeale8c5dce2020-04-15 11:27:06 -0700303
304 dumpUserMetrics(writer);
305 }
306
307 /**
308 * Dumps user metrics.
309 */
310 public void dumpUserMetrics(@NonNull PrintWriter writer) {
311 mUserMetrics.dump(writer);
312 }
313
314 /**
315 * Dumps first user unlocking time.
316 */
317 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
318 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700319 }
320
321 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
322 CountDownLatch latch = new CountDownLatch(1);
323 mHandler.post(() -> {
324 handleDumpUserLifecycleListeners(writer);
325 handleDumpAppLifecycleListeners(writer, indent);
326 latch.countDown();
327 });
328 int timeout = 5;
329 try {
330 if (!latch.await(timeout, TimeUnit.SECONDS)) {
331 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
332 timeout);
333 }
334 } catch (InterruptedException e) {
335 Thread.currentThread().interrupt();
336 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
337 }
338 }
339
340 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
341 if (mUserLifecycleListeners.isEmpty()) {
342 writer.println("No user lifecycle listeners");
343 return;
344 }
345 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
346 for (UserLifecycleListener listener : mUserLifecycleListeners) {
347 writer.printf("Listener %s\n", listener);
348 }
349 }
350
351 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
352 int numberListeners = mAppLifecycleListeners.size();
353 if (numberListeners == 0) {
354 writer.println("No lifecycle listeners");
355 return;
356 }
357 writer.printf("%d lifecycle listeners\n", numberListeners);
358 for (int i = 0; i < numberListeners; i++) {
359 int uid = mAppLifecycleListeners.keyAt(i);
360 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
361 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800362 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700363 }
364
365 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800366 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
367 *
368 * @param name The name of the driver to be created.
369 * @param admin Whether the created driver will be an admin.
370 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
371 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700372 */
373 @Override
374 @Nullable
375 public UserInfo createDriver(@NonNull String name, boolean admin) {
376 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000377 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700378 if (admin) {
379 return createNewAdminUser(name);
380 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700381 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700382 }
383
384 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800385 * Creates a passenger who is a profile of the given driver.
386 *
387 * @param name The name of the passenger to be created.
388 * @param driverId User id of the driver under whom a passenger is created.
389 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
390 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700391 */
392 @Override
393 @Nullable
394 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
395 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000396 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700397 UserInfo driver = mUserManager.getUserInfo(driverId);
398 if (driver == null) {
399 Log.w(TAG_USER, "the driver is invalid");
400 return null;
401 }
402 if (driver.isGuest()) {
403 Log.w(TAG_USER, "a guest driver cannot create a passenger");
404 return null;
405 }
Bookatz42fb1a62019-10-30 11:45:01 -0700406 UserInfo user = mUserManager.createProfileForUser(name,
407 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700408 if (user == null) {
409 // Couldn't create user, most likely because there are too many.
410 Log.w(TAG_USER, "can't create a profile for user" + driverId);
411 return null;
412 }
413 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700414 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700415 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700416 return user;
417 }
418
419 /**
420 * @see CarUserManager.switchDriver
421 */
422 @Override
423 public boolean switchDriver(@UserIdInt int driverId) {
424 checkManageUsersPermission("switchDriver");
425 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
426 // System user doesn't associate with real person, can not be switched to.
427 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
428 return false;
429 }
430 int userSwitchable = mUserManager.getUserSwitchability();
431 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
432 Log.w(TAG_USER, "current process is not allowed to switch user");
433 return false;
434 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700435 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700436 // The current user is already the given user.
437 return true;
438 }
439 try {
440 return mAm.switchUser(driverId);
441 } catch (RemoteException e) {
442 // ignore
443 Log.w(TAG_USER, "error while switching user", e);
444 }
445 return false;
446 }
447
448 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800449 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
450 *
451 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700452 */
453 @Override
454 @NonNull
455 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700456 checkManageUsersOrDumpPermission("getAllDrivers");
Eric Jeong40f8fa32020-05-12 12:23:33 -0700457 return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700458 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700459 }
460
461 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800462 * Returns all passengers under the given driver.
463 *
464 * @param driverId User id of a driver.
465 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700466 */
467 @Override
468 @NonNull
469 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700470 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700471 return getUsers((user) -> {
Eric Jeong40f8fa32020-05-12 12:23:33 -0700472 return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
473 && user.isManagedProfile() && user.profileGroupId == driverId;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 });
475 }
476
477 /**
478 * @see CarUserManager.startPassenger
479 */
480 @Override
481 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
482 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700483 synchronized (mLockUser) {
484 try {
485 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
486 Log.w(TAG_USER, "could not start passenger");
487 return false;
488 }
489 } catch (RemoteException e) {
490 // ignore
491 Log.w(TAG_USER, "error while starting passenger", e);
492 return false;
493 }
494 if (!assignUserToOccupantZone(passengerId, zoneId)) {
495 Log.w(TAG_USER, "could not assign passenger to zone");
496 return false;
497 }
498 mLastPassengerId = passengerId;
499 }
500 for (PassengerCallback callback : mPassengerCallbacks) {
501 callback.onPassengerStarted(passengerId, zoneId);
502 }
503 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700504 }
505
506 /**
507 * @see CarUserManager.stopPassenger
508 */
509 @Override
510 public boolean stopPassenger(@UserIdInt int passengerId) {
511 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700512 return stopPassengerInternal(passengerId, true);
513 }
514
515 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
516 synchronized (mLockUser) {
517 UserInfo passenger = mUserManager.getUserInfo(passengerId);
518 if (passenger == null) {
519 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
520 return false;
521 }
522 if (mLastPassengerId != passengerId) {
523 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
524 return true;
525 }
526 if (checkCurrentDriver) {
527 int currentUser = ActivityManager.getCurrentUser();
528 if (passenger.profileGroupId != currentUser) {
529 Log.w(TAG_USER, "passenger " + passengerId
530 + " is not a profile of the current user");
531 return false;
532 }
533 }
534 // Passenger is a profile, so cannot be stopped through activity manager.
535 // Instead, activities started by the passenger are stopped and the passenger is
536 // unassigned from the zone.
537 stopAllTasks(passengerId);
538 if (!unassignUserFromOccupantZone(passengerId)) {
539 Log.w(TAG_USER, "could not unassign user from occupant zone");
540 return false;
541 }
542 mLastPassengerId = UserHandle.USER_NULL;
543 }
544 for (PassengerCallback callback : mPassengerCallbacks) {
545 callback.onPassengerStopped(passengerId);
546 }
547 return true;
548 }
549
550 private void stopAllTasks(@UserIdInt int userId) {
551 try {
552 for (StackInfo info : mAm.getAllStackInfos()) {
553 for (int i = 0; i < info.taskIds.length; i++) {
554 if (info.taskUserIds[i] == userId) {
555 int taskId = info.taskIds[i];
556 if (!mAm.removeTask(taskId)) {
557 Log.w(TAG_USER, "could not remove task " + taskId);
558 }
559 }
560 }
561 }
562 } catch (RemoteException e) {
563 Log.e(TAG_USER, "could not get stack info", e);
564 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700565 }
566
Felipe Leme5528ff72020-02-10 19:05:14 -0800567 @Override
568 public void setLifecycleListenerForUid(IResultReceiver listener) {
569 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700570 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800571 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
572
573 try {
574 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
575 } catch (RemoteException e) {
576 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
577 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700578 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800579 }
580
581 private void onListenerDeath(int uid) {
582 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700583 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800584 }
585
586 @Override
587 public void resetLifecycleListenerForUid() {
588 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700589 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800590 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700591 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800592 }
593
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800594 @Override
595 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800596 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700597 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
598 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800599 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700600 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800601 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800602 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700603 Bundle resultData = null;
604 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700605 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
606 status, resp.action, resp.userToSwitchOrCreate.userId,
607 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700608 switch (resp.action) {
609 case InitialUserInfoResponseAction.SWITCH:
610 resultData = new Bundle();
611 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
612 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
613 break;
614 case InitialUserInfoResponseAction.CREATE:
615 resultData = new Bundle();
616 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
617 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
618 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
619 break;
620 case InitialUserInfoResponseAction.DEFAULT:
621 resultData = new Bundle();
622 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
623 break;
624 default:
625 // That's ok, it will be the same as DEFAULT...
626 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800627 }
felipeal312416a2020-04-14 12:28:24 -0700628 } else {
629 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800630 }
Mayank Garg0e239142020-04-14 19:16:31 -0700631 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800632 });
633 }
634
Felipe Lemee3cab982020-03-12 11:39:29 -0700635 /**
felipeal61ce3732020-04-03 11:01:00 -0700636 * Gets the initial foreground user after the device boots or resumes from suspension.
637 *
638 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
639 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
640 * method returns {@code null}.
641 *
642 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
643 * (like switching to the last active user), and this method will return the result of such
644 * operation.
645 *
646 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
647 * {@code null}.
648 *
649 * @hide
650 */
651 @Nullable
652 public UserInfo getInitialUser() {
653 checkInteractAcrossUsersPermission("getInitialUser");
654 synchronized (mLockUser) {
655 return mInitialUser;
656 }
657 }
658
659 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
660 // some reason passing the whole UserInfo through a raw binder transaction is not working.
661 /**
662 * Sets the initial foreground user after the device boots or resumes from suspension.
663 */
664 public void setInitialUser(@UserIdInt int userId) {
665 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
666 : mUserManager.getUserInfo(userId);
667 setInitialUser(initialUser);
668 }
669
670 /**
671 * Sets the initial foreground user after the device boots or resumes from suspension.
672 */
673 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700674 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
675 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700676 synchronized (mLockUser) {
677 mInitialUser = user;
678 }
679 if (user == null) {
680 // This mean InitialUserSetter failed and could not fallback, so the initial user was
681 // not switched (and most likely is SYSTEM_USER).
682 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
683 Log.wtf(TAG_USER, "Initial user set to null");
684 }
685 }
686
687 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700688 * Calls the User HAL to get the initial user info.
689 *
690 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
691 * @param callback callback to receive the results.
692 */
693 public void getInitialUserInfo(int requestType,
694 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700695 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
696 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700697 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700698 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700699 UsersInfo usersInfo = getUsersInfo();
700 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
701 }
702
703 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700704 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
705 *
706 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700707 * When everything works well, the workflow is:
708 * <ol>
709 * <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
710 * type, current user id, target user id, and a callback.
711 * <li> HAL called back with SUCCESS.
712 * <li> {@link IActivityManager} is called for Android user switch.
713 * <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
714 * <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
715 * request type, current user id, and target user id. In this case, the current and target
716 * user IDs would be same.
717 * <ol/>
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700718 *
719 * <p>
Mayank Gargb08f6772020-05-01 18:06:48 -0700720 * Corner cases:
721 * <ul>
722 * <li> If target user is already the current user, no user switch is performed and receiver
723 * would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
724 * <li> If HAL user switch call fails, no Android user switch. Receiver would receive
725 * {@code STATUS_HAL_INTERNAL_FAILURE}.
726 * <li> If HAL user switch call is successful, but android user switch call fails,
727 * {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
728 * target user id, but in this case the current and target user IDs would be different.
729 * <li> If another user switch request for the same target user is received while previous
730 * request is in process, receiver would receive
731 * {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
732 * <li> If a user switch request is received while another user switch request for different
733 * target user is in process, the previous request would be abandoned and new request will be
734 * processed. No POST_SWITCH would be sent for the previous request.
735 * <ul/>
Mayank Garg59f22192020-03-27 00:51:45 -0700736 *
Mayank Garge19c2922020-03-30 18:05:53 -0700737 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700738 * @param timeoutMs - timeout for HAL to wait
739 * @param receiver - receiver for the results
740 */
Mayank Garge19c2922020-03-30 18:05:53 -0700741 @Override
742 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700743 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700744 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700745 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700746 Objects.requireNonNull(receiver);
747 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700748 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700749
felipealf7368962020-04-16 12:55:19 -0700750 int currentUser = ActivityManager.getCurrentUser();
751 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700752 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
753 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
754 }
felipeale5bf0322020-04-16 15:10:57 -0700755 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
756 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700757 return;
758 }
759
Mayank Garg7a114c82020-04-08 21:25:06 -0700760 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700761 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
762 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
763 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
764 }
765
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700766 // If there is another request for the same target user, return another request in
767 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
768 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
769 // user switch request in process for different target user, but that request is now
770 // ignored.
felipealf7368962020-04-16 12:55:19 -0700771 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700772 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
773 Log.d(TAG_USER,
774 "Another user switch request in process for the requested target user: "
775 + targetUserId);
776 }
777
778 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700779 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700780 return;
781 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700782 else {
783 mUserIdForUserSwitchInProcess = targetUserId;
784 mRequestIdForUserSwitchInProcess = 0;
785 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700786 }
787
Mayank Garg59f22192020-03-27 00:51:45 -0700788 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700789 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700790 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700791 halTargetUser.userId = targetUser.id;
792 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
793 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700794 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
795 Log.d(TAG, "switch response: status="
796 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
797 }
798
felipeale5bf0322020-04-16 15:10:57 -0700799 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700800
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700801 synchronized (mLockUser) {
802 if (status != HalCallback.STATUS_OK) {
803 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
804 Log.w(TAG, "invalid callback status ("
805 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
806 + resp);
807 sendResult(receiver, resultStatus);
808 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
809 return;
810 }
felipealf7368962020-04-16 12:55:19 -0700811
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700812 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
813 resp.errorMessage);
814
815 if (mUserIdForUserSwitchInProcess != targetUserId) {
816 // Another user switch request received while HAL responded. No need to process
817 // this request further
818 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
819 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
820 + "abondoned for : " + targetUserId + ". Current user in process: "
821 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700822 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700823 resultStatus =
824 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
825 sendResult(receiver, resultStatus);
826 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
827 return;
828 }
829
830 switch (resp.status) {
831 case SwitchUserStatus.SUCCESS:
832 boolean switched;
833 try {
834 switched = mAm.switchUser(targetUserId);
835 if (switched) {
Mayank Garg587f1942020-05-06 01:41:34 -0700836 sendUserSwitchUiCallback(targetUserId);
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700837 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
838 mRequestIdForUserSwitchInProcess = resp.requestId;
839 } else {
840 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
841 postSwitchHalResponse(resp.requestId, targetUserId);
842 }
843 } catch (RemoteException e) {
844 // ignore
845 Log.w(TAG_USER,
846 "error while switching user " + targetUser.toFullString(), e);
847 }
848 break;
849 case SwitchUserStatus.FAILURE:
850 // HAL failed to switch user
851 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
852 break;
853 }
854
855 if (mRequestIdForUserSwitchInProcess == 0) {
856 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
857 }
Mayank Garg59f22192020-03-27 00:51:45 -0700858 }
felipeale5bf0322020-04-16 15:10:57 -0700859 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700860 });
861 }
862
Mayank Garg587f1942020-05-06 01:41:34 -0700863 private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
864 if (mUserSwitchUiReceiver == null) {
865 Log.w(TAG_USER, "No User switch UI receiver.");
866 return;
867 }
868
869 try {
870 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
871 mUserSwitchUiReceiver.send(targetUserId, null);
872 } catch (RemoteException e) {
873 Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
874 }
875 }
876
felipeal5e3ede42020-04-23 18:04:07 -0700877 @Override
felipeal159a2a42020-05-08 10:32:11 -0700878 public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
felipeal5e3ede42020-04-23 18:04:07 -0700879 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
880 checkManageUsersPermission("getUserIdentificationAssociation");
881
882 int uid = getCallingUid();
883 int userId = UserHandle.getUserId(uid);
884 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
885
886 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
887 request.userInfo.userId = userId;
888 request.userInfo.flags = getHalUserInfoFlags(userId);
889
890 request.numberAssociationTypes = types.length;
891 for (int i = 0; i < types.length; i++) {
892 request.associationTypes.add(types[i]);
893 }
894
895 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
896 if (halResponse == null) {
897 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
898 + Arrays.toString(types));
felipeal159a2a42020-05-08 10:32:11 -0700899 return UserIdentificationAssociationResponse.forFailure();
felipeal5e3ede42020-04-23 18:04:07 -0700900 }
901
902 int[] values = new int[halResponse.associations.size()];
903 for (int i = 0; i < values.length; i++) {
904 values[i] = halResponse.associations.get(i).value;
905 }
906 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
907
felipeal159a2a42020-05-08 10:32:11 -0700908 return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
909 }
910
911 @Override
912 public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
913 AndroidFuture<UserIdentificationAssociationResponse> result) {
914 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
915 Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
916 if (types.length != values.length) {
917 throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
918 + Arrays.toString(values) + ") should have the same length");
919 }
920 checkManageUsersPermission("setUserIdentificationAssociation");
921
922 int uid = getCallingUid();
923 int userId = UserHandle.getUserId(uid);
924 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
925
926 UserIdentificationSetRequest request = new UserIdentificationSetRequest();
927 request.userInfo.userId = userId;
928 request.userInfo.flags = getHalUserInfoFlags(userId);
929
930 request.numberAssociations = types.length;
931 for (int i = 0; i < types.length; i++) {
932 UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
933 association.type = types[i];
934 association.value = values[i];
935 request.associations.add(association);
936 }
937
938 mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
939 if (status != HalCallback.STATUS_OK) {
940 Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
941 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
942 + resp);
943 if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
944 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
945 result.complete(UserIdentificationAssociationResponse.forFailure());
946 return;
947 }
948 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
949 resp.errorMessage);
950 result.complete(
951 UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
952 return;
953 }
954 int respSize = resp.associations.size();
955 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
956 resp.errorMessage);
957
958 int[] responseTypes = new int[respSize];
959 for (int i = 0; i < respSize; i++) {
960 responseTypes[i] = resp.associations.get(i).value;
961 }
962 UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
963 .forSuccess(responseTypes, resp.errorMessage);
964 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
965 Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
966 + ", converted=" + response);
967 }
968 result.complete(response);
969 });
felipeal5e3ede42020-04-23 18:04:07 -0700970 }
971
972 /**
973 * Gets the User HAL flags for the given user.
974 *
975 * @throws IllegalArgumentException if the user does not exist.
976 */
977 private int getHalUserInfoFlags(@UserIdInt int userId) {
978 UserInfo user = mUserManager.getUserInfo(userId);
979 Preconditions.checkArgument(user != null, "no user for id %d", userId);
980 return UserHalHelper.convertFlags(user);
981 }
982
Mayank Garg0e239142020-04-14 19:16:31 -0700983 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
984 @Nullable Bundle resultData) {
985 try {
986 receiver.send(resultCode, resultData);
987 } catch (RemoteException e) {
988 // ignore
989 Log.w(TAG_USER, "error while sending results", e);
990 }
991 }
992
felipeale5bf0322020-04-16 15:10:57 -0700993 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
994 @UserSwitchResult.Status int status) {
995 sendResult(receiver, status, /* errorMessage= */ null);
996 }
997
998 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
999 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
1000 receiver.complete(new UserSwitchResult(status, errorMessage));
1001 }
1002
Mayank Garg6307fe42020-04-15 23:09:03 -07001003 /**
1004 * Calls activity manager for user switch.
1005 *
1006 * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
1007 *
1008 * @param requestId for the user switch request
1009 * @param targetUserId of the target user
1010 *
1011 * @hide
1012 */
1013 public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
1014 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
1015 targetUserId);
1016 Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
1017
1018 try {
1019 boolean result = mAm.switchUser(targetUserId);
1020 if (result) {
1021 updateUserSwitchInProcess(requestId, targetUserId);
1022 } else {
1023 postSwitchHalResponse(requestId, targetUserId);
1024 }
1025 } catch (RemoteException e) {
1026 // ignore
1027 Log.w(TAG_USER, "error while switching user " + targetUserId, e);
1028 }
1029 }
1030
1031 private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
1032 synchronized (mLockUser) {
1033 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
1034 // Some other user switch is in process.
1035 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1036 Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
1037 + " is in process. Abandoning it as a new user switch is requested"
1038 + " for the target user: " + targetUserId);
1039 }
1040 }
1041 mUserIdForUserSwitchInProcess = targetUserId;
1042 mRequestIdForUserSwitchInProcess = requestId;
1043 }
1044 }
1045
Mayank Garg7a114c82020-04-08 21:25:06 -07001046 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
1047 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
1048 UsersInfo usersInfo = getUsersInfo();
1049 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1050 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1051 halTargetUser.userId = targetUser.id;
1052 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -07001053 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
1054 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -07001055 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
1056 }
1057
Mayank Garg59f22192020-03-27 00:51:45 -07001058 /**
Felipe Lemee3cab982020-03-12 11:39:29 -07001059 * Checks if the User HAL is supported.
1060 */
1061 public boolean isUserHalSupported() {
1062 return mHal.isSupported();
1063 }
1064
Mayank Garg587f1942020-05-06 01:41:34 -07001065 /**
1066 * Sets a callback which is invoked before user switch.
1067 *
1068 * <p>
1069 * This method should only be called by the Car System UI. The purpose of this call is to notify
1070 * Car System UI to show the user switch UI before the user switch.
1071 */
1072 @Override
1073 public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
Yan Zhu67a383e2020-05-11 20:46:24 -07001074 checkManageUsersPermission("setUserSwitchUiCallback");
Mayank Garga480dd92020-05-14 03:14:57 -07001075
1076 // Confirm that caller is system UI.
1077 String systemUiPackageName = getSystemUiPackageName();
1078 if (systemUiPackageName == null) {
1079 throw new IllegalStateException("System UI package not found.");
1080 }
1081
1082 try {
1083 int systemUiUid = mContext
1084 .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
1085 .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
1086 int callerUid = Binder.getCallingUid();
1087 if (systemUiUid != callerUid) {
1088 throw new SecurityException("Invalid caller. Only" + systemUiPackageName
1089 + " is allowed to make this call");
1090 }
1091 } catch (NameNotFoundException e) {
1092 throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
1093 }
1094
Mayank Garg587f1942020-05-06 01:41:34 -07001095 mUserSwitchUiReceiver = receiver;
1096 }
1097
Mayank Garga480dd92020-05-14 03:14:57 -07001098 // TODO(157082995): This information can be taken from
1099 // PackageManageInternalImpl.getSystemUiServiceComponent
1100 @Nullable
1101 private String getSystemUiPackageName() {
1102 try {
1103 ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
1104 .getString(com.android.internal.R.string.config_systemUIServiceComponent));
1105 return componentName.getPackageName();
1106 } catch (RuntimeException e) {
1107 Log.w(TAG_USER, "error while getting system UI package name.", e);
1108 return null;
1109 }
1110 }
1111
felipeal159a2a42020-05-08 10:32:11 -07001112 // TODO(b/150413515): use helper to generate UsersInfo
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001113 private UsersInfo getUsersInfo() {
1114 UserInfo currentUser;
1115 try {
1116 currentUser = mAm.getCurrentUser();
1117 } catch (RemoteException e) {
1118 // shouldn't happen
1119 throw new IllegalStateException("Could not get current user: ", e);
1120 }
Mayank Garge5de0f92020-04-23 21:38:38 -07001121 return getUsersInfo(currentUser);
1122 }
1123
felipeal159a2a42020-05-08 10:32:11 -07001124 // TODO(b/150413515): use helper to generate UsersInfo
Mayank Garge5de0f92020-04-23 21:38:38 -07001125 private UsersInfo getUsersInfo(@NonNull UserInfo currentUser) {
Felipe Lemeabbf2da2020-02-24 18:25:29 -08001126 List<UserInfo> existingUsers = mUserManager.getUsers();
1127 int size = existingUsers.size();
1128
1129 UsersInfo usersInfo = new UsersInfo();
1130 usersInfo.numberUsers = size;
1131 usersInfo.currentUser.userId = currentUser.id;
1132 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
1133
1134 for (int i = 0; i < size; i++) {
1135 UserInfo androidUser = existingUsers.get(i);
1136 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
1137 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1138 halUser.userId = androidUser.id;
1139 halUser.flags = UserHalHelper.convertFlags(androidUser);
1140 usersInfo.existingUsers.add(halUser);
1141 }
1142
1143 return usersInfo;
1144 }
1145
Keun young Park13a7a822019-04-04 15:53:08 -07001146 private void updateDefaultUserRestriction() {
1147 // We want to set restrictions on system and guest users only once. These are persisted
1148 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
1149 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -07001150 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
1151 return;
Keun young Park13a7a822019-04-04 15:53:08 -07001152 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001153 // Only apply the system user restrictions if the system user is headless.
1154 if (UserManager.isHeadlessSystemUserMode()) {
1155 setSystemUserRestrictions();
1156 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001157 Settings.Global.putInt(mContext.getContentResolver(),
1158 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -07001159 }
1160
Eric Jeong1545f3b2019-09-16 13:56:52 -07001161 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -07001162 return !mUserManager.getUserInfo(userId).isEphemeral();
1163 }
1164
Antonio Kantekc8114752020-03-05 21:37:39 -08001165 /**
Antonio Kantekc8114752020-03-05 21:37:39 -08001166 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
1167 */
1168 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1169 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001170 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001171 }
1172
1173 /**
1174 * Removes previously added {@link UserLifecycleListener}.
1175 */
1176 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
1177 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001178 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -08001179 }
1180
Eric Jeongc91f9452019-08-30 15:04:21 -07001181 /** Adds callback to listen to passenger activity events. */
1182 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001183 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001184 mPassengerCallbacks.add(callback);
1185 }
1186
1187 /** Removes previously added callback to listen passenger events. */
1188 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001189 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -07001190 mPassengerCallbacks.remove(callback);
1191 }
1192
1193 /** Sets the implementation of ZoneUserBindingHelper. */
1194 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1195 synchronized (mLockHelper) {
1196 mZoneUserBindingHelper = helper;
1197 }
1198 }
1199
felipeal98900c82020-04-09 09:05:02 -07001200 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001201 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001202 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001203 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001204 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001205 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1206 updateDefaultUserRestriction();
1207 tasks = new ArrayList<>(mUser0UnlockTasks);
1208 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001209 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001210 }
1211 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001212 Integer user = userId;
1213 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001214 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001215 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001216 mBackgroundUsersToRestart.remove(user);
1217 mBackgroundUsersToRestart.add(0, user);
1218 }
1219 // -1 for user 0
1220 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001221 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001222 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001223 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001224 + ", dropping least recently user from restart list:" + userToDrop);
1225 // Drop the least recently used user.
1226 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1227 }
1228 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001229 }
1230 }
1231 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001232 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001233 for (Runnable r : tasks) {
1234 r.run();
1235 }
1236 }
1237 }
1238
1239 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001240 * Starts all background users that were active in system.
1241 *
Keun young Parkfb656372019-03-12 18:37:55 -07001242 * @return list of background users started successfully.
1243 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001244 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001245 public ArrayList<Integer> startAllBackgroundUsers() {
1246 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001247 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001248 users = new ArrayList<>(mBackgroundUsersToRestart);
1249 mBackgroundUsersRestartedHere.clear();
1250 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001251 }
1252 ArrayList<Integer> startedUsers = new ArrayList<>();
1253 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001254 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001255 continue;
1256 }
1257 try {
1258 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001259 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1260 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001261 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001262 } else if (mAm.unlockUser(user, null, null, null)) {
1263 startedUsers.add(user);
1264 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001265 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001266 if (mUserManager.isUserRunning(user)) {
1267 // add to started list so that it can be stopped later.
1268 startedUsers.add(user);
1269 }
Keun young Parkfb656372019-03-12 18:37:55 -07001270 }
1271 }
1272 } catch (RemoteException e) {
1273 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001274 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001275 }
1276 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001277 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001278 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001279 ArrayList<Integer> usersToRemove = new ArrayList<>();
1280 for (Integer user : mBackgroundUsersToRestart) {
1281 if (!startedUsers.contains(user)) {
1282 usersToRemove.add(user);
1283 }
1284 }
1285 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1286 }
Keun young Parkfb656372019-03-12 18:37:55 -07001287 return startedUsers;
1288 }
1289
1290 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001291 * Stops all background users that were active in system.
1292 *
1293 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001294 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001295 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001296 if (userId == UserHandle.USER_SYSTEM) {
1297 return false;
1298 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001299 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001300 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001301 return false;
1302 }
1303 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001304 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001305 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001306 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001307 Integer user = userId;
1308 mBackgroundUsersRestartedHere.remove(user);
1309 }
1310 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1311 return false;
1312 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001313 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001314 return false;
1315 }
1316 } catch (RemoteException e) {
1317 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001318 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001319 }
1320 return true;
1321 }
1322
1323 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001324 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001325 */
felipeale8c5dce2020-04-15 11:27:06 -07001326 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1327 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1328 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001329
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001330 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001331 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001332 onUserSwitching(fromUserId, toUserId);
felipeal98900c82020-04-09 09:05:02 -07001333 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1334 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001335 }
1336
felipeale8c5dce2020-04-15 11:27:06 -07001337 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001338 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001339
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001340 mHandler.post(() -> {
1341 handleNotifyServiceUserLifecycleListeners(event);
1342 handleNotifyAppUserLifecycleListeners(event);
1343 });
felipeale8c5dce2020-04-15 11:27:06 -07001344
1345 // Finally, update metrics.
1346 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1347 }
1348
1349 /**
1350 * Sets the first user unlocking metrics.
1351 */
1352 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1353 int halResponseTime) {
1354 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001355 }
1356
Mayank Garg7a114c82020-04-08 21:25:06 -07001357 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001358 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001359 || mUserIdForUserSwitchInProcess != userId
1360 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001361 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1362 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1363 }
1364 return;
1365 }
felipealf7368962020-04-16 12:55:19 -07001366 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1367 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001368 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001369 }
1370
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001371 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1372 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001373 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001374 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1375 Log.d(TAG_USER, "No app listener to be notified of " + event);
1376 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001377 return;
1378 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001379 // Must use a different TimingsTraceLog because it's another thread
1380 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1381 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1382 }
felipeal2a84d512020-04-06 18:52:15 -07001383 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001384 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1385 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1386 for (int i = 0; i < listenersSize; i++) {
1387 int uid = mAppLifecycleListeners.keyAt(i);
1388 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1389 Bundle data = new Bundle();
1390 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001391
1392 int fromUid = event.getPreviousUserId();
1393 if (fromUid != UserHandle.USER_NULL) {
1394 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1395 }
1396
felipeal2a84d512020-04-06 18:52:15 -07001397 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001398 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001399 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001400 try {
felipeal2a84d512020-04-06 18:52:15 -07001401 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001402 listener.send(userId, data);
1403 } catch (RemoteException e) {
1404 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1405 } finally {
1406 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001407 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001408 }
1409 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001410 }
1411
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001412 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001413 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1414 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001415 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001416 return;
felipeal2a84d512020-04-06 18:52:15 -07001417 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1418 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1419 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001420 }
felipeal2a84d512020-04-06 18:52:15 -07001421
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001422 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1423 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001424 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001425 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001426 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001427 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001428 listener.onEvent(event);
1429 } catch (RuntimeException e) {
1430 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001431 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001432 } finally {
1433 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001434 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001435 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001436 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001437 }
1438
Mayank Garge5de0f92020-04-23 21:38:38 -07001439 private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
Eric Jeong40f8fa32020-05-12 12:23:33 -07001440 Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001441 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
Mayank Garge5de0f92020-04-23 21:38:38 -07001442 t.traceBegin("onUserSwitching-" + toUserId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001443
Mayank Garge5de0f92020-04-23 21:38:38 -07001444 // Switch HAL users if user switch is not requested by CarUserService
1445 notifyHalLegacySwitch(fromUserId, toUserId);
1446
Felipe Lemeaba246c2020-05-11 15:02:52 -07001447 if (!UserHelper.isHeadlessSystemUser(toUserId)) {
Mayank Garge5de0f92020-04-23 21:38:38 -07001448 mCarUserManagerHelper.setLastActiveUser(toUserId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001449 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001450 if (mLastPassengerId != UserHandle.USER_NULL) {
1451 stopPassengerInternal(mLastPassengerId, false);
1452 }
1453 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1454 setupPassengerUser();
Mayank Garge5de0f92020-04-23 21:38:38 -07001455 startFirstPassenger(toUserId);
Eric Jeongc91f9452019-08-30 15:04:21 -07001456 }
felipeal98900c82020-04-09 09:05:02 -07001457 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001458 }
1459
Mayank Garge5de0f92020-04-23 21:38:38 -07001460 private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
1461 synchronized (mLockUser) {
1462 if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
1463 }
1464
1465 // switch HAL user
1466 UserInfo targetUser = mUserManager.getUserInfo(toUserId);
1467 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
1468 new android.hardware.automotive.vehicle.V2_0.UserInfo();
1469 halTargetUser.userId = targetUser.id;
1470 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
1471 UserInfo currentUser = mUserManager.getUserInfo(fromUserId);
1472 UsersInfo usersInfo = getUsersInfo(currentUser);
1473 mHal.legacyUserSwitch(halTargetUser, usersInfo);
1474 }
1475
Pavel Maltsev17e81832019-04-04 14:38:41 -07001476 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001477 * 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 -08001478 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001479 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001480 * @param r Runnable to run.
1481 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001482 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001483 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001484 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001485 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001486 if (mUser0Unlocked) {
1487 runNow = true;
1488 } else {
1489 mUser0UnlockTasks.add(r);
1490 }
1491 }
1492 if (runNow) {
1493 r.run();
1494 }
1495 }
1496
Keun young Parkf3523cd2019-04-08 10:09:17 -07001497 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001498 @NonNull
1499 ArrayList<Integer> getBackgroundUsersToRestart() {
1500 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001501 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001502 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1503 }
1504 return backgroundUsersToRestart;
1505 }
1506
Ying Zheng1ab32b62018-06-26 12:47:26 -07001507 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001508 // Disable Location service for system user.
1509 LocationManager locationManager =
1510 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001511 locationManager.setLocationEnabledForUser(
1512 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001513 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001514
1515 /**
1516 * Creates a new user on the system, the created user would be granted admin role.
1517 *
1518 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001519 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001520 */
1521 @Nullable
1522 private UserInfo createNewAdminUser(String name) {
1523 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1524 // Only admins or system user can create other privileged users.
1525 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1526 return null;
1527 }
1528
1529 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1530 if (user == null) {
1531 // Couldn't create user, most likely because there are too many.
1532 Log.w(TAG_USER, "can't create admin user.");
1533 return null;
1534 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001535 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001536
1537 return user;
1538 }
1539
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001540 /**
1541 * Assigns a default icon to a user according to the user's id.
1542 *
1543 * @param userInfo User whose avatar is set to default icon.
1544 * @return Bitmap of the user icon.
1545 */
1546 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1547 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1548 Bitmap bitmap = UserIcons.convertToBitmap(
1549 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1550 mUserManager.setUserIcon(userInfo.id, bitmap);
1551 return bitmap;
1552 }
1553
Eric Jeong1545f3b2019-09-16 13:56:52 -07001554 private interface UserFilter {
1555 boolean isEligibleUser(UserInfo user);
1556 }
1557
1558 /** Returns all users who are matched by the given filter. */
1559 private List<UserInfo> getUsers(UserFilter filter) {
1560 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1561
1562 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1563 UserInfo user = iterator.next();
1564 if (!filter.isEligibleUser(user)) {
1565 iterator.remove();
1566 }
1567 }
1568 return users;
1569 }
1570
1571 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001572 * Enforces that apps which have the
1573 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1574 * can make certain calls to the CarUserManager.
1575 *
1576 * @param message used as message if SecurityException is thrown.
1577 * @throws SecurityException if the caller is not system or root.
1578 */
1579 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001580 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1581 }
1582
1583 private static void checkManageUsersOrDumpPermission(String message) {
1584 checkAtLeastOnePermission(message,
1585 android.Manifest.permission.MANAGE_USERS,
1586 android.Manifest.permission.DUMP);
1587 }
1588
Felipe Leme5528ff72020-02-10 19:05:14 -08001589 private void checkInteractAcrossUsersPermission(String message) {
1590 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1591 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1592 }
1593
felipeal2d0483c2019-11-02 14:07:22 -07001594 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001595 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001596 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1597 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001598 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001599 }
1600 }
1601
felipeal2d0483c2019-11-02 14:07:22 -07001602 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1603 for (String permission : permissions) {
1604 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1605 /* exported = */ true)
1606 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1607 return true;
1608 }
1609 }
1610 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001611 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001612
1613 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1614 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1615 // Count all users that are managed profiles of the given user.
1616 int managedProfilesCount = 0;
1617 for (UserInfo user : users) {
1618 if (user.isManagedProfile() && user.profileGroupId == userId) {
1619 managedProfilesCount++;
1620 }
1621 }
1622 return managedProfilesCount;
1623 }
1624
1625 /**
1626 * Starts the first passenger of the given driver and assigns the passenger to the front
1627 * passenger zone.
1628 *
1629 * @param driverId User id of the driver.
1630 * @return whether it succeeds.
1631 */
1632 private boolean startFirstPassenger(@UserIdInt int driverId) {
1633 int zoneId = getAvailablePassengerZone();
1634 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1635 Log.w(TAG_USER, "passenger occupant zone is not found");
1636 return false;
1637 }
1638 List<UserInfo> passengers = getPassengers(driverId);
1639 if (passengers.size() < 1) {
1640 Log.w(TAG_USER, "passenger is not found");
1641 return false;
1642 }
1643 // Only one passenger is supported. If there are two or more passengers, the first passenger
1644 // is chosen.
1645 int passengerId = passengers.get(0).id;
1646 if (!startPassenger(passengerId, zoneId)) {
1647 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1648 return false;
1649 }
1650 return true;
1651 }
1652
1653 private int getAvailablePassengerZone() {
1654 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1655 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1656 for (int occupantType : occupantTypes) {
1657 int zoneId = getZoneId(occupantType);
1658 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1659 return zoneId;
1660 }
1661 }
1662 return OccupantZoneInfo.INVALID_ZONE_ID;
1663 }
1664
1665 /**
1666 * Creates a new passenger user when there is no passenger user.
1667 */
1668 private void setupPassengerUser() {
1669 int currentUser = ActivityManager.getCurrentUser();
1670 int profileCount = getNumberOfManagedProfiles(currentUser);
1671 if (profileCount > 0) {
1672 Log.w(TAG_USER, "max profile of user" + currentUser
1673 + " is exceeded: current profile count is " + profileCount);
1674 return;
1675 }
1676 // TODO(b/140311342): Use resource string for the default passenger name.
1677 UserInfo passenger = createPassenger("Passenger", currentUser);
1678 if (passenger == null) {
1679 // Couldn't create user, most likely because there are too many.
1680 Log.w(TAG_USER, "cannot create a passenger user");
1681 return;
1682 }
1683 }
1684
1685 @NonNull
1686 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1687 ZoneUserBindingHelper helper = null;
1688 synchronized (mLockHelper) {
1689 if (mZoneUserBindingHelper == null) {
1690 Log.w(TAG_USER, "implementation is not delegated");
1691 return new ArrayList<OccupantZoneInfo>();
1692 }
1693 helper = mZoneUserBindingHelper;
1694 }
1695 return helper.getOccupantZones(occupantType);
1696 }
1697
1698 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1699 ZoneUserBindingHelper helper = null;
1700 synchronized (mLockHelper) {
1701 if (mZoneUserBindingHelper == null) {
1702 Log.w(TAG_USER, "implementation is not delegated");
1703 return false;
1704 }
1705 helper = mZoneUserBindingHelper;
1706 }
1707 return helper.assignUserToOccupantZone(userId, zoneId);
1708 }
1709
1710 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1711 ZoneUserBindingHelper helper = null;
1712 synchronized (mLockHelper) {
1713 if (mZoneUserBindingHelper == null) {
1714 Log.w(TAG_USER, "implementation is not delegated");
1715 return false;
1716 }
1717 helper = mZoneUserBindingHelper;
1718 }
1719 return helper.unassignUserFromOccupantZone(userId);
1720 }
1721
1722 private boolean isPassengerDisplayAvailable() {
1723 ZoneUserBindingHelper helper = null;
1724 synchronized (mLockHelper) {
1725 if (mZoneUserBindingHelper == null) {
1726 Log.w(TAG_USER, "implementation is not delegated");
1727 return false;
1728 }
1729 helper = mZoneUserBindingHelper;
1730 }
1731 return helper.isPassengerDisplayAvailable();
1732 }
1733
1734 /**
1735 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1736 * zone is returned.
1737 *
1738 * @param occupantType The type of an occupant.
1739 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1740 * if not found.
1741 */
1742 private int getZoneId(@OccupantTypeEnum int occupantType) {
1743 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1744 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1745 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001746}