blob: e87b4e63c5b030c7583c2251e99ef358600a6ca5 [file] [log] [blame]
Benjamin Franza83859f2017-07-03 16:34:14 +01001/*
2 * Copyright 2017, 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.server.am;
18
19import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
20import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
21import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
Wale Ogunwale0568aed2017-09-08 13:29:37 -070022import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Benjamin Franza83859f2017-07-03 16:34:14 +010023import static android.content.Context.DEVICE_POLICY_SERVICE;
24import static android.content.Context.STATUS_BAR_SERVICE;
25import static android.os.UserHandle.USER_ALL;
Amith Yamasani7cbbf2222017-08-30 14:22:37 -070026import static android.os.UserHandle.USER_CURRENT;
Benjamin Franza83859f2017-07-03 16:34:14 +010027import static android.view.Display.DEFAULT_DISPLAY;
Charles He520b2832017-09-02 15:27:16 +010028
Benjamin Franza83859f2017-07-03 16:34:14 +010029import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
30import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
31import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
32import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
33import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
34import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
35import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
36import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
37import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
38
39import android.annotation.NonNull;
40import android.annotation.Nullable;
41import android.app.Activity;
42import android.app.ActivityManager;
Charles Hee078db72017-10-19 18:03:20 +010043import android.app.StatusBarManager;
44import android.app.admin.DevicePolicyManager;
Benjamin Franza83859f2017-07-03 16:34:14 +010045import android.app.admin.IDevicePolicyManager;
Charles Hee078db72017-10-19 18:03:20 +010046import android.content.ComponentName;
Benjamin Franza83859f2017-07-03 16:34:14 +010047import android.content.Context;
48import android.os.Binder;
49import android.os.Debug;
50import android.os.Handler;
51import android.os.IBinder;
52import android.os.RemoteException;
53import android.os.ServiceManager;
54import android.provider.Settings;
Charles Hee078db72017-10-19 18:03:20 +010055import android.util.Pair;
Benjamin Franza83859f2017-07-03 16:34:14 +010056import android.util.Slog;
Charles He520b2832017-09-02 15:27:16 +010057import android.util.SparseArray;
Benjamin Franza83859f2017-07-03 16:34:14 +010058
59import com.android.internal.annotations.VisibleForTesting;
60import com.android.internal.statusbar.IStatusBarService;
61import com.android.internal.widget.LockPatternUtils;
62import com.android.server.LocalServices;
63import com.android.server.statusbar.StatusBarManagerInternal;
64import com.android.server.wm.WindowManagerService;
65
66import java.io.PrintWriter;
67import java.util.ArrayList;
Charles He520b2832017-09-02 15:27:16 +010068import java.util.Arrays;
Benjamin Franza83859f2017-07-03 16:34:14 +010069
70/**
71 * Helper class that deals with all things related to task locking. This includes the screen pinning
72 * mode that can be launched via System UI as well as the fully locked mode that can be achieved
73 * on fully managed devices.
74 *
75 * Note: All methods in this class should only be called with the ActivityManagerService lock held.
76 *
77 * @see Activity#startLockTask()
78 * @see Activity#stopLockTask()
79 */
80public class LockTaskController {
81 private static final String TAG = TAG_WITH_CLASS_NAME ? "LockTaskController" : TAG_AM;
82 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
83
84 @VisibleForTesting
Charles Hee078db72017-10-19 18:03:20 +010085 static final int STATUS_BAR_MASK_LOCKED = StatusBarManager.DISABLE_MASK
86 & (~StatusBarManager.DISABLE_EXPAND)
87 & (~StatusBarManager.DISABLE_NOTIFICATION_TICKER)
88 & (~StatusBarManager.DISABLE_SYSTEM_INFO)
89 & (~StatusBarManager.DISABLE_BACK);
Benjamin Franza83859f2017-07-03 16:34:14 +010090 @VisibleForTesting
Charles Hee078db72017-10-19 18:03:20 +010091 static final int STATUS_BAR_MASK_PINNED = StatusBarManager.DISABLE_MASK
92 & (~StatusBarManager.DISABLE_BACK)
93 & (~StatusBarManager.DISABLE_HOME)
94 & (~StatusBarManager.DISABLE_RECENT);
95
96 private static final SparseArray<Pair<Integer, Integer>> STATUS_BAR_FLAG_MAP_LOCKED;
97 static {
98 STATUS_BAR_FLAG_MAP_LOCKED = new SparseArray<>();
99
100 STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO,
101 new Pair<>(StatusBarManager.DISABLE_CLOCK, StatusBarManager.DISABLE2_SYSTEM_ICONS));
102
103 STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS,
104 new Pair<>(StatusBarManager.DISABLE_NOTIFICATION_ICONS
105 | StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
106 StatusBarManager.DISABLE2_NOTIFICATION_SHADE));
107
108 STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_HOME,
109 new Pair<>(StatusBarManager.DISABLE_HOME, StatusBarManager.DISABLE2_NONE));
110
111 STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS,
112 new Pair<>(StatusBarManager.DISABLE_RECENT, StatusBarManager.DISABLE2_NONE));
113
114 STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
115 new Pair<>(StatusBarManager.DISABLE_NONE,
116 StatusBarManager.DISABLE2_GLOBAL_ACTIONS));
117 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100118
119 /** Tag used for disabling of keyguard */
120 private static final String LOCK_TASK_TAG = "Lock-to-App";
121
122 private final IBinder mToken = new Binder();
123 private final ActivityStackSupervisor mSupervisor;
124 private final Context mContext;
125
126 // The following system services cannot be final, because they do not exist when this class
127 // is instantiated during device boot
128 @VisibleForTesting
129 IStatusBarService mStatusBarService;
130 @VisibleForTesting
131 IDevicePolicyManager mDevicePolicyManager;
132 @VisibleForTesting
133 WindowManagerService mWindowManager;
134 @VisibleForTesting
135 LockPatternUtils mLockPatternUtils;
136
137 /**
138 * Helper that is responsible for showing the right toast when a disallowed activity operation
139 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
140 * fully locked mode we only show that unlocking is blocked.
141 */
142 @VisibleForTesting
143 LockTaskNotify mLockTaskNotify;
144
145 /**
Charles Heff9b4dff2017-09-22 10:18:37 +0100146 * The chain of tasks in LockTask mode, in the order of when they first entered LockTask mode.
147 *
148 * The first task in the list, which started the current LockTask session, is called the root
149 * task. It coincides with the Home task in a typical multi-app kiosk deployment. When there are
150 * more than one locked tasks, the root task can't be finished. Nor can it be moved to the back
151 * of the stack by {@link ActivityStack#moveTaskToBackLocked(int)};
152 *
153 * Calling {@link Activity#stopLockTask()} on the root task will finish all tasks but itself in
154 * this list, and the device will exit LockTask mode.
155 *
156 * The list is empty if LockTask is inactive.
Benjamin Franza83859f2017-07-03 16:34:14 +0100157 */
158 private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
159
160 /**
Charles He520b2832017-09-02 15:27:16 +0100161 * Packages that are allowed to be launched into the lock task mode for each user.
162 */
163 private final SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
164
165 /**
Charles Hee078db72017-10-19 18:03:20 +0100166 * Features that are allowed by DPC to show during LockTask mode.
167 */
168 private final SparseArray<Integer> mLockTaskFeatures = new SparseArray<>();
169
170 /**
Benjamin Franza83859f2017-07-03 16:34:14 +0100171 * Store the current lock task mode. Possible values:
172 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
173 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
174 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100175 private int mLockTaskModeState = LOCK_TASK_MODE_NONE;
Benjamin Franza83859f2017-07-03 16:34:14 +0100176
177 /**
178 * This is ActivityStackSupervisor's Handler.
179 */
180 private final Handler mHandler;
181
182 LockTaskController(Context context, ActivityStackSupervisor supervisor,
183 Handler handler) {
184 mContext = context;
185 mSupervisor = supervisor;
186 mHandler = handler;
187 }
188
189 /**
190 * Set the window manager instance used in this class. This is necessary, because the window
191 * manager does not exist during instantiation of this class.
192 */
193 void setWindowManager(WindowManagerService windowManager) {
194 mWindowManager = windowManager;
195 }
196
197 /**
198 * @return the current lock task state. This can be any of
199 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
200 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
201 */
202 int getLockTaskModeState() {
203 return mLockTaskModeState;
204 }
205
206 /**
Charles He520b2832017-09-02 15:27:16 +0100207 * @return whether the given task is locked at the moment. Locked tasks cannot be moved to the
208 * back of the stack.
Benjamin Franza83859f2017-07-03 16:34:14 +0100209 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100210 @VisibleForTesting
211 boolean isTaskLocked(TaskRecord task) {
212 return mLockTaskModeTasks.contains(task);
213 }
214
215 /**
216 * @return {@code true} whether this task first started the current LockTask session.
217 */
218 private boolean isRootTask(TaskRecord task) {
219 return mLockTaskModeTasks.indexOf(task) == 0;
220 }
221
222 /**
223 * @return whether the given activity is blocked from finishing, because it is the only activity
224 * of the last locked task and finishing it would mean that lock task mode is ended illegally.
225 */
226 boolean activityBlockedFromFinish(ActivityRecord activity) {
227 final TaskRecord task = activity.getTask();
228 if (activity == task.getRootActivity()
229 && activity == task.getTopActivity()
230 && task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
231 && isRootTask(task)) {
232 Slog.i(TAG, "Not finishing task in lock task mode");
Benjamin Franza83859f2017-07-03 16:34:14 +0100233 showLockTaskToast();
234 return true;
235 }
236 return false;
237 }
238
239 /**
Charles Heff9b4dff2017-09-22 10:18:37 +0100240 * @return whether the given task can be moved to the back of the stack with
241 * {@link ActivityStack#moveTaskToBackLocked(int)}
242 * @see #mLockTaskModeTasks
Benjamin Franza83859f2017-07-03 16:34:14 +0100243 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100244 boolean canMoveTaskToBack(TaskRecord task) {
245 if (isRootTask(task)) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100246 showLockTaskToast();
Charles Heff9b4dff2017-09-22 10:18:37 +0100247 return false;
Benjamin Franza83859f2017-07-03 16:34:14 +0100248 }
Charles Heff9b4dff2017-09-22 10:18:37 +0100249 return true;
Benjamin Franza83859f2017-07-03 16:34:14 +0100250 }
251
252 /**
253 * @return whether the requested task is allowed to be launched.
254 */
255 boolean isLockTaskModeViolation(TaskRecord task) {
256 return isLockTaskModeViolation(task, false);
257 }
258
259 /**
260 * @param isNewClearTask whether the task would be cleared as part of the operation.
261 * @return whether the requested task is allowed to be launched.
262 */
263 boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
264 if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
265 showLockTaskToast();
266 return true;
267 }
268 return false;
269 }
270
271 private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
272 // TODO: Double check what's going on here. If the task is already in lock task mode, it's
273 // likely whitelisted, so will return false below.
Charles Heff9b4dff2017-09-22 10:18:37 +0100274 if (isTaskLocked(task) && !isNewClearTask) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100275 // If the task is already at the top and won't be cleared, then allow the operation
276 return false;
277 }
278 final int lockTaskAuth = task.mLockTaskAuth;
279 switch (lockTaskAuth) {
280 case LOCK_TASK_AUTH_DONT_LOCK:
281 return !mLockTaskModeTasks.isEmpty();
282 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
283 case LOCK_TASK_AUTH_LAUNCHABLE:
284 case LOCK_TASK_AUTH_WHITELISTED:
285 return false;
286 case LOCK_TASK_AUTH_PINNABLE:
287 // Pinnable tasks can't be launched on top of locktask tasks.
288 return !mLockTaskModeTasks.isEmpty();
289 default:
290 Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth);
291 return true;
292 }
293 }
294
295 /**
296 * Stop the current lock task mode.
297 *
Charles Heff9b4dff2017-09-22 10:18:37 +0100298 * This is called by {@link ActivityManagerService} and performs various checks before actually
299 * finishing the locked task.
300 *
301 * @param task the task that requested the end of lock task mode ({@code null} for quitting app
302 * pinning mode)
303 * @param isSystemCaller indicates whether this request comes from the system via
304 * {@link ActivityManagerService#stopSystemLockTaskMode()}. If
305 * {@code true}, it means the user intends to stop pinned mode through UI;
306 * otherwise, it's called by an app and we need to stop locked or pinned
307 * mode, subject to checks.
Benjamin Franza83859f2017-07-03 16:34:14 +0100308 * @param callingUid the caller that requested the end of lock task mode.
Charles Heff9b4dff2017-09-22 10:18:37 +0100309 * @throws IllegalArgumentException if the calling task is invalid (e.g., {@code null} or not in
310 * foreground)
Benjamin Franza83859f2017-07-03 16:34:14 +0100311 * @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
312 * they differ from the one that launched lock task mode.
313 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100314 void stopLockTaskMode(@Nullable TaskRecord task, boolean isSystemCaller, int callingUid) {
315 if (mLockTaskModeState == LOCK_TASK_MODE_NONE) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100316 return;
317 }
318
Charles Heff9b4dff2017-09-22 10:18:37 +0100319 if (isSystemCaller) {
320 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
321 clearLockedTasks("stopAppPinning");
322 } else {
323 Slog.e(TAG_LOCKTASK, "Attempted to stop LockTask with isSystemCaller=true");
324 showLockTaskToast();
325 }
326
327 } else {
328 // Ensure calling activity is not null
329 if (task == null) {
330 throw new IllegalArgumentException("can't stop LockTask for null task");
331 }
332
333 // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
334 // It is possible lockTaskMode was started by the system process because
335 // android:lockTaskMode is set to a locking value in the application manifest
336 // instead of the app calling startLockTaskMode. In this case
337 // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
338 // {@link TaskRecord.effectiveUid} instead. Also caller with
339 // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
340 if (callingUid != task.mLockTaskUid
341 && (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) {
342 throw new SecurityException("Invalid uid, expected " + task.mLockTaskUid
343 + " callingUid=" + callingUid + " effectiveUid=" + task.effectiveUid);
344 }
345
346 // We don't care if it's pinned or locked mode; this will stop it anyways.
347 clearLockedTask(task);
348 }
349 }
350
351 /**
352 * Clear all locked tasks and request the end of LockTask mode.
353 *
354 * This method is called by {@link UserController} when starting a new foreground user, and,
355 * unlike {@link #stopLockTaskMode(TaskRecord, boolean, int)}, it doesn't perform the checks.
356 */
357 void clearLockedTasks(String reason) {
358 if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
359 if (!mLockTaskModeTasks.isEmpty()) {
360 clearLockedTask(mLockTaskModeTasks.get(0));
361 }
362 }
363
364 /**
365 * Clear one locked task from LockTask mode.
366 *
367 * If the requested task is the root task (see {@link #mLockTaskModeTasks}), then all locked
368 * tasks are cleared. Otherwise, only the requested task is cleared. LockTask mode is stopped
369 * when the last locked task is cleared.
370 *
371 * @param task the task to be cleared from LockTask mode.
372 */
373 void clearLockedTask(final TaskRecord task) {
374 if (task == null || mLockTaskModeTasks.isEmpty()) return;
375
376 if (task == mLockTaskModeTasks.get(0)) {
377 // We're removing the root task while there are other locked tasks. Therefore we should
378 // clear all locked tasks in reverse order.
379 for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx > 0; --taskNdx) {
380 clearLockedTask(mLockTaskModeTasks.get(taskNdx));
381 }
382 }
383
384 removeLockedTask(task);
385 if (mLockTaskModeTasks.isEmpty()) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100386 return;
387 }
Charles Heff9b4dff2017-09-22 10:18:37 +0100388 task.performClearTaskLocked();
389 mSupervisor.resumeFocusedStackTopActivityLocked();
Benjamin Franza83859f2017-07-03 16:34:14 +0100390 }
391
392 /**
393 * Remove the given task from the locked task list. If this was the last task in the list,
394 * lock task mode is stopped.
395 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100396 private void removeLockedTask(final TaskRecord task) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100397 if (!mLockTaskModeTasks.remove(task)) {
398 return;
399 }
Charles Heff9b4dff2017-09-22 10:18:37 +0100400 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: removed " + task);
Benjamin Franza83859f2017-07-03 16:34:14 +0100401 if (mLockTaskModeTasks.isEmpty()) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100402 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
403 " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
404 mHandler.post(() -> performStopLockTask(task.userId));
405 }
406 }
407
Benjamin Franza83859f2017-07-03 16:34:14 +0100408 // This method should only be called on the handler thread
409 private void performStopLockTask(int userId) {
410 // When lock task ends, we enable the status bars.
411 try {
Charles Hee078db72017-10-19 18:03:20 +0100412 setStatusBarState(LOCK_TASK_MODE_NONE, userId);
413 setKeyguardState(LOCK_TASK_MODE_NONE, userId);
414 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
415 lockKeyguardIfNeeded();
Benjamin Franza83859f2017-07-03 16:34:14 +0100416 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100417 if (getDevicePolicyManager() != null) {
418 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
419 }
Charles Hebfe82d12017-10-20 11:59:44 +0100420 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
421 getLockTaskNotify().showPinningExitToast();
422 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100423 } catch (RemoteException ex) {
424 throw new RuntimeException(ex);
425 } finally {
426 mLockTaskModeState = LOCK_TASK_MODE_NONE;
427 }
428 }
429
430 /**
Charles Hebfe82d12017-10-20 11:59:44 +0100431 * Show the lock task violation toast. Currently we only show toast for screen pinning mode, and
432 * no-op if the device is in locked mode.
Benjamin Franza83859f2017-07-03 16:34:14 +0100433 */
434 void showLockTaskToast() {
Charles Hebfe82d12017-10-20 11:59:44 +0100435 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
436 mHandler.post(() -> getLockTaskNotify().showEscapeToast());
437 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100438 }
439
440 // Starting lock task
441
442 /**
443 * Method to start lock task mode on a given task.
444 *
445 * @param task the task that should be locked.
Charles Heff9b4dff2017-09-22 10:18:37 +0100446 * @param isSystemCaller indicates whether this request was initiated by the system via
447 * {@link ActivityManagerService#startSystemLockTaskMode(int)}. If
448 * {@code true}, this intends to start pinned mode; otherwise, we look
449 * at the calling task's mLockTaskAuth to decide which mode to start.
Benjamin Franza83859f2017-07-03 16:34:14 +0100450 * @param callingUid the caller that requested the launch of lock task mode.
451 */
Charles Heff9b4dff2017-09-22 10:18:37 +0100452 void startLockTaskMode(@NonNull TaskRecord task, boolean isSystemCaller, int callingUid) {
453 if (!isSystemCaller) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100454 task.mLockTaskUid = callingUid;
455 if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
456 // startLockTask() called by app, but app is not part of lock task whitelist. Show
Charles Heff9b4dff2017-09-22 10:18:37 +0100457 // app pinning request. We will come back here with isSystemCaller true.
Benjamin Franza83859f2017-07-03 16:34:14 +0100458 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
459 StatusBarManagerInternal statusBarManager = LocalServices.getService(
460 StatusBarManagerInternal.class);
461 if (statusBarManager != null) {
462 statusBarManager.showScreenPinningRequest(task.taskId);
463 }
464 return;
465 }
466 }
467
468 // System can only initiate screen pinning, not full lock task mode
Charles Heff9b4dff2017-09-22 10:18:37 +0100469 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
470 isSystemCaller ? "Locking pinned" : "Locking fully");
471 setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
Benjamin Franza83859f2017-07-03 16:34:14 +0100472 "startLockTask", true);
473 }
474
475 /**
476 * Start lock task mode on the given task.
477 * @param lockTaskModeState whether fully locked or pinned mode.
478 * @param andResume whether the task should be brought to foreground as part of the operation.
479 */
480 private void setLockTaskMode(@NonNull TaskRecord task, int lockTaskModeState,
481 String reason, boolean andResume) {
482 // Should have already been checked, but do it again.
483 if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
484 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
485 "setLockTaskMode: Can't lock due to auth");
486 return;
487 }
488 if (isLockTaskModeViolation(task)) {
489 Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task.");
490 return;
491 }
492
493 if (mLockTaskModeTasks.isEmpty()) {
494 // Start lock task on the handler thread
495 mHandler.post(() -> performStartLockTask(
496 task.intent.getComponent().getPackageName(),
497 task.userId,
498 lockTaskModeState));
499 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100500 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
501 " Callers=" + Debug.getCallers(4));
Charles Heff9b4dff2017-09-22 10:18:37 +0100502
503 if (!mLockTaskModeTasks.contains(task)) {
504 mLockTaskModeTasks.add(task);
505 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100506
507 if (task.mLockTaskUid == -1) {
508 task.mLockTaskUid = task.effectiveUid;
509 }
510
511 if (andResume) {
Wale Ogunwale66e16852017-10-19 13:35:52 -0700512 mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
Benjamin Franza83859f2017-07-03 16:34:14 +0100513 lockTaskModeState != LOCK_TASK_MODE_NONE);
514 mSupervisor.resumeFocusedStackTopActivityLocked();
515 mWindowManager.executeAppTransition();
516 } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700517 mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700518 DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */);
Benjamin Franza83859f2017-07-03 16:34:14 +0100519 }
520 }
521
522 // This method should only be called on the handler thread
523 private void performStartLockTask(String packageName, int userId, int lockTaskModeState) {
524 // When lock task starts, we disable the status bars.
525 try {
Charles Hebfe82d12017-10-20 11:59:44 +0100526 if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
527 getLockTaskNotify().showPinningStartToast();
528 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100529 mLockTaskModeState = lockTaskModeState;
Charles Hee078db72017-10-19 18:03:20 +0100530 setStatusBarState(lockTaskModeState, userId);
531 setKeyguardState(lockTaskModeState, userId);
Benjamin Franza83859f2017-07-03 16:34:14 +0100532 if (getDevicePolicyManager() != null) {
533 getDevicePolicyManager().notifyLockTaskModeChanged(true, packageName, userId);
534 }
535 } catch (RemoteException ex) {
536 throw new RuntimeException(ex);
537 }
538 }
539
540 /**
Charles He520b2832017-09-02 15:27:16 +0100541 * Update packages that are allowed to be launched in lock task mode.
542 * @param userId Which user this whitelist is associated with
543 * @param packages The whitelist of packages allowed in lock task mode
544 * @see #mLockTaskPackages
Benjamin Franza83859f2017-07-03 16:34:14 +0100545 */
Charles He520b2832017-09-02 15:27:16 +0100546 void updateLockTaskPackages(int userId, String[] packages) {
547 mLockTaskPackages.put(userId, packages);
548
549 boolean taskChanged = false;
Benjamin Franza83859f2017-07-03 16:34:14 +0100550 for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
551 final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
Charles He520b2832017-09-02 15:27:16 +0100552 final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
553 || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
Benjamin Franza83859f2017-07-03 16:34:14 +0100554 lockedTask.setLockTaskAuth();
Charles He520b2832017-09-02 15:27:16 +0100555 final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
556 || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
557
558 if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
559 || lockedTask.userId != userId
560 || !wasWhitelisted || isWhitelisted) {
561 continue;
Benjamin Franza83859f2017-07-03 16:34:14 +0100562 }
Charles He520b2832017-09-02 15:27:16 +0100563
564 // Terminate locked tasks that have recently lost whitelist authorization.
565 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
566 lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
567 removeLockedTask(lockedTask);
568 lockedTask.performClearTaskLocked();
569 taskChanged = true;
Benjamin Franza83859f2017-07-03 16:34:14 +0100570 }
571
572 for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700573 mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated();
Benjamin Franza83859f2017-07-03 16:34:14 +0100574 }
Charles He520b2832017-09-02 15:27:16 +0100575
Benjamin Franza83859f2017-07-03 16:34:14 +0100576 final ActivityRecord r = mSupervisor.topRunningActivityLocked();
Charles He520b2832017-09-02 15:27:16 +0100577 final TaskRecord task = (r != null) ? r.getTask() : null;
578 if (mLockTaskModeTasks.isEmpty() && task!= null
Benjamin Franza83859f2017-07-03 16:34:14 +0100579 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
580 // This task must have just been authorized.
581 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
582 "onLockTaskPackagesUpdated: starting new locktask task=" + task);
Charles He520b2832017-09-02 15:27:16 +0100583 setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
584 taskChanged = true;
Benjamin Franza83859f2017-07-03 16:34:14 +0100585 }
Charles He520b2832017-09-02 15:27:16 +0100586
587 if (taskChanged) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100588 mSupervisor.resumeFocusedStackTopActivityLocked();
589 }
590 }
591
Charles He520b2832017-09-02 15:27:16 +0100592 boolean isPackageWhitelisted(int userId, String pkg) {
593 if (pkg == null) {
594 return false;
595 }
596 String[] whitelist;
597 whitelist = mLockTaskPackages.get(userId);
598 if (whitelist == null) {
599 return false;
600 }
601 for (String whitelistedPkg : whitelist) {
602 if (pkg.equals(whitelistedPkg)) {
603 return true;
604 }
605 }
606 return false;
607 }
608
Benjamin Franza83859f2017-07-03 16:34:14 +0100609 /**
Charles Hee078db72017-10-19 18:03:20 +0100610 * Update the UI features that are enabled for LockTask mode.
611 * @param userId Which user these feature flags are associated with
612 * @param flags Bitfield of feature flags
613 * @see DevicePolicyManager#setLockTaskFeatures(ComponentName, int)
614 */
615 void updateLockTaskFeatures(int userId, int flags) {
616 int oldFlags = getLockTaskFeaturesForUser(userId);
617 if (flags == oldFlags) {
618 return;
619 }
620
621 mLockTaskFeatures.put(userId, flags);
Charles Heff9b4dff2017-09-22 10:18:37 +0100622 if (!mLockTaskModeTasks.isEmpty() && userId == mLockTaskModeTasks.get(0).userId) {
Charles Hee078db72017-10-19 18:03:20 +0100623 mHandler.post(() -> {
624 if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
625 setStatusBarState(mLockTaskModeState, userId);
626 setKeyguardState(mLockTaskModeState, userId);
627 }
628 });
629 }
630 }
631
632 /**
633 * Helper method for configuring the status bar disabled state.
634 * Should only be called on the handler thread to avoid race.
635 */
636 private void setStatusBarState(int lockTaskModeState, int userId) {
637 IStatusBarService statusBar = getStatusBarService();
638 if (statusBar == null) {
639 Slog.e(TAG, "Can't find StatusBarService");
640 return;
641 }
642
643 // Default state, when lockTaskModeState == LOCK_TASK_MODE_NONE
644 int flags1 = StatusBarManager.DISABLE_NONE;
645 int flags2 = StatusBarManager.DISABLE2_NONE;
646
647 if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
648 flags1 = STATUS_BAR_MASK_PINNED;
649
650 } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
651 int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
652 Pair<Integer, Integer> statusBarFlags = getStatusBarDisableFlags(lockTaskFeatures);
653 flags1 = statusBarFlags.first;
654 flags2 = statusBarFlags.second;
655 }
656
657 try {
658 statusBar.disable(flags1, mToken, mContext.getPackageName());
659 statusBar.disable2(flags2, mToken, mContext.getPackageName());
660 } catch (RemoteException e) {
661 Slog.e(TAG, "Failed to set status bar flags", e);
662 }
663 }
664
665 /**
666 * Helper method for configuring the keyguard disabled state.
667 * Should only be called on the handler thread to avoid race.
668 */
669 private void setKeyguardState(int lockTaskModeState, int userId) {
670 if (lockTaskModeState == LOCK_TASK_MODE_NONE) {
671 mWindowManager.reenableKeyguard(mToken);
672
673 } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
674 int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
675 if ((DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD & lockTaskFeatures) == 0) {
676 mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
677 } else {
678 mWindowManager.reenableKeyguard(mToken);
679 }
680
681 } else { // lockTaskModeState == LOCK_TASK_MODE_PINNED
682 mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
683 }
684 }
685
686 /**
687 * Helper method for locking the device immediately. This may be necessary when the device
688 * leaves the pinned mode.
689 */
690 private void lockKeyguardIfNeeded() {
691 try {
692 boolean shouldLockKeyguard = Settings.Secure.getIntForUser(
693 mContext.getContentResolver(),
694 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
695 USER_CURRENT) != 0;
696 if (shouldLockKeyguard) {
697 mWindowManager.lockNow(null);
698 mWindowManager.dismissKeyguard(null /* callback */);
699 getLockPatternUtils().requireCredentialEntry(USER_ALL);
700 }
701 } catch (Settings.SettingNotFoundException e) {
702 // No setting, don't lock.
703 }
704 }
705
706 /**
707 * Translates from LockTask feature flags to StatusBarManager disable and disable2 flags.
708 * @param lockTaskFlags Bitfield of flags as per
709 * {@link DevicePolicyManager#setLockTaskFeatures(ComponentName, int)}
710 * @return A {@link Pair} of {@link StatusBarManager#disable(int)} and
711 * {@link StatusBarManager#disable2(int)} flags
712 */
713 @VisibleForTesting
714 Pair<Integer, Integer> getStatusBarDisableFlags(int lockTaskFlags) {
715 // Everything is disabled by default
716 int flags1 = StatusBarManager.DISABLE_MASK;
717 int flags2 = StatusBarManager.DISABLE2_MASK;
718 for (int i = STATUS_BAR_FLAG_MAP_LOCKED.size() - 1; i >= 0; i--) {
719 Pair<Integer, Integer> statusBarFlags = STATUS_BAR_FLAG_MAP_LOCKED.valueAt(i);
720 if ((STATUS_BAR_FLAG_MAP_LOCKED.keyAt(i) & lockTaskFlags) != 0) {
721 flags1 &= ~statusBarFlags.first;
722 flags2 &= ~statusBarFlags.second;
723 }
724 }
725 // Some flags are not used for LockTask purposes, so we mask them
726 flags1 &= STATUS_BAR_MASK_LOCKED;
727 return new Pair<>(flags1, flags2);
728 }
729
730 /**
731 * Gets the cached value of LockTask feature flags for a specific user.
732 */
733 private int getLockTaskFeaturesForUser(int userId) {
734 return mLockTaskFeatures.get(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
735 }
736
Benjamin Franza83859f2017-07-03 16:34:14 +0100737 // Should only be called on the handler thread
738 @Nullable
739 private IStatusBarService getStatusBarService() {
740 if (mStatusBarService == null) {
741 mStatusBarService = IStatusBarService.Stub.asInterface(
742 ServiceManager.checkService(STATUS_BAR_SERVICE));
743 if (mStatusBarService == null) {
744 Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
745 }
746 }
747 return mStatusBarService;
748 }
749
750 // Should only be called on the handler thread
751 @Nullable
752 private IDevicePolicyManager getDevicePolicyManager() {
753 if (mDevicePolicyManager == null) {
754 mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
755 ServiceManager.checkService(DEVICE_POLICY_SERVICE));
756 if (mDevicePolicyManager == null) {
757 Slog.w(TAG, "warning: no DEVICE_POLICY_SERVICE");
758 }
759 }
760 return mDevicePolicyManager;
761 }
762
763 @NonNull
764 private LockPatternUtils getLockPatternUtils() {
765 if (mLockPatternUtils == null) {
766 // We don't preserve the LPU object to save memory
767 return new LockPatternUtils(mContext);
768 }
769 return mLockPatternUtils;
770 }
771
772 // Should only be called on the handler thread
773 @NonNull
774 private LockTaskNotify getLockTaskNotify() {
775 if (mLockTaskNotify == null) {
776 mLockTaskNotify = new LockTaskNotify(mContext);
777 }
778 return mLockTaskNotify;
779 }
780
781 public void dump(PrintWriter pw, String prefix) {
Charles He520b2832017-09-02 15:27:16 +0100782 pw.println(prefix + "LockTaskController");
783 prefix = prefix + " ";
784 pw.println(prefix + "mLockTaskModeState=" + lockTaskModeToString());
785 pw.println(prefix + "mLockTaskModeTasks=");
786 for (int i = 0; i < mLockTaskModeTasks.size(); ++i) {
787 pw.println(prefix + " #" + i + " " + mLockTaskModeTasks.get(i));
788 }
789 pw.println(prefix + "mLockTaskPackages (userId:packages)=");
790 for (int i = 0; i < mLockTaskPackages.size(); ++i) {
791 pw.println(prefix + " u" + mLockTaskPackages.keyAt(i)
792 + ":" + Arrays.toString(mLockTaskPackages.valueAt(i)));
793 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100794 }
795
796 private String lockTaskModeToString() {
797 switch (mLockTaskModeState) {
798 case LOCK_TASK_MODE_LOCKED:
799 return "LOCKED";
800 case LOCK_TASK_MODE_PINNED:
801 return "PINNED";
802 case LOCK_TASK_MODE_NONE:
803 return "NONE";
804 default: return "unknown=" + mLockTaskModeState;
805 }
806 }
807}