blob: 8436fe714f469b8257d4b02bf139a4057377f818 [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;
25import android.app.IActivityManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070026import android.car.ICarUserService;
jovanak24470652018-09-11 17:51:57 -070027import android.car.settings.CarSettings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070028import android.content.Context;
Eric Jeong1545f3b2019-09-16 13:56:52 -070029import android.content.pm.UserInfo;
30import android.graphics.Bitmap;
Ying Zheng1ab32b62018-06-26 12:47:26 -070031import android.location.LocationManager;
Eric Jeong1545f3b2019-09-16 13:56:52 -070032import android.os.Binder;
33import android.os.Bundle;
Keun young Parkfb656372019-03-12 18:37:55 -070034import android.os.RemoteException;
Ying Zhengcf20f442018-06-22 16:54:51 -070035import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070036import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070037import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070038import android.util.Log;
39
40import com.android.car.CarServiceBase;
Keun-young Parkd462a912019-02-11 08:53:42 -080041import com.android.internal.annotations.GuardedBy;
Keun young Parkf3523cd2019-04-08 10:09:17 -070042import com.android.internal.annotations.VisibleForTesting;
Eric Jeong1545f3b2019-09-16 13:56:52 -070043import com.android.internal.util.Preconditions;
44import com.android.internal.util.UserIcons;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070045
46import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080047import java.util.ArrayList;
Eric Jeong1545f3b2019-09-16 13:56:52 -070048import java.util.Iterator;
49import java.util.List;
Pavel Maltsev17e81832019-04-04 14:38:41 -070050import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070051
52/**
53 * User service for cars. Manages users at boot time. Including:
54 *
55 * <ol>
Eric Jeong1545f3b2019-09-16 13:56:52 -070056 * <li> Creates a user used as driver.
57 * <li> Creates a user used as passenger.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070058 * <li> Creates a secondary admin user on first run.
Eric Jeong1545f3b2019-09-16 13:56:52 -070059 * <li> Switch drivers.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070060 * <ol/>
61 */
Eric Jeong1545f3b2019-09-16 13:56:52 -070062public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
Ying Zhengd3cb98e2018-05-11 11:42:48 -070063 private final Context mContext;
Keun young Parkfb656372019-03-12 18:37:55 -070064 private final IActivityManager mAm;
Anthony Hugh9932a252019-06-12 16:19:56 -070065 private final UserManager mUserManager;
66 private final int mMaxRunningUsers;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070067
Eric Jeong1545f3b2019-09-16 13:56:52 -070068 /**
69 * Default restrictions for Non-Admin users.
70 */
71 private static final String[] DEFAULT_NON_ADMIN_RESTRICTIONS = new String[] {
72 UserManager.DISALLOW_FACTORY_RESET
73 };
74
75 /**
76 * Default restrictions for Guest users.
77 */
78 private static final String[] DEFAULT_GUEST_RESTRICTIONS = new String[] {
79 UserManager.DISALLOW_FACTORY_RESET,
80 UserManager.DISALLOW_REMOVE_USER,
81 UserManager.DISALLOW_MODIFY_ACCOUNTS,
82 UserManager.DISALLOW_INSTALL_APPS,
83 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
84 UserManager.DISALLOW_UNINSTALL_APPS
85 };
86
87 /**
88 * List of restrictions relaxed for Non-Admin users.
89 *
90 * <p>Each non-admin has sms and outgoing call restrictions applied by the UserManager on
91 * creation. We want to enable these permissions by default in the car.
92 */
93 private static final String[] RELAXED_RESTRICTIONS_FOR_NON_ADMIN = new String[] {
94 UserManager.DISALLOW_SMS,
95 UserManager.DISALLOW_OUTGOING_CALLS
96 };
97
Keun-young Parkd462a912019-02-11 08:53:42 -080098 private final Object mLock = new Object();
99 @GuardedBy("mLock")
100 private boolean mUser0Unlocked;
101 @GuardedBy("mLock")
102 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Keun young Parkf3523cd2019-04-08 10:09:17 -0700103 /**
104 * Background users that will be restarted in garage mode. This list can include the
105 * current foreground user bit the current foreground user should not be restarted.
106 */
Keun young Parkfb656372019-03-12 18:37:55 -0700107 @GuardedBy("mLock")
Keun young Parkf3523cd2019-04-08 10:09:17 -0700108 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
109 /**
110 * Keep the list of background users started here. This is wholly for debugging purpose.
111 */
112 @GuardedBy("mLock")
113 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
114
Pavel Maltsev17e81832019-04-04 14:38:41 -0700115 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
116
117 /** Interface for callbacks related to user activities. */
118 public interface UserCallback {
119 /** Gets called when user lock status has been changed. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700120 void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700121 /** Called when new foreground user started to boot. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700122 void onSwitchUser(@UserIdInt int userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700123 }
124
Eric Jeong1545f3b2019-09-16 13:56:52 -0700125 public CarUserService(@NonNull Context context, @NonNull UserManager userManager,
126 @NonNull IActivityManager am, int maxRunningUsers) {
127 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
128 Log.d(TAG_USER, "constructed");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700129 }
130 mContext = context;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700131 mAm = am;
132 mMaxRunningUsers = maxRunningUsers;
Anthony Hugh9932a252019-06-12 16:19:56 -0700133 mUserManager = userManager;
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700134 }
135
136 @Override
137 public void init() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700138 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
139 Log.d(TAG_USER, "init");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700140 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700141 }
142
143 @Override
144 public void release() {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700145 if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
146 Log.d(TAG_USER, "release");
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700147 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700148 }
149
150 @Override
Eric Jeong1545f3b2019-09-16 13:56:52 -0700151 public void dump(@NonNull PrintWriter writer) {
152 writer.println("*CarUserService*");
Keun-young Parkd462a912019-02-11 08:53:42 -0800153 synchronized (mLock) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700154 writer.println("User0Unlocked: " + mUser0Unlocked);
155 writer.println("MaxRunningUsers: " + mMaxRunningUsers);
156 writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
157 writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
158 writer.println("NumberOfDrivers: " + getAllDrivers().size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800159 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700160 }
161
162 /**
163 * @see CarUserManager.createDriver
164 */
165 @Override
166 @Nullable
167 public UserInfo createDriver(@NonNull String name, boolean admin) {
168 checkManageUsersPermission("createDriver");
169 Preconditions.checkNotNull(name, "name cannot be null");
170 if (admin) {
171 return createNewAdminUser(name);
172 }
173 return createNewNonAdminUser(name);
174 }
175
176 /**
177 * @see CarUserManager.createPassenger
178 */
179 @Override
180 @Nullable
181 public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
182 checkManageUsersPermission("createPassenger");
183 Preconditions.checkNotNull(name, "name cannot be null");
184 UserInfo driver = mUserManager.getUserInfo(driverId);
185 if (driver == null) {
186 Log.w(TAG_USER, "the driver is invalid");
187 return null;
188 }
189 if (driver.isGuest()) {
190 Log.w(TAG_USER, "a guest driver cannot create a passenger");
191 return null;
192 }
193 UserInfo user = mUserManager.createProfileForUser(name, UserInfo.FLAG_MANAGED_PROFILE,
194 driverId);
195 if (user == null) {
196 // Couldn't create user, most likely because there are too many.
197 Log.w(TAG_USER, "can't create a profile for user" + driverId);
198 return null;
199 }
200 // Passenger user should be a non-admin user.
201 setDefaultNonAdminRestrictions(user, /* enable= */ true);
202 assignDefaultIcon(user);
203 return user;
204 }
205
206 /**
207 * @see CarUserManager.switchDriver
208 */
209 @Override
210 public boolean switchDriver(@UserIdInt int driverId) {
211 checkManageUsersPermission("switchDriver");
212 if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
213 // System user doesn't associate with real person, can not be switched to.
214 Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
215 return false;
216 }
217 int userSwitchable = mUserManager.getUserSwitchability();
218 if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
219 Log.w(TAG_USER, "current process is not allowed to switch user");
220 return false;
221 }
222 if (driverId == getCurrentUserId()) {
223 // The current user is already the given user.
224 return true;
225 }
226 try {
227 return mAm.switchUser(driverId);
228 } catch (RemoteException e) {
229 // ignore
230 Log.w(TAG_USER, "error while switching user", e);
231 }
232 return false;
233 }
234
235 /**
236 * @see CarUserManager.getAllDrivers
237 */
238 @Override
239 @NonNull
240 public List<UserInfo> getAllDrivers() {
241 checkManageUsersPermission("getAllDrivers");
242 return getUsers((user) -> {
243 return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
244 && !user.isEphemeral();
245 });
246 }
247
248 /**
249 * @see CarUserManager.getPassengers
250 * @return
251 */
252 @Override
253 @NonNull
254 public List<UserInfo> getPassengers(@UserIdInt int driverId) {
255 checkManageUsersPermission("getPassengers");
256 return getUsers((user) -> {
257 return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
258 && user.profileGroupId == driverId;
259 });
260 }
261
262 /**
263 * @see CarUserManager.startPassenger
264 */
265 @Override
266 public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
267 checkManageUsersPermission("startPassenger");
268 // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
269 return false;
270 }
271
272 /**
273 * @see CarUserManager.stopPassenger
274 */
275 @Override
276 public boolean stopPassenger(@UserIdInt int passengerId) {
277 checkManageUsersPermission("stopPassenger");
278 // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
279 return false;
280 }
281
282 /** Returns whether the given user is a system user. */
283 private static boolean isSystemUser(@UserIdInt int userId) {
284 return userId == UserHandle.USER_SYSTEM;
285 }
286
287 /** Returns whether the user running the current process has a restriction. */
288 private boolean isCurrentProcessUserHasRestriction(String restriction) {
289 return mUserManager.hasUserRestriction(restriction);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700290 }
291
Keun young Park13a7a822019-04-04 15:53:08 -0700292 private void updateDefaultUserRestriction() {
293 // We want to set restrictions on system and guest users only once. These are persisted
294 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
295 if (Settings.Global.getInt(mContext.getContentResolver(),
Eric Jeong1545f3b2019-09-16 13:56:52 -0700296 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
297 return;
Keun young Park13a7a822019-04-04 15:53:08 -0700298 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700299 // Only apply the system user restrictions if the system user is headless.
300 if (UserManager.isHeadlessSystemUserMode()) {
301 setSystemUserRestrictions();
302 }
303 initDefaultGuestRestrictions();
304 Settings.Global.putInt(mContext.getContentResolver(),
305 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Keun young Park13a7a822019-04-04 15:53:08 -0700306 }
307
Eric Jeong1545f3b2019-09-16 13:56:52 -0700308 /**
309 * Sets default guest restrictions that will be applied every time a Guest user is created.
310 *
311 * <p> Restrictions are written to disk and persistent across boots.
312 */
313 private void initDefaultGuestRestrictions() {
314 Bundle defaultGuestRestrictions = new Bundle();
315 for (String restriction : DEFAULT_GUEST_RESTRICTIONS) {
316 defaultGuestRestrictions.putBoolean(restriction, true);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700317 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700318 mUserManager.setDefaultGuestRestrictions(defaultGuestRestrictions);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700319 }
Ying Zheng1ab32b62018-06-26 12:47:26 -0700320
Eric Jeong1545f3b2019-09-16 13:56:52 -0700321 private boolean isPersistentUser(@UserIdInt int userId) {
Anthony Hugh9932a252019-06-12 16:19:56 -0700322 return !mUserManager.getUserInfo(userId).isEphemeral();
323 }
324
Eric Jeong1545f3b2019-09-16 13:56:52 -0700325 /** Adds callback to listen to user activity events. */
326 public void addUserCallback(@NonNull UserCallback callback) {
327 Preconditions.checkNotNull(callback, "callback cannot be null");
Pavel Maltsev17e81832019-04-04 14:38:41 -0700328 mUserCallbacks.add(callback);
329 }
330
Yabin Huang27712d72019-06-26 12:46:30 -0700331 /** Removes previously added callback to listen user events. */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700332 public void removeUserCallback(@NonNull UserCallback callback) {
333 Preconditions.checkNotNull(callback, "callback cannot be null");
Pavel Maltsev38da4312019-04-08 10:38:38 -0700334 mUserCallbacks.remove(callback);
335 }
336
Keun-young Parkd462a912019-02-11 08:53:42 -0800337 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700338 * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
339 *
340 * @param userId User id whoes lock status is changed.
341 * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
Keun-young Parkd462a912019-02-11 08:53:42 -0800342 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700343 public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
Pavel Maltsev17e81832019-04-04 14:38:41 -0700344 for (UserCallback callback : mUserCallbacks) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700345 callback.onUserLockChanged(userId, unlocked);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700346 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700347 if (!unlocked) { // nothing else to do when it is locked back.
348 return;
349 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800350 ArrayList<Runnable> tasks = null;
351 synchronized (mLock) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700352 if (userId == UserHandle.USER_SYSTEM) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700353 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
354 updateDefaultUserRestriction();
355 tasks = new ArrayList<>(mUser0UnlockTasks);
356 mUser0UnlockTasks.clear();
357 mUser0Unlocked = unlocked;
358 }
359 } else { // none user0
Eric Jeong1545f3b2019-09-16 13:56:52 -0700360 Integer user = userId;
361 if (isPersistentUser(userId)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700362 // current foreground user should stay in top priority.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700363 if (userId == getCurrentUserId()) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700364 mBackgroundUsersToRestart.remove(user);
365 mBackgroundUsersToRestart.add(0, user);
366 }
367 // -1 for user 0
368 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700369 int userToDrop = mBackgroundUsersToRestart.get(
Keun young Parkf3523cd2019-04-08 10:09:17 -0700370 mBackgroundUsersToRestart.size() - 1);
Eric Jeong1545f3b2019-09-16 13:56:52 -0700371 Log.i(TAG_USER, "New user unlocked:" + userId
Keun young Parkf3523cd2019-04-08 10:09:17 -0700372 + ", dropping least recently user from restart list:" + userToDrop);
373 // Drop the least recently used user.
374 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
375 }
376 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800377 }
378 }
379 if (tasks != null && tasks.size() > 0) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700380 Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
Keun-young Parkd462a912019-02-11 08:53:42 -0800381 for (Runnable r : tasks) {
382 r.run();
383 }
384 }
385 }
386
387 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700388 * Starts all background users that were active in system.
389 *
Keun young Parkfb656372019-03-12 18:37:55 -0700390 * @return list of background users started successfully.
391 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700392 @NonNull
Keun young Parkfb656372019-03-12 18:37:55 -0700393 public ArrayList<Integer> startAllBackgroundUsers() {
394 ArrayList<Integer> users;
395 synchronized (mLock) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700396 users = new ArrayList<>(mBackgroundUsersToRestart);
397 mBackgroundUsersRestartedHere.clear();
398 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
Keun young Parkfb656372019-03-12 18:37:55 -0700399 }
400 ArrayList<Integer> startedUsers = new ArrayList<>();
401 for (Integer user : users) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700402 if (user == getCurrentUserId()) {
Keun young Parkfb656372019-03-12 18:37:55 -0700403 continue;
404 }
405 try {
406 if (mAm.startUserInBackground(user)) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700407 if (mUserManager.isUserUnlockingOrUnlocked(user)) {
408 // already unlocked / unlocking. No need to unlock.
Keun young Parkfb656372019-03-12 18:37:55 -0700409 startedUsers.add(user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700410 } else if (mAm.unlockUser(user, null, null, null)) {
411 startedUsers.add(user);
412 } else { // started but cannot unlock
Eric Jeong1545f3b2019-09-16 13:56:52 -0700413 Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700414 if (mUserManager.isUserRunning(user)) {
415 // add to started list so that it can be stopped later.
416 startedUsers.add(user);
417 }
Keun young Parkfb656372019-03-12 18:37:55 -0700418 }
419 }
420 } catch (RemoteException e) {
421 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700422 Log.w(TAG_USER, "error while starting user in background", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700423 }
424 }
Keun young Parkf3523cd2019-04-08 10:09:17 -0700425 // Keep only users that were re-started in mBackgroundUsersRestartedHere
426 synchronized (mLock) {
427 ArrayList<Integer> usersToRemove = new ArrayList<>();
428 for (Integer user : mBackgroundUsersToRestart) {
429 if (!startedUsers.contains(user)) {
430 usersToRemove.add(user);
431 }
432 }
433 mBackgroundUsersRestartedHere.removeAll(usersToRemove);
434 }
Keun young Parkfb656372019-03-12 18:37:55 -0700435 return startedUsers;
436 }
437
438 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700439 * Stops all background users that were active in system.
440 *
441 * @return whether stopping succeeds.
Keun young Parkfb656372019-03-12 18:37:55 -0700442 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700443 public boolean stopBackgroundUser(@UserIdInt int userId) {
Keun young Parkf3523cd2019-04-08 10:09:17 -0700444 if (userId == UserHandle.USER_SYSTEM) {
445 return false;
446 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700447 if (userId == getCurrentUserId()) {
448 Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
Keun young Parkfb656372019-03-12 18:37:55 -0700449 return false;
450 }
451 try {
452 int r = mAm.stopUser(userId, true, null);
Keun young Parkf3523cd2019-04-08 10:09:17 -0700453 if (r == ActivityManager.USER_OP_SUCCESS) {
454 synchronized (mLock) {
455 Integer user = userId;
456 mBackgroundUsersRestartedHere.remove(user);
457 }
458 } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
459 return false;
460 } else {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700461 Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
Keun young Parkfb656372019-03-12 18:37:55 -0700462 return false;
463 }
464 } catch (RemoteException e) {
465 // ignore
Eric Jeong1545f3b2019-09-16 13:56:52 -0700466 Log.w(TAG_USER, "error while stopping user", e);
Keun young Parkfb656372019-03-12 18:37:55 -0700467 }
468 return true;
469 }
470
471 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700472 * Called when new foreground user started to boot.
473 *
Eric Jeong1545f3b2019-09-16 13:56:52 -0700474 * @param userId User id of new user.
Pavel Maltsev17e81832019-04-04 14:38:41 -0700475 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700476 public void onSwitchUser(@UserIdInt int userId) {
477 if (!isSystemUser(userId) && isPersistentUser(userId)) {
478 setLastActiveUser(userId);
479 }
Pavel Maltsev17e81832019-04-04 14:38:41 -0700480 for (UserCallback callback : mUserCallbacks) {
Eric Jeong1545f3b2019-09-16 13:56:52 -0700481 callback.onSwitchUser(userId);
Pavel Maltsev17e81832019-04-04 14:38:41 -0700482 }
483 }
484
485 /**
Eric Jeong1545f3b2019-09-16 13:56:52 -0700486 * 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 -0800487 * run inside this call.
Eric Jeong1545f3b2019-09-16 13:56:52 -0700488 *
Keun-young Parkd462a912019-02-11 08:53:42 -0800489 * @param r Runnable to run.
490 */
Eric Jeong1545f3b2019-09-16 13:56:52 -0700491 public void runOnUser0Unlock(@NonNull Runnable r) {
492 Preconditions.checkNotNull(r, "runnable cannot be null");
Keun-young Parkd462a912019-02-11 08:53:42 -0800493 boolean runNow = false;
494 synchronized (mLock) {
495 if (mUser0Unlocked) {
496 runNow = true;
497 } else {
498 mUser0UnlockTasks.add(r);
499 }
500 }
501 if (runNow) {
502 r.run();
503 }
504 }
505
Keun young Parkf3523cd2019-04-08 10:09:17 -0700506 @VisibleForTesting
Eric Jeong1545f3b2019-09-16 13:56:52 -0700507 @NonNull
508 ArrayList<Integer> getBackgroundUsersToRestart() {
509 ArrayList<Integer> backgroundUsersToRestart = null;
Keun young Parkf3523cd2019-04-08 10:09:17 -0700510 synchronized (mLock) {
511 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
512 }
513 return backgroundUsersToRestart;
514 }
515
Ying Zheng1ab32b62018-06-26 12:47:26 -0700516 private void setSystemUserRestrictions() {
517 // Disable adding accounts for system user.
Anthony Hugh9932a252019-06-12 16:19:56 -0700518 UserHandle systemUserHandle = UserHandle.of(UserHandle.USER_SYSTEM);
519 mUserManager.setUserRestriction(
520 UserManager.DISALLOW_MODIFY_ACCOUNTS, /* value= */ true, systemUserHandle);
Ying Zheng1ab32b62018-06-26 12:47:26 -0700521
522 // Disable Location service for system user.
523 LocationManager locationManager =
524 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
Anthony Hugh9932a252019-06-12 16:19:56 -0700525 locationManager.setLocationEnabledForUser(/* enabled= */ false, systemUserHandle);
Ying Zheng1ab32b62018-06-26 12:47:26 -0700526 }
Eric Jeong1545f3b2019-09-16 13:56:52 -0700527
528 /**
529 * Creates a new user on the system, the created user would be granted admin role.
530 *
531 * @param name Name to be given to the newly created user.
532 * @return Newly created admin user, {@code null} if it fails to create a user.
533 */
534 @Nullable
535 private UserInfo createNewAdminUser(String name) {
536 if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
537 // Only admins or system user can create other privileged users.
538 Log.e(TAG_USER, "Only admin users and system user can create other admins.");
539 return null;
540 }
541
542 UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
543 if (user == null) {
544 // Couldn't create user, most likely because there are too many.
545 Log.w(TAG_USER, "can't create admin user.");
546 return null;
547 }
548 assignDefaultIcon(user);
549
550 return user;
551 }
552
553 /**
554 * Creates a new non-admin user on the system.
555 *
556 * @param name Name to be given to the newly created user.
557 * @return Newly created non-admin user, {@code null} if failed to create a user.
558 */
559 @Nullable
560 private UserInfo createNewNonAdminUser(String name) {
561 UserInfo user = mUserManager.createUser(name, /* flags= */ 0);
562 if (user == null) {
563 // Couldn't create user, most likely because there are too many.
564 Log.w(TAG_USER, "can't create non-admin user.");
565 return null;
566 }
567 setDefaultNonAdminRestrictions(user, /* enable= */ true);
568
569 // Remove restrictions which are allowed for non-admin car users.
570 for (String restriction : RELAXED_RESTRICTIONS_FOR_NON_ADMIN) {
571 mUserManager.setUserRestriction(restriction, /* enable= */ false, user.getUserHandle());
572 }
573
574 assignDefaultIcon(user);
575 return user;
576 }
577
578 private Bitmap getUserDefaultIcon(UserInfo userInfo) {
579 return UserIcons.convertToBitmap(
580 UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
581 }
582
583 private Bitmap getGuestDefaultIcon() {
584 return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(mContext.getResources(),
585 UserHandle.USER_NULL, false));
586 }
587
588 /** Assigns a default icon to a user according to the user's id. */
589 private void assignDefaultIcon(UserInfo userInfo) {
590 Bitmap bitmap = userInfo.isGuest()
591 ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
592 mUserManager.setUserIcon(userInfo.id, bitmap);
593 }
594
595 private void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
596 for (String restriction : DEFAULT_NON_ADMIN_RESTRICTIONS) {
597 mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle());
598 }
599 }
600
601 /** Gets the current user on the device. */
602 @VisibleForTesting
603 @UserIdInt
604 int getCurrentUserId() {
605 UserInfo user = getCurrentUser();
606 return user != null ? user.id : UserHandle.USER_NULL;
607 }
608
609 @Nullable
610 private UserInfo getCurrentUser() {
611 UserInfo user = null;
612 try {
613 user = mAm.getCurrentUser();
614 } catch (RemoteException e) {
615 // ignore
616 Log.w(TAG_USER, "error while getting current user", e);
617 }
618 return user;
619 }
620
621 private interface UserFilter {
622 boolean isEligibleUser(UserInfo user);
623 }
624
625 /** Returns all users who are matched by the given filter. */
626 private List<UserInfo> getUsers(UserFilter filter) {
627 List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
628
629 for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
630 UserInfo user = iterator.next();
631 if (!filter.isEligibleUser(user)) {
632 iterator.remove();
633 }
634 }
635 return users;
636 }
637
638 /**
639 * Sets last active user.
640 *
641 * @param userId Last active user id.
642 */
643 @VisibleForTesting
644 void setLastActiveUser(@UserIdInt int userId) {
645 Settings.Global.putInt(
646 mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, userId);
647 }
648
649 /**
650 * Enforces that apps which have the
651 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
652 * can make certain calls to the CarUserManager.
653 *
654 * @param message used as message if SecurityException is thrown.
655 * @throws SecurityException if the caller is not system or root.
656 */
657 private static void checkManageUsersPermission(String message) {
658 int callingUid = Binder.getCallingUid();
659 if (!hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)) {
660 throw new SecurityException(
661 "You need MANAGE_USERS permission to: " + message);
662 }
663 }
664
665 private static boolean hasPermissionGranted(String permission, int uid) {
666 return ActivityManager.checkComponentPermission(
667 permission, uid, /* owningUid = */-1, /* exported = */ true)
668 == android.content.pm.PackageManager.PERMISSION_GRANTED;
669 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700670}