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