1 /* 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 17 package com.android.car.user; 18 19 import android.annotation.Nullable; 20 import android.app.ActivityManager; 21 import android.app.IActivityManager; 22 import android.car.settings.CarSettings; 23 import android.car.userlib.CarUserManagerHelper; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.location.LocationManager; 29 import android.os.RemoteException; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.provider.Settings; 33 import android.util.Log; 34 35 import com.android.car.CarServiceBase; 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.annotations.VisibleForTesting; 38 39 import java.io.PrintWriter; 40 import java.util.ArrayList; 41 import java.util.concurrent.CopyOnWriteArrayList; 42 43 /** 44 * User service for cars. Manages users at boot time. Including: 45 * 46 * <ol> 47 * <li> Creates a secondary admin user on first run. 48 * <li> Log in to the last active user. 49 * <ol/> 50 */ 51 public class CarUserService extends BroadcastReceiver implements CarServiceBase { 52 private static final String TAG = "CarUserService"; 53 private final Context mContext; 54 private final CarUserManagerHelper mCarUserManagerHelper; 55 private final IActivityManager mAm; 56 57 private final Object mLock = new Object(); 58 @GuardedBy("mLock") 59 private boolean mUser0Unlocked; 60 @GuardedBy("mLock") 61 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>(); 62 /** 63 * Background users that will be restarted in garage mode. This list can include the 64 * current foreground user bit the current foreground user should not be restarted. 65 */ 66 @GuardedBy("mLock") 67 private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>(); 68 /** 69 * Keep the list of background users started here. This is wholly for debugging purpose. 70 */ 71 @GuardedBy("mLock") 72 private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>(); 73 74 private final int mMaxRunningUsers; 75 76 private final UserManager mUserManager; 77 78 79 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>(); 80 81 /** Interface for callbacks related to user activities. */ 82 public interface UserCallback { 83 /** Gets called when user lock status has been changed. */ onUserLockChanged(int userId, boolean unlocked)84 void onUserLockChanged(int userId, boolean unlocked); 85 /** Called when new foreground user started to boot. */ onSwitchUser(int userId)86 void onSwitchUser(int userId); 87 } 88 CarUserService( @ullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper, IActivityManager am, int maxRunningUsers)89 public CarUserService( 90 @Nullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper, 91 IActivityManager am, int maxRunningUsers) { 92 if (Log.isLoggable(TAG, Log.DEBUG)) { 93 Log.d(TAG, "constructed"); 94 } 95 mContext = context; 96 mCarUserManagerHelper = carUserManagerHelper; 97 mAm = am; 98 mMaxRunningUsers = maxRunningUsers; 99 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 100 } 101 102 @Override init()103 public void init() { 104 if (Log.isLoggable(TAG, Log.DEBUG)) { 105 Log.d(TAG, "init"); 106 } 107 IntentFilter filter = new IntentFilter(); 108 filter.addAction(Intent.ACTION_USER_SWITCHED); 109 110 mContext.registerReceiver(this, filter); 111 } 112 113 @Override release()114 public void release() { 115 if (Log.isLoggable(TAG, Log.DEBUG)) { 116 Log.d(TAG, "release"); 117 } 118 mContext.unregisterReceiver(this); 119 } 120 121 @Override dump(PrintWriter writer)122 public void dump(PrintWriter writer) { 123 writer.println(TAG); 124 boolean user0Unlocked; 125 ArrayList<Integer> backgroundUsersToRestart; 126 ArrayList<Integer> backgroundUsersRestarted; 127 synchronized (mLock) { 128 user0Unlocked = mUser0Unlocked; 129 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart); 130 backgroundUsersRestarted = new ArrayList<>(mBackgroundUsersRestartedHere); 131 132 } 133 writer.println("User0Unlocked: " + user0Unlocked); 134 writer.println("maxRunningUsers:" + mMaxRunningUsers); 135 writer.println("BackgroundUsersToRestart:" + backgroundUsersToRestart); 136 writer.println("BackgroundUsersRestarted:" + backgroundUsersRestarted); 137 } 138 updateDefaultUserRestriction()139 private void updateDefaultUserRestriction() { 140 // We want to set restrictions on system and guest users only once. These are persisted 141 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes. 142 if (Settings.Global.getInt(mContext.getContentResolver(), 143 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) { 144 // Only apply the system user restrictions if the system user is headless. 145 if (mCarUserManagerHelper.isHeadlessSystemUser()) { 146 setSystemUserRestrictions(); 147 } 148 mCarUserManagerHelper.initDefaultGuestRestrictions(); 149 Settings.Global.putInt(mContext.getContentResolver(), 150 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1); 151 } 152 } 153 154 @Override onReceive(Context context, Intent intent)155 public void onReceive(Context context, Intent intent) { 156 if (Log.isLoggable(TAG, Log.DEBUG)) { 157 Log.d(TAG, "onReceive " + intent); 158 } 159 160 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 161 // Update last active user if the switched-to user is a persistent, non-system user. 162 final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 163 if (currentUser > UserHandle.USER_SYSTEM 164 && mCarUserManagerHelper.isPersistentUser(currentUser)) { 165 mCarUserManagerHelper.setLastActiveUser(currentUser); 166 } 167 } 168 } 169 170 /** Add callback to listen to user activity events. */ addUserCallback(UserCallback callback)171 public void addUserCallback(UserCallback callback) { 172 mUserCallbacks.add(callback); 173 } 174 175 /** Removes previuosly added callback to lilsten user events. */ removeUserCallback(UserCallback callback)176 public void removeUserCallback(UserCallback callback) { 177 mUserCallbacks.remove(callback); 178 } 179 180 /** 181 * Set user lock / unlocking status. This is coming from system server through ICar binder call. 182 * @param userHandle Handle of user 183 * @param unlocked unlocked (=true) or locked (=false) 184 */ setUserLockStatus(int userHandle, boolean unlocked)185 public void setUserLockStatus(int userHandle, boolean unlocked) { 186 for (UserCallback callback : mUserCallbacks) { 187 callback.onUserLockChanged(userHandle, unlocked); 188 } 189 if (!unlocked) { // nothing else to do when it is locked back. 190 return; 191 } 192 ArrayList<Runnable> tasks = null; 193 synchronized (mLock) { 194 if (userHandle == UserHandle.USER_SYSTEM) { 195 if (!mUser0Unlocked) { // user 0, unlocked, do this only once 196 updateDefaultUserRestriction(); 197 tasks = new ArrayList<>(mUser0UnlockTasks); 198 mUser0UnlockTasks.clear(); 199 mUser0Unlocked = unlocked; 200 } 201 } else { // none user0 202 Integer user = userHandle; 203 if (mCarUserManagerHelper.isPersistentUser(userHandle)) { 204 // current foreground user should stay in top priority. 205 if (userHandle == mCarUserManagerHelper.getCurrentForegroundUserId()) { 206 mBackgroundUsersToRestart.remove(user); 207 mBackgroundUsersToRestart.add(0, user); 208 } 209 // -1 for user 0 210 if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) { 211 final int userToDrop = mBackgroundUsersToRestart.get( 212 mBackgroundUsersToRestart.size() - 1); 213 Log.i(TAG, "New user unlocked:" + userHandle 214 + ", dropping least recently user from restart list:" + userToDrop); 215 // Drop the least recently used user. 216 mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1); 217 } 218 } 219 } 220 } 221 if (tasks != null && tasks.size() > 0) { 222 Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size()); 223 for (Runnable r : tasks) { 224 r.run(); 225 } 226 } 227 } 228 229 /** 230 * Start all background users that were active in system. 231 * @return list of background users started successfully. 232 */ startAllBackgroundUsers()233 public ArrayList<Integer> startAllBackgroundUsers() { 234 ArrayList<Integer> users; 235 synchronized (mLock) { 236 users = new ArrayList<>(mBackgroundUsersToRestart); 237 mBackgroundUsersRestartedHere.clear(); 238 mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart); 239 } 240 ArrayList<Integer> startedUsers = new ArrayList<>(); 241 for (Integer user : users) { 242 if (user == mCarUserManagerHelper.getCurrentForegroundUserId()) { 243 continue; 244 } 245 try { 246 if (mAm.startUserInBackground(user)) { 247 if (mUserManager.isUserUnlockingOrUnlocked(user)) { 248 // already unlocked / unlocking. No need to unlock. 249 startedUsers.add(user); 250 } else if (mAm.unlockUser(user, null, null, null)) { 251 startedUsers.add(user); 252 } else { // started but cannot unlock 253 Log.w(TAG, "Background user started but cannot be unlocked:" + user); 254 if (mUserManager.isUserRunning(user)) { 255 // add to started list so that it can be stopped later. 256 startedUsers.add(user); 257 } 258 } 259 } 260 } catch (RemoteException e) { 261 // ignore 262 } 263 } 264 // Keep only users that were re-started in mBackgroundUsersRestartedHere 265 synchronized (mLock) { 266 ArrayList<Integer> usersToRemove = new ArrayList<>(); 267 for (Integer user : mBackgroundUsersToRestart) { 268 if (!startedUsers.contains(user)) { 269 usersToRemove.add(user); 270 } 271 } 272 mBackgroundUsersRestartedHere.removeAll(usersToRemove); 273 } 274 return startedUsers; 275 } 276 277 /** 278 * Stop all background users that were active in system. 279 * @return true if stopping succeeds. 280 */ stopBackgroundUser(int userId)281 public boolean stopBackgroundUser(int userId) { 282 if (userId == UserHandle.USER_SYSTEM) { 283 return false; 284 } 285 if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) { 286 Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId); 287 return false; 288 } 289 try { 290 int r = mAm.stopUser(userId, true, null); 291 if (r == ActivityManager.USER_OP_SUCCESS) { 292 synchronized (mLock) { 293 Integer user = userId; 294 mBackgroundUsersRestartedHere.remove(user); 295 } 296 } else if (r == ActivityManager.USER_OP_IS_CURRENT) { 297 return false; 298 } else { 299 Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r); 300 return false; 301 } 302 } catch (RemoteException e) { 303 // ignore 304 } 305 return true; 306 } 307 308 /** 309 * Called when new foreground user started to boot. 310 * 311 * @param userHandle user handle of new user 312 */ onSwitchUser(int userHandle)313 public void onSwitchUser(int userHandle) { 314 for (UserCallback callback : mUserCallbacks) { 315 callback.onSwitchUser(userHandle); 316 } 317 } 318 319 /** 320 * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is 321 * run inside this call. 322 * @param r Runnable to run. 323 */ runOnUser0Unlock(Runnable r)324 public void runOnUser0Unlock(Runnable r) { 325 boolean runNow = false; 326 synchronized (mLock) { 327 if (mUser0Unlocked) { 328 runNow = true; 329 } else { 330 mUser0UnlockTasks.add(r); 331 } 332 } 333 if (runNow) { 334 r.run(); 335 } 336 } 337 338 @VisibleForTesting getBackgroundUsersToRestart()339 protected ArrayList<Integer> getBackgroundUsersToRestart() { 340 ArrayList<Integer> backgroundUsersToRestart; 341 synchronized (mLock) { 342 backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart); 343 } 344 return backgroundUsersToRestart; 345 } 346 setSystemUserRestrictions()347 private void setSystemUserRestrictions() { 348 // Disable adding accounts for system user. 349 mCarUserManagerHelper.setUserRestriction(mCarUserManagerHelper.getSystemUserInfo(), 350 UserManager.DISALLOW_MODIFY_ACCOUNTS, /* enable= */ true); 351 352 // Disable Location service for system user. 353 LocationManager locationManager = 354 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 355 locationManager.setLocationEnabledForUser( 356 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM)); 357 } 358 } 359