blob: f0192edab63268cbf1249d1f626d1e77d0fb522f [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 Parkd462a912019-02-11 08:53:42 -080090 if (mCarUserManagerHelper.isHeadlessSystemUser()) {
91 IntentFilter filter = new IntentFilter();
92 filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
93 filter.addAction(Intent.ACTION_USER_SWITCHED);
Ying Zhengd3cb98e2018-05-11 11:42:48 -070094
Keun-young Parkd462a912019-02-11 08:53:42 -080095 mContext.registerReceiver(this, filter);
96 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -070097 }
98
99 @Override
100 public void release() {
101 if (Log.isLoggable(TAG, Log.DEBUG)) {
102 Log.d(TAG, "release");
103 }
Keun-young Parkf80ca6c2019-02-13 14:56:44 -0800104 if (mCarUserManagerHelper.isHeadlessSystemUser()) {
105 mContext.unregisterReceiver(this);
106 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700107 }
108
109 @Override
110 public void dump(PrintWriter writer) {
111 writer.println(TAG);
112 writer.println("Context: " + mContext);
Keun-young Parkd462a912019-02-11 08:53:42 -0800113 boolean user0Unlocked;
Keun young Parkfb656372019-03-12 18:37:55 -0700114 ArrayList<Integer> lastUnlockedUsers;
Keun-young Parkd462a912019-02-11 08:53:42 -0800115 synchronized (mLock) {
116 user0Unlocked = mUser0Unlocked;
Keun young Parkfb656372019-03-12 18:37:55 -0700117 lastUnlockedUsers = new ArrayList<>(mLastUnlockedUsers);
118
Keun-young Parkd462a912019-02-11 08:53:42 -0800119 }
120 writer.println("User0Unlocked: " + user0Unlocked);
Keun young Parkfb656372019-03-12 18:37:55 -0700121 writer.println("LastUnlockedUsers:" + lastUnlockedUsers);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700122 }
123
124 @Override
125 public void onReceive(Context context, Intent intent) {
126 if (Log.isLoggable(TAG, Log.DEBUG)) {
127 Log.d(TAG, "onReceive " + intent);
128 }
129
Ying Zhengcf20f442018-06-22 16:54:51 -0700130 if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(intent.getAction())) {
jovanak24470652018-09-11 17:51:57 -0700131 // We want to set restrictions on system and guest users only once. These are persisted
132 // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
133 if (Settings.Global.getInt(mContext.getContentResolver(),
134 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) {
Ying Zheng1ab32b62018-06-26 12:47:26 -0700135 setSystemUserRestrictions();
jovanak811265f2018-06-28 11:22:14 -0700136 mCarUserManagerHelper.initDefaultGuestRestrictions();
jovanak24470652018-09-11 17:51:57 -0700137 Settings.Global.putInt(mContext.getContentResolver(),
138 CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
Ying Zhengf4339b82018-06-19 16:01:05 -0700139 }
jovanak24470652018-09-11 17:51:57 -0700140
Ying Zhengcf20f442018-06-22 16:54:51 -0700141 } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
142 // Update last active user if the switched-to user is a persistent, non-system user.
Keun-young Parkd462a912019-02-11 08:53:42 -0800143 final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Ying Zhengcf20f442018-06-22 16:54:51 -0700144 if (currentUser > UserHandle.USER_SYSTEM
145 && mCarUserManagerHelper.isPersistentUser(currentUser)) {
Ying Zhengbb1ba2d2018-11-08 10:46:16 -0800146 mCarUserManagerHelper.setLastActiveUser(currentUser);
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700147 }
148 }
149 }
Ying Zheng1ab32b62018-06-26 12:47:26 -0700150
Pavel Maltsev17e81832019-04-04 14:38:41 -0700151 /** Add callback to listen to user activity events. */
152 public void addUserCallback(UserCallback callback) {
153 mUserCallbacks.add(callback);
154 }
155
Keun-young Parkd462a912019-02-11 08:53:42 -0800156 /**
157 * Set user lock / unlocking status. This is coming from system server through ICar binder call.
158 * @param userHandle Handle of user
159 * @param unlocked unlocked (=true) or locked (=false)
160 */
161 public void setUserLockStatus(int userHandle, boolean unlocked) {
Pavel Maltsev17e81832019-04-04 14:38:41 -0700162 for (UserCallback callback : mUserCallbacks) {
163 callback.onUserLockChanged(userHandle, unlocked);
164 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800165 ArrayList<Runnable> tasks = null;
166 synchronized (mLock) {
Keun young Parkfb656372019-03-12 18:37:55 -0700167 if (userHandle != UserHandle.USER_SYSTEM && unlocked
168 && mCarUserManagerHelper.isPersistentUser(userHandle)) {
169 Integer user = userHandle;
170 mLastUnlockedUsers.remove(user);
171 mLastUnlockedUsers.add(0, user);
172 return;
173 }
Keun-young Parkd462a912019-02-11 08:53:42 -0800174 // Assumes that car service need to do it only once during boot-up
175 if (unlocked && !mUser0Unlocked) {
176 tasks = new ArrayList<>(mUser0UnlockTasks);
177 mUser0UnlockTasks.clear();
178 mUser0Unlocked = unlocked;
179 }
180 }
181 if (tasks != null && tasks.size() > 0) {
182 Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size());
183 for (Runnable r : tasks) {
184 r.run();
185 }
186 }
187 }
188
189 /**
Keun young Parkfb656372019-03-12 18:37:55 -0700190 * Start all background users that were active in system.
191 * @return list of background users started successfully.
192 */
193 public ArrayList<Integer> startAllBackgroundUsers() {
194 ArrayList<Integer> users;
195 synchronized (mLock) {
196 users = new ArrayList<>(mLastUnlockedUsers);
197 }
198 ArrayList<Integer> startedUsers = new ArrayList<>();
199 for (Integer user : users) {
200 if (user == mCarUserManagerHelper.getCurrentForegroundUserId()) {
201 continue;
202 }
203 try {
204 if (mAm.startUserInBackground(user)) {
205 if (mAm.unlockUser(user, null, null, null)) {
206 startedUsers.add(user);
207 }
208 }
209 } catch (RemoteException e) {
210 // ignore
211 }
212 }
213 return startedUsers;
214 }
215
216 /**
217 * Stop all background users that were active in system.
218 * @return true if stopping succeeds.
219 */
220 public boolean stopBackgroundUser(int userId) {
221 if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
222 Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId);
223 return false;
224 }
225 try {
226 int r = mAm.stopUser(userId, true, null);
227 if (r != ActivityManager.USER_OP_SUCCESS) {
228 Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
229 return false;
230 }
231 } catch (RemoteException e) {
232 // ignore
233 }
234 return true;
235 }
236
237 /**
Pavel Maltsev17e81832019-04-04 14:38:41 -0700238 * Called when new foreground user started to boot.
239 *
240 * @param userHandle user handle of new user
241 */
242 public void onSwitchUser(int userHandle) {
243 for (UserCallback callback : mUserCallbacks) {
244 callback.onSwitchUser(userHandle);
245 }
246 }
247
248 /**
Keun-young Parkd462a912019-02-11 08:53:42 -0800249 * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is
250 * run inside this call.
251 * @param r Runnable to run.
252 */
253 public void runOnUser0Unlock(Runnable r) {
254 boolean runNow = false;
255 synchronized (mLock) {
256 if (mUser0Unlocked) {
257 runNow = true;
258 } else {
259 mUser0UnlockTasks.add(r);
260 }
261 }
262 if (runNow) {
263 r.run();
264 }
265 }
266
Ying Zheng1ab32b62018-06-26 12:47:26 -0700267 private void setSystemUserRestrictions() {
268 // Disable adding accounts for system user.
269 mCarUserManagerHelper.setUserRestriction(mCarUserManagerHelper.getSystemUserInfo(),
270 UserManager.DISALLOW_MODIFY_ACCOUNTS, /* enable= */ true);
271
272 // Disable Location service for system user.
273 LocationManager locationManager =
274 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
275 locationManager.setLocationEnabledForUser(
276 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
277 }
Ying Zhengd3cb98e2018-05-11 11:42:48 -0700278}