• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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