blob: a6e74c10bc9994d48f5e1d93f510c244ef24f359 [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;
felipeal5e3ede42020-04-23 18:04:07 -070036import android.car.user.GetUserIdentificationAssociationResponse;
felipeale5bf0322020-04-16 15:10:57 -070037import android.car.user.UserSwitchResult;
Eric Jeong3a793b02019-09-30 16:12:53 -070038import android.car.userlib.CarUserManagerHelper;
felipeal19e3d732020-03-18 12:07:32 -070039import android.car.userlib.HalCallback;
40import android.car.userlib.UserHalHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070041import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070042import android.content.pm.UserInfo;
Felipe Leme315a53b2020-03-12 10:51:04 -070043import android.content.res.Resources;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070044import android.graphics.Bitmap;
Felipe Lemee3cab982020-03-12 11:39:29 -070045import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080046import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
Mayank Garg59f22192020-03-27 00:51:45 -070047import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
felipeal5e3ede42020-04-23 18:04:07 -070048import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
49import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
Felipe Lemec6e3c2a2020-02-19 16:53:57 -080050import android.hardware.automotive.vehicle.V2_0.UsersInfo;
Ying Zheng1ab32b62018-06-26 12:47:26 -070051import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070052import android.os.Binder;
Felipe Leme5528ff72020-02-10 19:05:14 -080053import android.os.Bundle;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070054import android.os.Handler;
55import android.os.HandlerThread;
Keun young Parkfb656372019-03-12 18:37:55 -070056import android.os.RemoteException;
Mayank Garg31e73042020-01-23 00:10:38 -080057import android.os.Trace;
Ying Zhengcf20f442018-06-22 16:54:51 -070058import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070059import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070060import android.provider.Settings;
Felipe Lemee3cab982020-03-12 11:39:29 -070061import android.sysprop.CarProperties;
felipeal312416a2020-04-14 12:28:24 -070062import android.util.EventLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070063import android.util.Log;
Felipe Leme5528ff72020-02-10 19:05:14 -080064import android.util.SparseArray;
Mayank Garg31e73042020-01-23 00:10:38 -080065import android.util.TimingsTraceLog;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070066
67import com.android.car.CarServiceBase;
Keun young Parkb241d022020-04-20 20:31:34 -070068import com.android.car.CarServiceUtils;
Eric Jeongc91f9452019-08-30 15:04:21 -070069import com.android.car.R;
Felipe Leme58412202020-01-09 13:45:33 -080070import com.android.car.hal.UserHalService;
Keun-young Parkd462a912019-02-11 08:53:42 -080071import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070072import com.android.internal.annotations.VisibleForTesting;
felipeal312416a2020-04-14 12:28:24 -070073import com.android.internal.car.EventLogTags;
felipeale5bf0322020-04-16 15:10:57 -070074import com.android.internal.infra.AndroidFuture;
Felipe Leme5528ff72020-02-10 19:05:14 -080075import com.android.internal.os.IResultReceiver;
felipeal5e3ede42020-04-23 18:04:07 -070076import com.android.internal.util.ArrayUtils;
felipeal2a84d512020-04-06 18:52:15 -070077import com.android.internal.util.FunctionalUtils;
Mayank Garge19c2922020-03-30 18:05:53 -070078import com.android.internal.util.Preconditions;
Anthony Hugh6fed1e92019-10-22 16:22:03 -070079import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070080
81import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080082import java.util.ArrayList;
felipeal2d0483c2019-11-02 14:07:22 -070083import java.util.Arrays;
Eric Jeong1545f3b2019-09-16 13:56:52 -070084import java.util.Iterator;
85import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000086import java.util.Objects;
Pavel Maltsev17e81832019-04-04 14:38:41 -070087import java.util.concurrent.CopyOnWriteArrayList;
Antonio Kantek7236a5b2020-04-06 19:53:55 -070088import java.util.concurrent.CountDownLatch;
89import java.util.concurrent.TimeUnit;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070090
91/**
92 * User service for cars. Manages users at boot time. Including:
93 *
94 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070095 * <li> Creates a user used as driver.
96 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070098 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070099 * <ol/>
100 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700101public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Felipe Leme5528ff72020-02-10 19:05:14 -0800102
felipealf7368962020-04-16 12:55:19 -0700103 private static final String TAG = TAG_USER;
104
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800105 /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800106 public static final String BUNDLE_USER_ID = "user.id";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800107 /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800108 public static final String BUNDLE_USER_FLAGS = "user.flags";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800109 /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800110 public static final String BUNDLE_USER_NAME = "user.name";
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800111 /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
112 public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
Felipe Leme5528ff72020-02-10 19:05:14 -0800113
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700114 private final Context mContext;
Eric Jeong3a793b02019-09-30 16:12:53 -0700115 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -0700116 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -0700117 private final UserManager mUserManager;
118 private final int mMaxRunningUsers;
Eric Jeongc91f9452019-08-30 15:04:21 -0700119 private final boolean mEnablePassengerSupport;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700120
Eric Jeongc91f9452019-08-30 15:04:21 -0700121 private final Object mLockUser = new Object();
122 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800123 private boolean mUser0Unlocked;
Eric Jeongc91f9452019-08-30 15:04:21 -0700124 @GuardedBy("mLockUser")
Keun-young Parkd462a912019-02-11 08:53:42 -0800125 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Eric Jeongc91f9452019-08-30 15:04:21 -0700126 // Only one passenger is supported.
127 @GuardedBy("mLockUser")
128 private @UserIdInt int mLastPassengerId;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700129 /**
130 * Background users that will be restarted in garage mode. This list can include the
Mayank Garg31e73042020-01-23 00:10:38 -0800131 * current foreground user but the current foreground user should not be restarted.
Keun young Parkf3523cd2019-04-08 10:09:17 -0700132 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700133 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700134 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
135 /**
136 * Keep the list of background users started here. This is wholly for debugging purpose.
137 */
Eric Jeongc91f9452019-08-30 15:04:21 -0700138 @GuardedBy("mLockUser")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700139 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
140
Felipe Leme58412202020-01-09 13:45:33 -0800141 private final UserHalService mHal;
142
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700143 // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
Keun young Parkb241d022020-04-20 20:31:34 -0700144 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
145 getClass().getSimpleName());
146 private final Handler mHandler = new Handler(mHandlerThread.getLooper());
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700147
Felipe Leme5528ff72020-02-10 19:05:14 -0800148 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800149 * List of listeners to be notified on new user activities events.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700150 * This collection should be accessed and manipulated by mHandlerThread only.
Antonio Kantekc8114752020-03-05 21:37:39 -0800151 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700152 private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
Antonio Kantekc8114752020-03-05 21:37:39 -0800153
154 /**
Felipe Leme5528ff72020-02-10 19:05:14 -0800155 * List of lifecycle listeners by uid.
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700156 * This collection should be accessed and manipulated by mHandlerThread only.
Felipe Leme5528ff72020-02-10 19:05:14 -0800157 */
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700158 private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
Felipe Leme5528ff72020-02-10 19:05:14 -0800159
Mayank Garg7a114c82020-04-08 21:25:06 -0700160 /**
161 * User Id for the user switch in process, if any.
162 */
163 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700164 private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg7a114c82020-04-08 21:25:06 -0700165 /**
166 * Request Id for the user switch in process, if any.
167 */
168 @GuardedBy("mLockUser")
felipealf7368962020-04-16 12:55:19 -0700169 private int mRequestIdForUserSwitchInProcess;
Felipe Lemee3cab982020-03-12 11:39:29 -0700170 private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
171
Eric Jeongc91f9452019-08-30 15:04:21 -0700172 private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
173 new CopyOnWriteArrayList<>();
174
felipeal61ce3732020-04-03 11:01:00 -0700175 @Nullable
176 @GuardedBy("mLockUser")
177 private UserInfo mInitialUser;
178
Mayank Garg71661ea2020-04-29 01:25:03 -0700179 private UserMetrics mUserMetrics;
felipeale8c5dce2020-04-15 11:27:06 -0700180
Eric Jeongc91f9452019-08-30 15:04:21 -0700181 /** Interface for callbaks related to passenger activities. */
182 public interface PassengerCallback {
183 /** Called when passenger is started at a certain zone. */
184 void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
185 /** Called when passenger is stopped. */
186 void onPassengerStopped(@UserIdInt int passengerId);
187 }
188
189 /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
190 public interface ZoneUserBindingHelper {
191 /** Gets occupant zones corresponding to the occupant type. */
192 @NonNull
193 List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
194 /** Assigns the user to the occupant zone. */
195 boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
196 /** Makes the occupant zone unoccupied. */
197 boolean unassignUserFromOccupantZone(@UserIdInt int userId);
198 /** Returns whether there is a passenger display. */
199 boolean isPassengerDisplayAvailable();
200 }
201
202 private final Object mLockHelper = new Object();
203 @GuardedBy("mLockHelper")
204 private ZoneUserBindingHelper mZoneUserBindingHelper;
205
Felipe Leme58412202020-01-09 13:45:33 -0800206 public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
Mayank Garg71661ea2020-04-29 01:25:03 -0700207 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
208 @NonNull IActivityManager am, int maxRunningUsers) {
209 this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
210 new UserMetrics());
211 }
212
213 @VisibleForTesting
214 CarUserService(@NonNull Context context, @NonNull UserHalService hal,
215 @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
216 @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700217 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
218 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700219 }
220 mContext = context;
Felipe Leme58412202020-01-09 13:45:33 -0800221 mHal = hal;
Eric Jeong3a793b02019-09-30 16:12:53 -0700222 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700223 mAm = am;
224 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700225 mUserManager = userManager;
Eric Jeongc91f9452019-08-30 15:04:21 -0700226 mLastPassengerId = UserHandle.USER_NULL;
227 mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
Mayank Garg71661ea2020-04-29 01:25:03 -0700228 mUserMetrics = userMetrics;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700229 }
230
231 @Override
232 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700233 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
234 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700235 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700236 }
237
238 @Override
239 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700240 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
241 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700242 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700243 }
244
245 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700246 public void dump(@NonNull PrintWriter writer) {
felipeal2d0483c2019-11-02 14:07:22 -0700247 checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700248 writer.println("*CarUserService*");
Felipe Leme5528ff72020-02-10 19:05:14 -0800249 String indent = " ";
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700250 handleDumpListeners(writer, indent);
Eric Jeongc91f9452019-08-30 15:04:21 -0700251 synchronized (mLockUser) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700252 writer.println("User0Unlocked: " + mUser0Unlocked);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700253 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
254 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700255 }
256 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
257 List<UserInfo> allDrivers = getAllDrivers();
258 int driversSize = allDrivers.size();
259 writer.println("NumberOfDrivers: " + driversSize);
260 for (int i = 0; i < driversSize; i++) {
261 int driverId = allDrivers.get(i).id;
262 writer.print(indent + "#" + i + ": id=" + driverId);
263 List<UserInfo> passengers = getPassengers(driverId);
264 int passengersSize = passengers.size();
265 writer.print(" NumberPassengers: " + passengersSize);
266 if (passengersSize > 0) {
267 writer.print(" [");
268 for (int j = 0; j < passengersSize; j++) {
269 writer.print(passengers.get(j).id);
270 if (j < passengersSize - 1) {
271 writer.print(" ");
felipeal2d0483c2019-11-02 14:07:22 -0700272 }
felipeal2d0483c2019-11-02 14:07:22 -0700273 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700274 writer.print("]");
felipeal2d0483c2019-11-02 14:07:22 -0700275 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700276 writer.println();
277 }
278 writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
279 writer.printf("User HAL timeout: %dms\n", mHalTimeoutMs);
280 writer.printf("Initial user: %s\n", mInitialUser);
281 writer.println("Relevant overlayable properties");
282 Resources res = mContext.getResources();
283 writer.printf("%sowner_name=%s\n", indent,
284 res.getString(com.android.internal.R.string.owner_name));
285 writer.printf("%sdefault_guest_name=%s\n", indent,
286 res.getString(R.string.default_guest_name));
felipealf7368962020-04-16 12:55:19 -0700287 writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
Mayank Garg7a114c82020-04-08 21:25:06 -0700288 writer.printf("Request Id for the user switch in process=%d\n ",
289 mRequestIdForUserSwitchInProcess);
felipeale8c5dce2020-04-15 11:27:06 -0700290
291 dumpUserMetrics(writer);
292 }
293
294 /**
295 * Dumps user metrics.
296 */
297 public void dumpUserMetrics(@NonNull PrintWriter writer) {
298 mUserMetrics.dump(writer);
299 }
300
301 /**
302 * Dumps first user unlocking time.
303 */
304 public void dumpFirstUserUnlockDuration(PrintWriter writer) {
305 mUserMetrics.dumpFirstUserUnlockDuration(writer);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700306 }
307
308 private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
309 CountDownLatch latch = new CountDownLatch(1);
310 mHandler.post(() -> {
311 handleDumpUserLifecycleListeners(writer);
312 handleDumpAppLifecycleListeners(writer, indent);
313 latch.countDown();
314 });
315 int timeout = 5;
316 try {
317 if (!latch.await(timeout, TimeUnit.SECONDS)) {
318 writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
319 timeout);
320 }
321 } catch (InterruptedException e) {
322 Thread.currentThread().interrupt();
323 writer.println("Interrupted waiting for handler thread to dump app and user listeners");
324 }
325 }
326
327 private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
328 if (mUserLifecycleListeners.isEmpty()) {
329 writer.println("No user lifecycle listeners");
330 return;
331 }
332 writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
333 for (UserLifecycleListener listener : mUserLifecycleListeners) {
334 writer.printf("Listener %s\n", listener);
335 }
336 }
337
338 private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
339 int numberListeners = mAppLifecycleListeners.size();
340 if (numberListeners == 0) {
341 writer.println("No lifecycle listeners");
342 return;
343 }
344 writer.printf("%d lifecycle listeners\n", numberListeners);
345 for (int i = 0; i < numberListeners; i++) {
346 int uid = mAppLifecycleListeners.keyAt(i);
347 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
348 writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
Keun-young Parkd462a912019-02-11 08:53:42 -0800349 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700350 }
351
352 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800353 * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
354 *
355 * @param name The name of the driver to be created.
356 * @param admin Whether the created driver will be an admin.
357 * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
358 * not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700359 */
360 @Override
361 @Nullable
362 public UserInfo createDriver(@NonNull String name, boolean admin) {
363 checkManageUsersPermission("createDriver");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000364 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700365 if (admin) {
366 return createNewAdminUser(name);
367 }
Eric Jeong3a793b02019-09-30 16:12:53 -0700368 return mCarUserManagerHelper.createNewNonAdminUser(name);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700369 }
370
371 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800372 * Creates a passenger who is a profile of the given driver.
373 *
374 * @param name The name of the passenger to be created.
375 * @param driverId User id of the driver under whom a passenger is created.
376 * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
377 * could not be created.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700378 */
379 @Override
380 @Nullable
381 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
382 checkManageUsersPermission("createPassenger");
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000383 Objects.requireNonNull(name, "name cannot be null");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700384 UserInfo driver = mUserManager.getUserInfo(driverId);
385 if (driver == null) {
386 Log.w(TAG_USER, "the driver is invalid");
387 return null;
388 }
389 if (driver.isGuest()) {
390 Log.w(TAG_USER, "a guest driver cannot create a passenger");
391 return null;
392 }
Bookatz42fb1a62019-10-30 11:45:01 -0700393 UserInfo user = mUserManager.createProfileForUser(name,
394 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700395 if (user == null) {
396 // Couldn't create user, most likely because there are too many.
397 Log.w(TAG_USER, "can't create a profile for user" + driverId);
398 return null;
399 }
400 // Passenger user should be a non-admin user.
Eric Jeong3a793b02019-09-30 16:12:53 -0700401 mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
Anthony Hugh6fed1e92019-10-22 16:22:03 -0700402 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700403 return user;
404 }
405
406 /**
407 * @see CarUserManager.switchDriver
408 */
409 @Override
410 public boolean switchDriver(@UserIdInt int driverId) {
411 checkManageUsersPermission("switchDriver");
412 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
413 // System user doesn't associate with real person, can not be switched to.
414 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
415 return false;
416 }
417 int userSwitchable = mUserManager.getUserSwitchability();
418 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
419 Log.w(TAG_USER, "current process is not allowed to switch user");
420 return false;
421 }
Anthony Hughfbb67762019-10-15 12:54:54 -0700422 if (driverId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700423 // The current user is already the given user.
424 return true;
425 }
426 try {
427 return mAm.switchUser(driverId);
428 } catch (RemoteException e) {
429 // ignore
430 Log.w(TAG_USER, "error while switching user", e);
431 }
432 return false;
433 }
434
435 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800436 * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
437 *
438 * @return the list of {@link UserInfo} who can be a driver on the device.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700439 */
440 @Override
441 @NonNull
442 public List<UserInfo> getAllDrivers() {
felipeal2d0483c2019-11-02 14:07:22 -0700443 checkManageUsersOrDumpPermission("getAllDrivers");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700444 return getUsers((user) -> !isSystemUser(user.id) && user.isEnabled()
445 && !user.isManagedProfile() && !user.isEphemeral());
Eric Jeong1545f3b2019-09-16 13:56:52 -0700446 }
447
448 /**
Eric Jeonge7916fc2019-12-20 14:03:34 -0800449 * Returns all passengers under the given driver.
450 *
451 * @param driverId User id of a driver.
452 * @return the list of {@link UserInfo} who is a passenger under the given driver.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700453 */
454 @Override
455 @NonNull
456 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
felipeal2d0483c2019-11-02 14:07:22 -0700457 checkManageUsersOrDumpPermission("getPassengers");
Eric Jeong1545f3b2019-09-16 13:56:52 -0700458 return getUsers((user) -> {
459 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
460 && user.profileGroupId == driverId;
461 });
462 }
463
464 /**
465 * @see CarUserManager.startPassenger
466 */
467 @Override
468 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
469 checkManageUsersPermission("startPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700470 synchronized (mLockUser) {
471 try {
472 if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
473 Log.w(TAG_USER, "could not start passenger");
474 return false;
475 }
476 } catch (RemoteException e) {
477 // ignore
478 Log.w(TAG_USER, "error while starting passenger", e);
479 return false;
480 }
481 if (!assignUserToOccupantZone(passengerId, zoneId)) {
482 Log.w(TAG_USER, "could not assign passenger to zone");
483 return false;
484 }
485 mLastPassengerId = passengerId;
486 }
487 for (PassengerCallback callback : mPassengerCallbacks) {
488 callback.onPassengerStarted(passengerId, zoneId);
489 }
490 return true;
Eric Jeong1545f3b2019-09-16 13:56:52 -0700491 }
492
493 /**
494 * @see CarUserManager.stopPassenger
495 */
496 @Override
497 public boolean stopPassenger(@UserIdInt int passengerId) {
498 checkManageUsersPermission("stopPassenger");
Eric Jeongc91f9452019-08-30 15:04:21 -0700499 return stopPassengerInternal(passengerId, true);
500 }
501
502 private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
503 synchronized (mLockUser) {
504 UserInfo passenger = mUserManager.getUserInfo(passengerId);
505 if (passenger == null) {
506 Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
507 return false;
508 }
509 if (mLastPassengerId != passengerId) {
510 Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
511 return true;
512 }
513 if (checkCurrentDriver) {
514 int currentUser = ActivityManager.getCurrentUser();
515 if (passenger.profileGroupId != currentUser) {
516 Log.w(TAG_USER, "passenger " + passengerId
517 + " is not a profile of the current user");
518 return false;
519 }
520 }
521 // Passenger is a profile, so cannot be stopped through activity manager.
522 // Instead, activities started by the passenger are stopped and the passenger is
523 // unassigned from the zone.
524 stopAllTasks(passengerId);
525 if (!unassignUserFromOccupantZone(passengerId)) {
526 Log.w(TAG_USER, "could not unassign user from occupant zone");
527 return false;
528 }
529 mLastPassengerId = UserHandle.USER_NULL;
530 }
531 for (PassengerCallback callback : mPassengerCallbacks) {
532 callback.onPassengerStopped(passengerId);
533 }
534 return true;
535 }
536
537 private void stopAllTasks(@UserIdInt int userId) {
538 try {
539 for (StackInfo info : mAm.getAllStackInfos()) {
540 for (int i = 0; i < info.taskIds.length; i++) {
541 if (info.taskUserIds[i] == userId) {
542 int taskId = info.taskIds[i];
543 if (!mAm.removeTask(taskId)) {
544 Log.w(TAG_USER, "could not remove task " + taskId);
545 }
546 }
547 }
548 }
549 } catch (RemoteException e) {
550 Log.e(TAG_USER, "could not get stack info", e);
551 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700552 }
553
Felipe Leme5528ff72020-02-10 19:05:14 -0800554 @Override
555 public void setLifecycleListenerForUid(IResultReceiver listener) {
556 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700557 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800558 checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
559
560 try {
561 listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
562 } catch (RemoteException e) {
563 Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
564 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700565 mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
Felipe Leme5528ff72020-02-10 19:05:14 -0800566 }
567
568 private void onListenerDeath(int uid) {
569 Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700570 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800571 }
572
573 @Override
574 public void resetLifecycleListenerForUid() {
575 int uid = Binder.getCallingUid();
felipeal312416a2020-04-14 12:28:24 -0700576 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
Felipe Leme5528ff72020-02-10 19:05:14 -0800577 checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700578 mHandler.post(() -> mAppLifecycleListeners.remove(uid));
Felipe Leme5528ff72020-02-10 19:05:14 -0800579 }
580
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800581 @Override
582 public void getInitialUserInfo(int requestType, int timeoutMs,
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800583 @NonNull IResultReceiver receiver) {
felipeal312416a2020-04-14 12:28:24 -0700584 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
585 timeoutMs);
Felipe Lemee2600fc2020-02-26 11:06:04 -0800586 Objects.requireNonNull(receiver, "receiver cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700587 checkManageUsersPermission("getInitialInfo");
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800588 UsersInfo usersInfo = getUsersInfo();
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800589 mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
Mayank Garg0e239142020-04-14 19:16:31 -0700590 Bundle resultData = null;
591 if (resp != null) {
felipeal312416a2020-04-14 12:28:24 -0700592 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
593 status, resp.action, resp.userToSwitchOrCreate.userId,
594 resp.userToSwitchOrCreate.flags, resp.userNameToCreate);
Mayank Garg0e239142020-04-14 19:16:31 -0700595 switch (resp.action) {
596 case InitialUserInfoResponseAction.SWITCH:
597 resultData = new Bundle();
598 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
599 resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
600 break;
601 case InitialUserInfoResponseAction.CREATE:
602 resultData = new Bundle();
603 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
604 resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
605 resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
606 break;
607 case InitialUserInfoResponseAction.DEFAULT:
608 resultData = new Bundle();
609 resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
610 break;
611 default:
612 // That's ok, it will be the same as DEFAULT...
613 Log.w(TAG_USER, "invalid response action on " + resp);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800614 }
felipeal312416a2020-04-14 12:28:24 -0700615 } else {
616 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800617 }
Mayank Garg0e239142020-04-14 19:16:31 -0700618 sendResult(receiver, status, resultData);
Felipe Lemec6e3c2a2020-02-19 16:53:57 -0800619 });
620 }
621
Felipe Lemee3cab982020-03-12 11:39:29 -0700622 /**
felipeal61ce3732020-04-03 11:01:00 -0700623 * Gets the initial foreground user after the device boots or resumes from suspension.
624 *
625 * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
626 * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
627 * method returns {@code null}.
628 *
629 * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
630 * (like switching to the last active user), and this method will return the result of such
631 * operation.
632 *
633 * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
634 * {@code null}.
635 *
636 * @hide
637 */
638 @Nullable
639 public UserInfo getInitialUser() {
640 checkInteractAcrossUsersPermission("getInitialUser");
641 synchronized (mLockUser) {
642 return mInitialUser;
643 }
644 }
645
646 // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
647 // some reason passing the whole UserInfo through a raw binder transaction is not working.
648 /**
649 * Sets the initial foreground user after the device boots or resumes from suspension.
650 */
651 public void setInitialUser(@UserIdInt int userId) {
652 UserInfo initialUser = userId == UserHandle.USER_NULL ? null
653 : mUserManager.getUserInfo(userId);
654 setInitialUser(initialUser);
655 }
656
657 /**
658 * Sets the initial foreground user after the device boots or resumes from suspension.
659 */
660 public void setInitialUser(@Nullable UserInfo user) {
felipeal312416a2020-04-14 12:28:24 -0700661 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
662 user == null ? UserHandle.USER_NULL : user.id);
felipeal61ce3732020-04-03 11:01:00 -0700663 synchronized (mLockUser) {
664 mInitialUser = user;
665 }
666 if (user == null) {
667 // This mean InitialUserSetter failed and could not fallback, so the initial user was
668 // not switched (and most likely is SYSTEM_USER).
669 // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
670 Log.wtf(TAG_USER, "Initial user set to null");
671 }
672 }
673
674 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700675 * Calls the User HAL to get the initial user info.
676 *
677 * @param requestType type as defined by {@code InitialUserInfoRequestType}.
678 * @param callback callback to receive the results.
679 */
680 public void getInitialUserInfo(int requestType,
681 HalCallback<InitialUserInfoResponse> callback) {
felipeal312416a2020-04-14 12:28:24 -0700682 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
683 mHalTimeoutMs);
Felipe Lemee3cab982020-03-12 11:39:29 -0700684 Objects.requireNonNull(callback, "callback cannot be null");
felipeal0ec1ff02020-03-27 17:18:28 -0700685 checkManageUsersPermission("getInitialUserInfo");
Felipe Lemee3cab982020-03-12 11:39:29 -0700686 UsersInfo usersInfo = getUsersInfo();
687 mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
688 }
689
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700690 // TODO(b/154966308): update javadoc
Felipe Lemee3cab982020-03-12 11:39:29 -0700691 /**
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700692 * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
693 *
694 * <p>
695 * First {@link UserHalService} is called for HAL user switch. If HAL user switch is successful,
696 * {@link IActivityManager} is called for Android user switch, otherwise Android user is not
697 * switched and HAL is informed about Android switch failure.
698 *
699 * <p>
700 * If target user is already the current user, no user switch is performed and receiver would
701 * receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
702 *
703 * <p>
704 * If another user switch request for the same target user is received while previous request is
705 * in process, receiver would receive {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for
706 * the new request right away.
707 *
708 * <p>
709 * If a user switch request is received while another user switch request for different target
710 * user is in process, previous request would be abandoned and new request will be processed.
Mayank Garg59f22192020-03-27 00:51:45 -0700711 *
Mayank Garge19c2922020-03-30 18:05:53 -0700712 * @param targetUserId - target user Id
Mayank Garg59f22192020-03-27 00:51:45 -0700713 * @param timeoutMs - timeout for HAL to wait
714 * @param receiver - receiver for the results
715 */
Mayank Garge19c2922020-03-30 18:05:53 -0700716 @Override
717 public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
felipeale5bf0322020-04-16 15:10:57 -0700718 @NonNull AndroidFuture<UserSwitchResult> receiver) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700719 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
Mayank Garg59f22192020-03-27 00:51:45 -0700720 checkManageUsersPermission("switchUser");
Mayank Garge19c2922020-03-30 18:05:53 -0700721 Objects.requireNonNull(receiver);
722 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
felipealf7368962020-04-16 12:55:19 -0700723 Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
Mayank Garg7a114c82020-04-08 21:25:06 -0700724
felipealf7368962020-04-16 12:55:19 -0700725 int currentUser = ActivityManager.getCurrentUser();
726 if (currentUser == targetUserId) {
Mayank Garg0e239142020-04-14 19:16:31 -0700727 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
728 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
729 }
felipeale5bf0322020-04-16 15:10:57 -0700730 int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
731 sendResult(receiver, resultStatus);
Mayank Garg0e239142020-04-14 19:16:31 -0700732 return;
733 }
734
Mayank Garg7a114c82020-04-08 21:25:06 -0700735 synchronized (mLockUser) {
felipealf7368962020-04-16 12:55:19 -0700736 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
737 Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
738 + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
739 }
740
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700741 // If there is another request for the same target user, return another request in
742 // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
743 // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
744 // user switch request in process for different target user, but that request is now
745 // ignored.
felipealf7368962020-04-16 12:55:19 -0700746 if (mUserIdForUserSwitchInProcess == targetUserId) {
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700747 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
748 Log.d(TAG_USER,
749 "Another user switch request in process for the requested target user: "
750 + targetUserId);
751 }
752
753 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
felipeale5bf0322020-04-16 15:10:57 -0700754 sendResult(receiver, resultStatus);
Mayank Garg7a114c82020-04-08 21:25:06 -0700755 return;
756 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700757 else {
758 mUserIdForUserSwitchInProcess = targetUserId;
759 mRequestIdForUserSwitchInProcess = 0;
760 }
Mayank Garg7a114c82020-04-08 21:25:06 -0700761 }
762
Mayank Garg59f22192020-03-27 00:51:45 -0700763 UsersInfo usersInfo = getUsersInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700764 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
Mayank Garg59f22192020-03-27 00:51:45 -0700765 new android.hardware.automotive.vehicle.V2_0.UserInfo();
Mayank Garg7a114c82020-04-08 21:25:06 -0700766 halTargetUser.userId = targetUser.id;
767 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
768 mHal.switchUser(halTargetUser, timeoutMs, usersInfo, (status, resp) -> {
felipealf7368962020-04-16 12:55:19 -0700769 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
770 Log.d(TAG, "switch response: status="
771 + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
772 }
773
felipeale5bf0322020-04-16 15:10:57 -0700774 int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
felipealf7368962020-04-16 12:55:19 -0700775
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700776 synchronized (mLockUser) {
777 if (status != HalCallback.STATUS_OK) {
778 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
779 Log.w(TAG, "invalid callback status ("
780 + UserHalHelper.halCallbackStatusToString(status) + ") for response "
781 + resp);
782 sendResult(receiver, resultStatus);
783 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
784 return;
785 }
felipealf7368962020-04-16 12:55:19 -0700786
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700787 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
788 resp.errorMessage);
789
790 if (mUserIdForUserSwitchInProcess != targetUserId) {
791 // Another user switch request received while HAL responded. No need to process
792 // this request further
793 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
794 Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
795 + "abondoned for : " + targetUserId + ". Current user in process: "
796 + mUserIdForUserSwitchInProcess);
felipealf7368962020-04-16 12:55:19 -0700797 }
Mayank Garg1f20dcd2020-04-22 17:46:01 -0700798 resultStatus =
799 UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
800 sendResult(receiver, resultStatus);
801 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
802 return;
803 }
804
805 switch (resp.status) {
806 case SwitchUserStatus.SUCCESS:
807 boolean switched;
808 try {
809 switched = mAm.switchUser(targetUserId);
810 if (switched) {
811 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
812 mRequestIdForUserSwitchInProcess = resp.requestId;
813 } else {
814 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
815 postSwitchHalResponse(resp.requestId, targetUserId);
816 }
817 } catch (RemoteException e) {
818 // ignore
819 Log.w(TAG_USER,
820 "error while switching user " + targetUser.toFullString(), e);
821 }
822 break;
823 case SwitchUserStatus.FAILURE:
824 // HAL failed to switch user
825 resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
826 break;
827 }
828
829 if (mRequestIdForUserSwitchInProcess == 0) {
830 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
831 }
Mayank Garg59f22192020-03-27 00:51:45 -0700832 }
felipeale5bf0322020-04-16 15:10:57 -0700833 sendResult(receiver, resultStatus, resp.errorMessage);
Mayank Garg59f22192020-03-27 00:51:45 -0700834 });
835 }
836
felipeal5e3ede42020-04-23 18:04:07 -0700837 @Override
838 public GetUserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
839 Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
840 checkManageUsersPermission("getUserIdentificationAssociation");
841
842 int uid = getCallingUid();
843 int userId = UserHandle.getUserId(uid);
844 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
845
846 UserIdentificationGetRequest request = new UserIdentificationGetRequest();
847 request.userInfo.userId = userId;
848 request.userInfo.flags = getHalUserInfoFlags(userId);
849
850 request.numberAssociationTypes = types.length;
851 for (int i = 0; i < types.length; i++) {
852 request.associationTypes.add(types[i]);
853 }
854
855 UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
856 if (halResponse == null) {
857 Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
858 + Arrays.toString(types));
859 return null;
860 }
861
862 int[] values = new int[halResponse.associations.size()];
863 for (int i = 0; i < values.length; i++) {
864 values[i] = halResponse.associations.get(i).value;
865 }
866 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
867
868 return new GetUserIdentificationAssociationResponse(halResponse.errorMessage, values);
869 }
870
871 /**
872 * Gets the User HAL flags for the given user.
873 *
874 * @throws IllegalArgumentException if the user does not exist.
875 */
876 private int getHalUserInfoFlags(@UserIdInt int userId) {
877 UserInfo user = mUserManager.getUserInfo(userId);
878 Preconditions.checkArgument(user != null, "no user for id %d", userId);
879 return UserHalHelper.convertFlags(user);
880 }
881
Mayank Garg0e239142020-04-14 19:16:31 -0700882 private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
883 @Nullable Bundle resultData) {
884 try {
885 receiver.send(resultCode, resultData);
886 } catch (RemoteException e) {
887 // ignore
888 Log.w(TAG_USER, "error while sending results", e);
889 }
890 }
891
felipeale5bf0322020-04-16 15:10:57 -0700892 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
893 @UserSwitchResult.Status int status) {
894 sendResult(receiver, status, /* errorMessage= */ null);
895 }
896
897 private void sendResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
898 @UserSwitchResult.Status int status, @Nullable String errorMessage) {
899 receiver.complete(new UserSwitchResult(status, errorMessage));
900 }
901
Mayank Garg7a114c82020-04-08 21:25:06 -0700902 private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
903 UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
904 UsersInfo usersInfo = getUsersInfo();
905 android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
906 new android.hardware.automotive.vehicle.V2_0.UserInfo();
907 halTargetUser.userId = targetUser.id;
908 halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
felipeal312416a2020-04-14 12:28:24 -0700909 EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
910 targetUserId, usersInfo.currentUser.userId);
Mayank Garg7a114c82020-04-08 21:25:06 -0700911 mHal.postSwitchResponse(requestId, halTargetUser, usersInfo);
912 }
913
Mayank Garg59f22192020-03-27 00:51:45 -0700914 /**
Felipe Lemee3cab982020-03-12 11:39:29 -0700915 * Checks if the User HAL is supported.
916 */
917 public boolean isUserHalSupported() {
918 return mHal.isSupported();
919 }
920
Felipe Lemeabbf2da2020-02-24 18:25:29 -0800921 // TODO(b/144120654): use helper to generate UsersInfo
922 private UsersInfo getUsersInfo() {
923 UserInfo currentUser;
924 try {
925 currentUser = mAm.getCurrentUser();
926 } catch (RemoteException e) {
927 // shouldn't happen
928 throw new IllegalStateException("Could not get current user: ", e);
929 }
930 List<UserInfo> existingUsers = mUserManager.getUsers();
931 int size = existingUsers.size();
932
933 UsersInfo usersInfo = new UsersInfo();
934 usersInfo.numberUsers = size;
935 usersInfo.currentUser.userId = currentUser.id;
936 usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
937
938 for (int i = 0; i < size; i++) {
939 UserInfo androidUser = existingUsers.get(i);
940 android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
941 new android.hardware.automotive.vehicle.V2_0.UserInfo();
942 halUser.userId = androidUser.id;
943 halUser.flags = UserHalHelper.convertFlags(androidUser);
944 usersInfo.existingUsers.add(halUser);
945 }
946
947 return usersInfo;
948 }
949
Eric Jeong1545f3b2019-09-16 13:56:52 -0700950 /** Returns whether the given user is a system user. */
951 private static boolean isSystemUser(@UserIdInt int userId) {
952 return userId == UserHandle.USER_SYSTEM;
953 }
954
Keun young Park13a7a822019-04-04 15:53:08 -0700955 private void updateDefaultUserRestriction() {
956 // We want to set restrictions on system and guest users only once. These are persisted
957 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
958 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700959 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
960 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700961 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700962 // Only apply the system user restrictions if the system user is headless.
963 if (UserManager.isHeadlessSystemUserMode()) {
964 setSystemUserRestrictions();
965 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700966 Settings.Global.putInt(mContext.getContentResolver(),
967 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700968 }
969
Eric Jeong1545f3b2019-09-16 13:56:52 -0700970 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700971 return !mUserManager.getUserInfo(userId).isEphemeral();
972 }
973
Antonio Kantekc8114752020-03-05 21:37:39 -0800974 /**
Antonio Kantekc8114752020-03-05 21:37:39 -0800975 * Adds a new {@link UserLifecycleListener} to listen to user activity events.
976 */
977 public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
978 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700979 mHandler.post(() -> mUserLifecycleListeners.add(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800980 }
981
982 /**
983 * Removes previously added {@link UserLifecycleListener}.
984 */
985 public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
986 Objects.requireNonNull(listener, "listener cannot be null");
Antonio Kantek7236a5b2020-04-06 19:53:55 -0700987 mHandler.post(() -> mUserLifecycleListeners.remove(listener));
Antonio Kantekc8114752020-03-05 21:37:39 -0800988 }
989
Eric Jeongc91f9452019-08-30 15:04:21 -0700990 /** Adds callback to listen to passenger activity events. */
991 public void addPassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000992 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700993 mPassengerCallbacks.add(callback);
994 }
995
996 /** Removes previously added callback to listen passenger events. */
997 public void removePassengerCallback(@NonNull PassengerCallback callback) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +0000998 Objects.requireNonNull(callback, "callback cannot be null");
Eric Jeongc91f9452019-08-30 15:04:21 -0700999 mPassengerCallbacks.remove(callback);
1000 }
1001
1002 /** Sets the implementation of ZoneUserBindingHelper. */
1003 public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
1004 synchronized (mLockHelper) {
1005 mZoneUserBindingHelper = helper;
1006 }
1007 }
1008
felipeal98900c82020-04-09 09:05:02 -07001009 private void onUserUnlocked(@UserIdInt int userId) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001010 ArrayList<Runnable> tasks = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001011 synchronized (mLockUser) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001012 sendPostSwitchToHalLocked(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001013 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001014 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
1015 updateDefaultUserRestriction();
1016 tasks = new ArrayList<>(mUser0UnlockTasks);
1017 mUser0UnlockTasks.clear();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001018 mUser0Unlocked = true;
Keun young Parkf3523cd2019-04-08 10:09:17 -07001019 }
1020 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -07001021 Integer user = userId;
1022 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001023 // current foreground user should stay in top priority.
Anthony Hughfbb67762019-10-15 12:54:54 -07001024 if (userId == ActivityManager.getCurrentUser()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001025 mBackgroundUsersToRestart.remove(user);
1026 mBackgroundUsersToRestart.add(0, user);
1027 }
1028 // -1 for user 0
1029 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001030 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -07001031 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001032 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -07001033 + ", dropping least recently user from restart list:" + userToDrop);
1034 // Drop the least recently used user.
1035 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
1036 }
1037 }
Keun-young Parkd462a912019-02-11 08:53:42 -08001038 }
1039 }
1040 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001041 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -08001042 for (Runnable r : tasks) {
1043 r.run();
1044 }
1045 }
1046 }
1047
1048 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001049 * Starts all background users that were active in system.
1050 *
Keun young Parkfb656372019-03-12 18:37:55 -07001051 * @return list of background users started successfully.
1052 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001053 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -07001054 public ArrayList<Integer> startAllBackgroundUsers() {
1055 ArrayList<Integer> users;
Eric Jeongc91f9452019-08-30 15:04:21 -07001056 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001057 users = new ArrayList<>(mBackgroundUsersToRestart);
1058 mBackgroundUsersRestartedHere.clear();
1059 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -07001060 }
1061 ArrayList<Integer> startedUsers = new ArrayList<>();
1062 for (Integer user : users) {
Anthony Hughfbb67762019-10-15 12:54:54 -07001063 if (user == ActivityManager.getCurrentUser()) {
Keun young Parkfb656372019-03-12 18:37:55 -07001064 continue;
1065 }
1066 try {
1067 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001068 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
1069 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -07001070 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001071 } else if (mAm.unlockUser(user, null, null, null)) {
1072 startedUsers.add(user);
1073 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -07001074 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001075 if (mUserManager.isUserRunning(user)) {
1076 // add to started list so that it can be stopped later.
1077 startedUsers.add(user);
1078 }
Keun young Parkfb656372019-03-12 18:37:55 -07001079 }
1080 }
1081 } catch (RemoteException e) {
1082 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001083 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001084 }
1085 }
Keun young Parkf3523cd2019-04-08 10:09:17 -07001086 // Keep only users that were re-started in mBackgroundUsersRestartedHere
Eric Jeongc91f9452019-08-30 15:04:21 -07001087 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001088 ArrayList<Integer> usersToRemove = new ArrayList<>();
1089 for (Integer user : mBackgroundUsersToRestart) {
1090 if (!startedUsers.contains(user)) {
1091 usersToRemove.add(user);
1092 }
1093 }
1094 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
1095 }
Keun young Parkfb656372019-03-12 18:37:55 -07001096 return startedUsers;
1097 }
1098
1099 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001100 * Stops all background users that were active in system.
1101 *
1102 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -07001103 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001104 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001105 if (userId == UserHandle.USER_SYSTEM) {
1106 return false;
1107 }
Anthony Hughfbb67762019-10-15 12:54:54 -07001108 if (userId == ActivityManager.getCurrentUser()) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001109 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -07001110 return false;
1111 }
1112 try {
Keun young Parked9e6282019-09-19 17:38:26 -07001113 int r = mAm.stopUserWithDelayedLocking(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -07001114 if (r == ActivityManager.USER_OP_SUCCESS) {
Eric Jeongc91f9452019-08-30 15:04:21 -07001115 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001116 Integer user = userId;
1117 mBackgroundUsersRestartedHere.remove(user);
1118 }
1119 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
1120 return false;
1121 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001122 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -07001123 return false;
1124 }
1125 } catch (RemoteException e) {
1126 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -07001127 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -07001128 }
1129 return true;
1130 }
1131
1132 /**
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001133 * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
Pavel Maltsev17e81832019-04-04 14:38:41 -07001134 */
felipeale8c5dce2020-04-15 11:27:06 -07001135 public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
1136 @UserIdInt int fromUserId, @UserIdInt int toUserId) {
1137 int userId = toUserId;
felipeal98900c82020-04-09 09:05:02 -07001138
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001139 // Handle special cases first...
felipeal98900c82020-04-09 09:05:02 -07001140 if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
1141 onUserSwitching(userId);
1142 } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
1143 onUserUnlocked(userId);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001144 }
1145
felipeale8c5dce2020-04-15 11:27:06 -07001146 // ...then notify listeners.
Yan Zhue7921522020-04-16 15:59:25 -07001147 UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
felipeale8c5dce2020-04-15 11:27:06 -07001148
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001149 mHandler.post(() -> {
1150 handleNotifyServiceUserLifecycleListeners(event);
1151 handleNotifyAppUserLifecycleListeners(event);
1152 });
felipeale8c5dce2020-04-15 11:27:06 -07001153
1154 // Finally, update metrics.
1155 mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
1156 }
1157
1158 /**
1159 * Sets the first user unlocking metrics.
1160 */
1161 public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
1162 int halResponseTime) {
1163 mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001164 }
1165
Mayank Garg7a114c82020-04-08 21:25:06 -07001166 private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
felipealf7368962020-04-16 12:55:19 -07001167 if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001168 || mUserIdForUserSwitchInProcess != userId
1169 || mRequestIdForUserSwitchInProcess == 0) {
Mayank Garg7a114c82020-04-08 21:25:06 -07001170 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1171 Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
1172 }
1173 return;
1174 }
felipealf7368962020-04-16 12:55:19 -07001175 postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
1176 mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
Mayank Garg1f20dcd2020-04-22 17:46:01 -07001177 mRequestIdForUserSwitchInProcess = 0;
Mayank Garg7a114c82020-04-08 21:25:06 -07001178 }
1179
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001180 private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
1181 int listenersSize = mAppLifecycleListeners.size();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001182 if (listenersSize == 0) {
felipeal2a84d512020-04-06 18:52:15 -07001183 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1184 Log.d(TAG_USER, "No app listener to be notified of " + event);
1185 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001186 return;
1187 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001188 // Must use a different TimingsTraceLog because it's another thread
1189 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1190 Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
1191 }
felipeal2a84d512020-04-06 18:52:15 -07001192 int userId = event.getUserId();
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001193 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1194 t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
1195 for (int i = 0; i < listenersSize; i++) {
1196 int uid = mAppLifecycleListeners.keyAt(i);
1197 IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
1198 Bundle data = new Bundle();
1199 data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
Yan Zhue7921522020-04-16 15:59:25 -07001200
1201 int fromUid = event.getPreviousUserId();
1202 if (fromUid != UserHandle.USER_NULL) {
1203 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
1204 }
1205
felipeal2a84d512020-04-06 18:52:15 -07001206 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001207 Log.d(TAG_USER, "Notifying listener for uid " + uid);
felipeal2a84d512020-04-06 18:52:15 -07001208 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001209 try {
felipeal2a84d512020-04-06 18:52:15 -07001210 t.traceBegin("notify-app-listener-" + uid);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001211 listener.send(userId, data);
1212 } catch (RemoteException e) {
1213 Log.e(TAG_USER, "Error calling lifecycle listener", e);
1214 } finally {
1215 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001216 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001217 }
1218 t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001219 }
1220
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001221 private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001222 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
1223 if (mUserLifecycleListeners.isEmpty()) {
felipeal2a84d512020-04-06 18:52:15 -07001224 Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001225 return;
felipeal2a84d512020-04-06 18:52:15 -07001226 } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
1227 Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
1228 + event);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001229 }
felipeal2a84d512020-04-06 18:52:15 -07001230
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001231 t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
1232 + event.getEventType());
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001233 for (UserLifecycleListener listener : mUserLifecycleListeners) {
felipeal2a84d512020-04-06 18:52:15 -07001234 String listenerName = FunctionalUtils.getLambdaName(listener);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001235 try {
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001236 t.traceBegin("notify-listener-" + listenerName);
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001237 listener.onEvent(event);
1238 } catch (RuntimeException e) {
1239 Log.e(TAG_USER,
felipeal2a84d512020-04-06 18:52:15 -07001240 "Exception raised when invoking onEvent for " + listenerName, e);
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001241 } finally {
1242 t.traceEnd();
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001243 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001244 }
Antonio Kantek7236a5b2020-04-06 19:53:55 -07001245 t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001246 }
1247
felipeal98900c82020-04-09 09:05:02 -07001248 private void onUserSwitching(@UserIdInt int userId) {
Felipe Leme5528ff72020-02-10 19:05:14 -08001249 Log.i(TAG_USER, "onSwitchUser() callback for user " + userId);
1250 TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
felipeal98900c82020-04-09 09:05:02 -07001251 t.traceBegin("onUserSwitching-" + userId);
Felipe Leme5528ff72020-02-10 19:05:14 -08001252
Felipe Lemef45ee502019-12-19 10:00:14 -08001253 if (!isSystemUser(userId)) {
Eric Jeong3a793b02019-09-30 16:12:53 -07001254 mCarUserManagerHelper.setLastActiveUser(userId);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001255 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001256 if (mLastPassengerId != UserHandle.USER_NULL) {
1257 stopPassengerInternal(mLastPassengerId, false);
1258 }
1259 if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
1260 setupPassengerUser();
1261 startFirstPassenger(userId);
1262 }
felipeal98900c82020-04-09 09:05:02 -07001263 t.traceEnd();
Pavel Maltsev17e81832019-04-04 14:38:41 -07001264 }
1265
1266 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001267 * 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 -08001268 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001269 *
Keun-young Parkd462a912019-02-11 08:53:42 -08001270 * @param r Runnable to run.
1271 */
Eric Jeong1545f3b2019-09-16 13:56:52 -07001272 public void runOnUser0Unlock(@NonNull Runnable r) {
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +00001273 Objects.requireNonNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -08001274 boolean runNow = false;
Eric Jeongc91f9452019-08-30 15:04:21 -07001275 synchronized (mLockUser) {
Keun-young Parkd462a912019-02-11 08:53:42 -08001276 if (mUser0Unlocked) {
1277 runNow = true;
1278 } else {
1279 mUser0UnlockTasks.add(r);
1280 }
1281 }
1282 if (runNow) {
1283 r.run();
1284 }
1285 }
1286
Keun young Parkf3523cd2019-04-08 10:09:17 -07001287 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -07001288 @NonNull
1289 ArrayList<Integer> getBackgroundUsersToRestart() {
1290 ArrayList<Integer> backgroundUsersToRestart = null;
Eric Jeongc91f9452019-08-30 15:04:21 -07001291 synchronized (mLockUser) {
Keun young Parkf3523cd2019-04-08 10:09:17 -07001292 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
1293 }
1294 return backgroundUsersToRestart;
1295 }
1296
Ying Zheng1ab32b62018-06-26 12:47:26 -07001297 private void setSystemUserRestrictions() {
Ying Zheng1ab32b62018-06-26 12:47:26 -07001298 // Disable Location service for system user.
1299 LocationManager locationManager =
1300 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh04ee04f2019-12-17 16:11:33 -08001301 locationManager.setLocationEnabledForUser(
1302 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
Ying Zheng1ab32b62018-06-26 12:47:26 -07001303 }
Eric Jeong1545f3b2019-09-16 13:56:52 -07001304
1305 /**
1306 * Creates a new user on the system, the created user would be granted admin role.
1307 *
1308 * @param name Name to be given to the newly created user.
Eric Jeong3a793b02019-09-30 16:12:53 -07001309 * @return newly created admin user, {@code null} if it fails to create a user.
Eric Jeong1545f3b2019-09-16 13:56:52 -07001310 */
1311 @Nullable
1312 private UserInfo createNewAdminUser(String name) {
1313 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
1314 // Only admins or system user can create other privileged users.
1315 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
1316 return null;
1317 }
1318
1319 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
1320 if (user == null) {
1321 // Couldn't create user, most likely because there are too many.
1322 Log.w(TAG_USER, "can't create admin user.");
1323 return null;
1324 }
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001325 assignDefaultIcon(user);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001326
1327 return user;
1328 }
1329
Anthony Hugh6fed1e92019-10-22 16:22:03 -07001330 /**
1331 * Assigns a default icon to a user according to the user's id.
1332 *
1333 * @param userInfo User whose avatar is set to default icon.
1334 * @return Bitmap of the user icon.
1335 */
1336 private Bitmap assignDefaultIcon(UserInfo userInfo) {
1337 int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
1338 Bitmap bitmap = UserIcons.convertToBitmap(
1339 UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
1340 mUserManager.setUserIcon(userInfo.id, bitmap);
1341 return bitmap;
1342 }
1343
Eric Jeong1545f3b2019-09-16 13:56:52 -07001344 private interface UserFilter {
1345 boolean isEligibleUser(UserInfo user);
1346 }
1347
1348 /** Returns all users who are matched by the given filter. */
1349 private List<UserInfo> getUsers(UserFilter filter) {
1350 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
1351
1352 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
1353 UserInfo user = iterator.next();
1354 if (!filter.isEligibleUser(user)) {
1355 iterator.remove();
1356 }
1357 }
1358 return users;
1359 }
1360
1361 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -07001362 * Enforces that apps which have the
1363 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
1364 * can make certain calls to the CarUserManager.
1365 *
1366 * @param message used as message if SecurityException is thrown.
1367 * @throws SecurityException if the caller is not system or root.
1368 */
1369 private static void checkManageUsersPermission(String message) {
felipeal2d0483c2019-11-02 14:07:22 -07001370 checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
1371 }
1372
1373 private static void checkManageUsersOrDumpPermission(String message) {
1374 checkAtLeastOnePermission(message,
1375 android.Manifest.permission.MANAGE_USERS,
1376 android.Manifest.permission.DUMP);
1377 }
1378
Felipe Leme5528ff72020-02-10 19:05:14 -08001379 private void checkInteractAcrossUsersPermission(String message) {
1380 checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
1381 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1382 }
1383
felipeal2d0483c2019-11-02 14:07:22 -07001384 private static void checkAtLeastOnePermission(String message, String...permissions) {
Eric Jeong1545f3b2019-09-16 13:56:52 -07001385 int callingUid = Binder.getCallingUid();
felipeal2d0483c2019-11-02 14:07:22 -07001386 if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
1387 throw new SecurityException("You need one of " + Arrays.toString(permissions)
Felipe Leme5528ff72020-02-10 19:05:14 -08001388 + " to: " + message);
Eric Jeong1545f3b2019-09-16 13:56:52 -07001389 }
1390 }
1391
felipeal2d0483c2019-11-02 14:07:22 -07001392 private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
1393 for (String permission : permissions) {
1394 if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
1395 /* exported = */ true)
1396 == android.content.pm.PackageManager.PERMISSION_GRANTED) {
1397 return true;
1398 }
1399 }
1400 return false;
Eric Jeong1545f3b2019-09-16 13:56:52 -07001401 }
Eric Jeongc91f9452019-08-30 15:04:21 -07001402
1403 private int getNumberOfManagedProfiles(@UserIdInt int userId) {
1404 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
1405 // Count all users that are managed profiles of the given user.
1406 int managedProfilesCount = 0;
1407 for (UserInfo user : users) {
1408 if (user.isManagedProfile() && user.profileGroupId == userId) {
1409 managedProfilesCount++;
1410 }
1411 }
1412 return managedProfilesCount;
1413 }
1414
1415 /**
1416 * Starts the first passenger of the given driver and assigns the passenger to the front
1417 * passenger zone.
1418 *
1419 * @param driverId User id of the driver.
1420 * @return whether it succeeds.
1421 */
1422 private boolean startFirstPassenger(@UserIdInt int driverId) {
1423 int zoneId = getAvailablePassengerZone();
1424 if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
1425 Log.w(TAG_USER, "passenger occupant zone is not found");
1426 return false;
1427 }
1428 List<UserInfo> passengers = getPassengers(driverId);
1429 if (passengers.size() < 1) {
1430 Log.w(TAG_USER, "passenger is not found");
1431 return false;
1432 }
1433 // Only one passenger is supported. If there are two or more passengers, the first passenger
1434 // is chosen.
1435 int passengerId = passengers.get(0).id;
1436 if (!startPassenger(passengerId, zoneId)) {
1437 Log.w(TAG_USER, "cannot start passenger " + passengerId);
1438 return false;
1439 }
1440 return true;
1441 }
1442
1443 private int getAvailablePassengerZone() {
1444 int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
1445 CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
1446 for (int occupantType : occupantTypes) {
1447 int zoneId = getZoneId(occupantType);
1448 if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
1449 return zoneId;
1450 }
1451 }
1452 return OccupantZoneInfo.INVALID_ZONE_ID;
1453 }
1454
1455 /**
1456 * Creates a new passenger user when there is no passenger user.
1457 */
1458 private void setupPassengerUser() {
1459 int currentUser = ActivityManager.getCurrentUser();
1460 int profileCount = getNumberOfManagedProfiles(currentUser);
1461 if (profileCount > 0) {
1462 Log.w(TAG_USER, "max profile of user" + currentUser
1463 + " is exceeded: current profile count is " + profileCount);
1464 return;
1465 }
1466 // TODO(b/140311342): Use resource string for the default passenger name.
1467 UserInfo passenger = createPassenger("Passenger", currentUser);
1468 if (passenger == null) {
1469 // Couldn't create user, most likely because there are too many.
1470 Log.w(TAG_USER, "cannot create a passenger user");
1471 return;
1472 }
1473 }
1474
1475 @NonNull
1476 private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
1477 ZoneUserBindingHelper helper = null;
1478 synchronized (mLockHelper) {
1479 if (mZoneUserBindingHelper == null) {
1480 Log.w(TAG_USER, "implementation is not delegated");
1481 return new ArrayList<OccupantZoneInfo>();
1482 }
1483 helper = mZoneUserBindingHelper;
1484 }
1485 return helper.getOccupantZones(occupantType);
1486 }
1487
1488 private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
1489 ZoneUserBindingHelper helper = null;
1490 synchronized (mLockHelper) {
1491 if (mZoneUserBindingHelper == null) {
1492 Log.w(TAG_USER, "implementation is not delegated");
1493 return false;
1494 }
1495 helper = mZoneUserBindingHelper;
1496 }
1497 return helper.assignUserToOccupantZone(userId, zoneId);
1498 }
1499
1500 private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
1501 ZoneUserBindingHelper helper = null;
1502 synchronized (mLockHelper) {
1503 if (mZoneUserBindingHelper == null) {
1504 Log.w(TAG_USER, "implementation is not delegated");
1505 return false;
1506 }
1507 helper = mZoneUserBindingHelper;
1508 }
1509 return helper.unassignUserFromOccupantZone(userId);
1510 }
1511
1512 private boolean isPassengerDisplayAvailable() {
1513 ZoneUserBindingHelper helper = null;
1514 synchronized (mLockHelper) {
1515 if (mZoneUserBindingHelper == null) {
1516 Log.w(TAG_USER, "implementation is not delegated");
1517 return false;
1518 }
1519 helper = mZoneUserBindingHelper;
1520 }
1521 return helper.isPassengerDisplayAvailable();
1522 }
1523
1524 /**
1525 * Gets the zone id of the given occupant type. If there are two or more zones, the first found
1526 * zone is returned.
1527 *
1528 * @param occupantType The type of an occupant.
1529 * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
1530 * if not found.
1531 */
1532 private int getZoneId(@OccupantTypeEnum int occupantType) {
1533 List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
1534 return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
1535 }
Antonio Kantek4cf199d2020-03-27 15:56:13 -07001536}