blob: a5d64dc0e2747975373007cc4ab97bc9361ea3df [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
19import android.annotation.Nullable;
Keun young Parkfb656372019-03-12 18:37:55 -070020import android.app.ActivityManager;
21import android.app.IActivityManager;
jovanak24470652018-09-11 17:51:57 -070022import android.car.settings.CarSettings;
Ying Zheng9fc99402018-09-19 14:23:59 -070023import android.car.userlib.CarUserManagerHelper;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070024import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
Ying Zheng1ab32b62018-06-26 12:47:26 -070028import android.location.LocationManager;
Keun young Parkfb656372019-03-12 18:37:55 -070029import android.os.RemoteException;
Ying Zhengcf20f442018-06-22 16:54:51 -070030import android.os.UserHandle;
Ying Zheng8f90edb2018-06-13 12:42:31 -070031import android.os.UserManager;
jovanak24470652018-09-11 17:51:57 -070032import android.provider.Settings;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070033import android.util.Log;
34
35import com.android.car.CarServiceBase;
Keun-young Parkd462a912019-02-11 08:53:42 -080036import com.android.internal.annotations.GuardedBy;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070037
38import java.io.PrintWriter;
Keun-young Parkd462a912019-02-11 08:53:42 -080039import java.util.ArrayList;
Pavel Maltsev17e81832019-04-04 14:38:41 -070040import java.util.concurrent.CopyOnWriteArrayList;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070041
42/**
43 * User service for cars. Manages users at boot time. Including:
44 *
45 * <ol>
46 * <li> Creates a secondary admin user on first run.
Ying Zhengf4339b82018-06-19 16:01:05 -070047 * <li> Log in to the last active user.
Ying Zhengd3cb98e2018-05-11 11:42:48 -070048 * <ol/>
49 */
50public class CarUserService extends BroadcastReceiver implements CarServiceBase {
Ying Zhengd3cb98e2018-05-11 11:42:48 -070051 private static final String TAG = "CarUserService";
52 private final Context mContext;
53 private final CarUserManagerHelper mCarUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070054 private final IActivityManager mAm;
Ying Zhengd3cb98e2018-05-11 11:42:48 -070055
Keun-young Parkd462a912019-02-11 08:53:42 -080056 private final Object mLock = new Object();
57 @GuardedBy("mLock")
58 private boolean mUser0Unlocked;
59 @GuardedBy("mLock")
60 private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
Keun young Parkfb656372019-03-12 18:37:55 -070061 @GuardedBy("mLock")
62 private final ArrayList<Integer> mLastUnlockedUsers = new ArrayList<>();
Keun-young Parkd462a912019-02-11 08:53:42 -080063
Pavel Maltsev17e81832019-04-04 14:38:41 -070064
65 private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
66
67 /** Interface for callbacks related to user activities. */
68 public interface UserCallback {
69 /** Gets called when user lock status has been changed. */
70 void onUserLockChanged(int userId, boolean unlocked);
71 /** Called when new foreground user started to boot. */
72 void onSwitchUser(int userId);
73 }
74
Ying Zhengd3cb98e2018-05-11 11:42:48 -070075 public CarUserService(
76 @Nullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper) {
77 if (Log.isLoggable(TAG, Log.DEBUG)) {
78 Log.d(TAG, "constructed");
79 }
80 mContext = context;
81 mCarUserManagerHelper = carUserManagerHelper;
Keun young Parkfb656372019-03-12 18:37:55 -070082 mAm = ActivityManager.getService();
Ying Zhengd3cb98e2018-05-11 11:42:48 -070083 }
84
85 @Override
86 public void init() {
87 if (Log.isLoggable(TAG, Log.DEBUG)) {
88 Log.d(TAG, "init");
89 }
Keun young Park13a7a822019-04-04 15:53:08 -070090 IntentFilter filter = new IntentFilter();
91 filter.addAction(Intent.ACTION_USER_SWITCHED);
Ying Zhengd3cb98e2018-05-11 11:42:48 -070092
Keun young Park13a7a822019-04-04 15:53:08 -070093 mContext.registerReceiver(this, filter);
Ying Zhengd3cb98e2018-05-11 11:42:48 -070094 }
95
96 @Override
97 public void release() {
98 if (Log.isLoggable(TAG, Log.DEBUG)) {
99 Log.d(TAG, "release");
100 }
Keun young Park13a7a822019-04-04 15:53:08 -0700101 mContext.unregisterReceiver(this);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700102 }
103
104 @Override
105 public void dump(PrintWriter writer) {
106 writer.println(TAG);
107 writer.println("Context: " + mContext);
Keun-young Parkd462a912019-02-11 08:53:42 -0800108 boolean user0Unlocked;
Keun young Parkfb656372019-03-12 18:37:55 -0700109 ArrayList<Integer> lastUnlockedUsers;
Keun-young Parkd462a912019-02-11 08:53:42 -0800110 synchronized (mLock) {
111 user0Unlocked = mUser0Unlocked;
Keun young Parkfb656372019-03-12 18:37:55 -0700112 lastUnlockedUsers = new ArrayList<>(mLastUnlockedUsers);
113
Keun-young Parkd462a912019-02-11 08:53:42 -0800114 }
115 writer.println("User0Unlocked: " + user0Unlocked);
Keun young Parkfb656372019-03-12 18:37:55 -0700116 writer.println("LastUnlockedUsers:" + lastUnlockedUsers);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700117 }
118
Keun young Park13a7a822019-04-04 15:53:08 -0700119 private void updateDefaultUserRestriction() {
120 // We want to set restrictions on system and guest users only once. These are persisted
121 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
122 if (Settings.Global.getInt(mContext.getContentResolver(),
123 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) {
124 setSystemUserRestrictions();
125 mCarUserManagerHelper.initDefaultGuestRestrictions();
126 Settings.Global.putInt(mContext.getContentResolver(),
127 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
128 }
129 }
130
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700131 @Override
132 public void onReceive(Context context, Intent intent) {
133 if (Log.isLoggable(TAG, Log.DEBUG)) {
134 Log.d(TAG, "onReceive " + intent);
135 }
136
Keun young Park13a7a822019-04-04 15:53:08 -0700137 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
Ying Zhengcf20f442018-06-22 16:54:51 -0700138 // Update last active user if the switched-to user is a persistent, non-system user.
Keun-young Parkd462a912019-02-11 08:53:42 -0800139 final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Ying Zhengcf20f442018-06-22 16:54:51 -0700140 if (currentUser > UserHandle.USER_SYSTEM
141 && mCarUserManagerHelper.isPersistentUser(currentUser)) {
Ying Zhengbb1ba2d2018-11-08 10:46:16 -0800142 mCarUserManagerHelper.setLastActiveUser(currentUser);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700143 }
144 }
145 }
Ying Zheng1ab32b62018-06-26 12:47:26 -0700146
Pavel Maltsev17e81832019-04-04 14:38:41 -0700147 /** Add callback to listen to user activity events. */
148 public void addUserCallback(UserCallback callback) {
149 mUserCallbacks.add(callback);
150 }
151
Keun-young Parkd462a912019-02-11 08:53:42 -0800152 /**
153 * Set user lock / unlocking status. This is coming from system server through ICar binder call.
154 * @param userHandle Handle of user
155 * @param unlocked unlocked (=true) or locked (=false)
156 */
157 public void setUserLockStatus(int userHandle, boolean unlocked) {
Pavel Maltsev17e81832019-04-04 14:38:41 -0700158 for (UserCallback callback : mUserCallbacks) {
159 callback.onUserLockChanged(userHandle, unlocked);
160 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800161 ArrayList<Runnable> tasks = null;
162 synchronized (mLock) {
Keun young Parkfb656372019-03-12 18:37:55 -0700163 if (userHandle != UserHandle.USER_SYSTEM && unlocked
164 && mCarUserManagerHelper.isPersistentUser(userHandle)) {
165 Integer user = userHandle;
166 mLastUnlockedUsers.remove(user);
167 mLastUnlockedUsers.add(0, user);
168 return;
169 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800170 // Assumes that car service need to do it only once during boot-up
171 if (unlocked && !mUser0Unlocked) {
Keun young Park13a7a822019-04-04 15:53:08 -0700172 updateDefaultUserRestriction();
Keun-young Parkd462a912019-02-11 08:53:42 -0800173 tasks = new ArrayList<>(mUser0UnlockTasks);
174 mUser0UnlockTasks.clear();
175 mUser0Unlocked = unlocked;
176 }
177 }
178 if (tasks != null && tasks.size() > 0) {
179 Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size());
180 for (Runnable r : tasks) {
181 r.run();
182 }
183 }
184 }
185
186 /**
Keun young Parkfb656372019-03-12 18:37:55 -0700187 * Start all background users that were active in system.
188 * @return list of background users started successfully.
189 */
190 public ArrayList<Integer> startAllBackgroundUsers() {
191 ArrayList<Integer> users;
192 synchronized (mLock) {
193 users = new ArrayList<>(mLastUnlockedUsers);
194 }
195 ArrayList<Integer> startedUsers = new ArrayList<>();
196 for (Integer user : users) {
197 if (user == mCarUserManagerHelper.getCurrentForegroundUserId()) {
198 continue;
199 }
200 try {
201 if (mAm.startUserInBackground(user)) {
202 if (mAm.unlockUser(user, null, null, null)) {
203 startedUsers.add(user);
204 }
205 }
206 } catch (RemoteException e) {
207 // ignore
208 }
209 }
210 return startedUsers;
211 }
212
213 /**
214 * Stop all background users that were active in system.
215 * @return true if stopping succeeds.
216 */
217 public boolean stopBackgroundUser(int userId) {
218 if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
219 Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId);
220 return false;
221 }
222 try {
223 int r = mAm.stopUser(userId, true, null);
224 if (r != ActivityManager.USER_OP_SUCCESS) {
225 Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
226 return false;
227 }
228 } catch (RemoteException e) {
229 // ignore
230 }
231 return true;
232 }
233
234 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700235 * Called when new foreground user started to boot.
236 *
237 * @param userHandle user handle of new user
238 */
239 public void onSwitchUser(int userHandle) {
240 for (UserCallback callback : mUserCallbacks) {
241 callback.onSwitchUser(userHandle);
242 }
243 }
244
245 /**
Keun-young Parkd462a912019-02-11 08:53:42 -0800246 * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is
247 * run inside this call.
248 * @param r Runnable to run.
249 */
250 public void runOnUser0Unlock(Runnable r) {
251 boolean runNow = false;
252 synchronized (mLock) {
253 if (mUser0Unlocked) {
254 runNow = true;
255 } else {
256 mUser0UnlockTasks.add(r);
257 }
258 }
259 if (runNow) {
260 r.run();
261 }
262 }
263
Ying Zheng1ab32b62018-06-26 12:47:26 -0700264 private void setSystemUserRestrictions() {
265 // Disable adding accounts for system user.
266 mCarUserManagerHelper.setUserRestriction(mCarUserManagerHelper.getSystemUserInfo(),
267 UserManager.DISALLOW_MODIFY_ACCOUNTS, /* enable= */ true);
268
269 // Disable Location service for system user.
270 LocationManager locationManager =
271 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
272 locationManager.setLocationEnabledForUser(
273 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
274 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700275}