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