blob: c03ac86a2bf968b1bfce7bd6644557ba2a2934a2 [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;
22import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
23import static android.app.StatusBarManager.DISABLE_BACK;
24import static android.app.StatusBarManager.DISABLE_HOME;
25import static android.app.StatusBarManager.DISABLE_MASK;
26import static android.app.StatusBarManager.DISABLE_NONE;
27import static android.app.StatusBarManager.DISABLE_RECENT;
28import static android.content.Context.DEVICE_POLICY_SERVICE;
29import static android.content.Context.STATUS_BAR_SERVICE;
30import static android.os.UserHandle.USER_ALL;
31import static android.provider.Settings.Secure.LOCK_TO_APP_EXIT_LOCKED;
32import static android.view.Display.DEFAULT_DISPLAY;
33import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
34import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
35import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
36import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
37import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
38import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
39import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
40import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
41import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
42
43import android.annotation.NonNull;
44import android.annotation.Nullable;
45import android.app.Activity;
46import android.app.ActivityManager;
47import android.app.admin.IDevicePolicyManager;
48import android.content.Context;
49import android.os.Binder;
50import android.os.Debug;
51import android.os.Handler;
52import android.os.IBinder;
53import android.os.RemoteException;
54import android.os.ServiceManager;
55import android.provider.Settings;
56import android.util.Slog;
57
58import com.android.internal.annotations.VisibleForTesting;
59import com.android.internal.statusbar.IStatusBarService;
60import com.android.internal.widget.LockPatternUtils;
61import com.android.server.LocalServices;
62import com.android.server.statusbar.StatusBarManagerInternal;
63import com.android.server.wm.WindowManagerService;
64
65import java.io.PrintWriter;
66import java.util.ArrayList;
67
68/**
69 * Helper class that deals with all things related to task locking. This includes the screen pinning
70 * mode that can be launched via System UI as well as the fully locked mode that can be achieved
71 * on fully managed devices.
72 *
73 * Note: All methods in this class should only be called with the ActivityManagerService lock held.
74 *
75 * @see Activity#startLockTask()
76 * @see Activity#stopLockTask()
77 */
78public class LockTaskController {
79 private static final String TAG = TAG_WITH_CLASS_NAME ? "LockTaskController" : TAG_AM;
80 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
81
82 @VisibleForTesting
83 static final int STATUS_BAR_MASK_LOCKED = DISABLE_MASK
84 & (~DISABLE_BACK);
85 @VisibleForTesting
86 static final int STATUS_BAR_MASK_PINNED = DISABLE_MASK
87 & (~DISABLE_BACK)
88 & (~DISABLE_HOME)
89 & (~DISABLE_RECENT);
90
91 /** Tag used for disabling of keyguard */
92 private static final String LOCK_TASK_TAG = "Lock-to-App";
93
94 private final IBinder mToken = new Binder();
95 private final ActivityStackSupervisor mSupervisor;
96 private final Context mContext;
97
98 // The following system services cannot be final, because they do not exist when this class
99 // is instantiated during device boot
100 @VisibleForTesting
101 IStatusBarService mStatusBarService;
102 @VisibleForTesting
103 IDevicePolicyManager mDevicePolicyManager;
104 @VisibleForTesting
105 WindowManagerService mWindowManager;
106 @VisibleForTesting
107 LockPatternUtils mLockPatternUtils;
108
109 /**
110 * Helper that is responsible for showing the right toast when a disallowed activity operation
111 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
112 * fully locked mode we only show that unlocking is blocked.
113 */
114 @VisibleForTesting
115 LockTaskNotify mLockTaskNotify;
116
117 /**
118 * The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks
119 * may be finished until there is only one entry left. If this is empty the system is not
120 * in lockTask mode.
121 */
122 private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
123
124 /**
125 * Store the current lock task mode. Possible values:
126 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
127 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
128 */
129 private int mLockTaskModeState;
130
131 /**
132 * This is ActivityStackSupervisor's Handler.
133 */
134 private final Handler mHandler;
135
136 LockTaskController(Context context, ActivityStackSupervisor supervisor,
137 Handler handler) {
138 mContext = context;
139 mSupervisor = supervisor;
140 mHandler = handler;
141 }
142
143 /**
144 * Set the window manager instance used in this class. This is necessary, because the window
145 * manager does not exist during instantiation of this class.
146 */
147 void setWindowManager(WindowManagerService windowManager) {
148 mWindowManager = windowManager;
149 }
150
151 /**
152 * @return the current lock task state. This can be any of
153 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
154 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
155 */
156 int getLockTaskModeState() {
157 return mLockTaskModeState;
158 }
159
160 /**
161 * @return whether the given task can be moved to the back of the stack. Locked tasks cannot be
162 * moved to the back of the stack.
163 */
164 boolean checkLockedTask(TaskRecord task) {
165 if (mLockTaskModeTasks.contains(task)) {
166 showLockTaskToast();
167 return true;
168 }
169 return false;
170 }
171
172 /**
173 * @return whether the given activity is blocked from finishing, because it is the root activity
174 * of the last locked task and finishing it would mean that lock task mode is ended illegally.
175 */
176 boolean activityBlockedFromFinish(ActivityRecord activity) {
177 TaskRecord task = activity.getTask();
178 if (activity == task.getRootActivity()
179 && task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
180 && mLockTaskModeTasks.size() == 1
181 && mLockTaskModeTasks.contains(task)) {
182 Slog.i(TAG, "Not finishing task in lock task mode");
183 showLockTaskToast();
184 return true;
185 }
186 return false;
187 }
188
189 /**
190 * @return whether the requested task is allowed to be launched.
191 */
192 boolean isLockTaskModeViolation(TaskRecord task) {
193 return isLockTaskModeViolation(task, false);
194 }
195
196 /**
197 * @param isNewClearTask whether the task would be cleared as part of the operation.
198 * @return whether the requested task is allowed to be launched.
199 */
200 boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
201 if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
202 showLockTaskToast();
203 return true;
204 }
205 return false;
206 }
207
208 private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
209 // TODO: Double check what's going on here. If the task is already in lock task mode, it's
210 // likely whitelisted, so will return false below.
211 if (getLockedTask() == task && !isNewClearTask) {
212 // If the task is already at the top and won't be cleared, then allow the operation
213 return false;
214 }
215 final int lockTaskAuth = task.mLockTaskAuth;
216 switch (lockTaskAuth) {
217 case LOCK_TASK_AUTH_DONT_LOCK:
218 return !mLockTaskModeTasks.isEmpty();
219 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
220 case LOCK_TASK_AUTH_LAUNCHABLE:
221 case LOCK_TASK_AUTH_WHITELISTED:
222 return false;
223 case LOCK_TASK_AUTH_PINNABLE:
224 // Pinnable tasks can't be launched on top of locktask tasks.
225 return !mLockTaskModeTasks.isEmpty();
226 default:
227 Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth);
228 return true;
229 }
230 }
231
232 /**
233 * Stop the current lock task mode.
234 *
235 * @param isSystemInitiated indicates whether this request was initiated by the system via
236 * {@link ActivityManagerService#stopSystemLockTaskMode()}.
237 * @param callingUid the caller that requested the end of lock task mode.
238 * @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
239 * they differ from the one that launched lock task mode.
240 */
241 void stopLockTaskMode(boolean isSystemInitiated, int callingUid) {
242 final TaskRecord lockTask = getLockedTask();
243 if (lockTask == null || mLockTaskModeState == LOCK_TASK_MODE_NONE) {
244 // Our work here is done.
245 return;
246 }
247
248 if (isSystemInitiated && mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
249 // As system can only start app pinning, we also only let it unlock in this mode.
250 showLockTaskToast();
251 return;
252 }
253
254 // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
255 // It is possible lockTaskMode was started by the system process because
256 // android:lockTaskMode is set to a locking value in the application manifest
257 // instead of the app calling startLockTaskMode. In this case
258 // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
259 // {@link TaskRecord.effectiveUid} instead. Also caller with
260 // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
261 if (!isSystemInitiated && callingUid != lockTask.mLockTaskUid
262 && (lockTask.mLockTaskUid != 0 || callingUid != lockTask.effectiveUid)) {
263 throw new SecurityException("Invalid uid, expected " + lockTask.mLockTaskUid
264 + " callingUid=" + callingUid + " effectiveUid=" + lockTask.effectiveUid);
265 }
266
267 clearLockTaskMode("stopLockTask");
268 }
269
270 /**
271 * Remove the given task from the locked task list. If this was the last task in the list,
272 * lock task mode is stopped.
273 */
274 void removeLockedTask(final TaskRecord task) {
275 if (!mLockTaskModeTasks.remove(task)) {
276 return;
277 }
278 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "removeLockedTask: removed " + task);
279 if (mLockTaskModeTasks.isEmpty()) {
280 // Last one.
281 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
282 " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
283 mHandler.post(() -> performStopLockTask(task.userId));
284 }
285 }
286
287 /**
288 * Remove the topmost task from the locked task list. If this is the last task in the list, it
289 * will result in the end of locked task mode.
290 */
291 void clearLockTaskMode(String reason) {
292 // Take out of lock task mode if necessary
293 final TaskRecord lockedTask = getLockedTask();
294 if (lockedTask != null) {
295 removeLockedTask(lockedTask);
296 if (!mLockTaskModeTasks.isEmpty()) {
297 // There are locked tasks remaining, can only finish this task, not unlock it.
298 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
299 "setLockTaskMode: Tasks remaining, can't unlock");
300 lockedTask.performClearTaskLocked();
301 mSupervisor.resumeFocusedStackTopActivityLocked();
302 return;
303 }
304 }
305 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
306 "setLockTaskMode: No tasks to unlock. Callers=" + Debug.getCallers(4));
307 }
308
309 // This method should only be called on the handler thread
310 private void performStopLockTask(int userId) {
311 // When lock task ends, we enable the status bars.
312 try {
313 if (getStatusBarService() != null) {
314 getStatusBarService().disable(DISABLE_NONE, mToken,
315 mContext.getPackageName());
316 }
317 mWindowManager.reenableKeyguard(mToken);
318 if (getDevicePolicyManager() != null) {
319 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
320 }
321 getLockTaskNotify().show(false);
322 try {
323 boolean shouldLockKeyguard = Settings.Secure.getInt(
324 mContext.getContentResolver(),
325 LOCK_TO_APP_EXIT_LOCKED) != 0;
326 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
327 mWindowManager.lockNow(null);
328 mWindowManager.dismissKeyguard(null /* callback */);
329 getLockPatternUtils().requireCredentialEntry(USER_ALL);
330 }
331 } catch (Settings.SettingNotFoundException e) {
332 // No setting, don't lock.
333 }
334 } catch (RemoteException ex) {
335 throw new RuntimeException(ex);
336 } finally {
337 mLockTaskModeState = LOCK_TASK_MODE_NONE;
338 }
339 }
340
341 /**
342 * Show the lock task violation toast.
343 */
344 void showLockTaskToast() {
345 mHandler.post(() -> getLockTaskNotify().showToast(mLockTaskModeState));
346 }
347
348 // Starting lock task
349
350 /**
351 * Method to start lock task mode on a given task.
352 *
353 * @param task the task that should be locked.
354 * @param isSystemInitiated indicates whether this request was initiated by the system via
355 * {@link ActivityManagerService#startSystemLockTaskMode(int)}.
356 * @param callingUid the caller that requested the launch of lock task mode.
357 */
358 void startLockTaskMode(@NonNull TaskRecord task, boolean isSystemInitiated,
359 int callingUid) {
360 if (!isSystemInitiated) {
361 task.mLockTaskUid = callingUid;
362 if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
363 // startLockTask() called by app, but app is not part of lock task whitelist. Show
364 // app pinning request. We will come back here with isSystemInitiated true.
365 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
366 StatusBarManagerInternal statusBarManager = LocalServices.getService(
367 StatusBarManagerInternal.class);
368 if (statusBarManager != null) {
369 statusBarManager.showScreenPinningRequest(task.taskId);
370 }
371 return;
372 }
373 }
374
375 // System can only initiate screen pinning, not full lock task mode
376 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, isSystemInitiated ? "Locking pinned" : "Locking fully");
377 setLockTaskMode(task, isSystemInitiated ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
378 "startLockTask", true);
379 }
380
381 /**
382 * Start lock task mode on the given task.
383 * @param lockTaskModeState whether fully locked or pinned mode.
384 * @param andResume whether the task should be brought to foreground as part of the operation.
385 */
386 private void setLockTaskMode(@NonNull TaskRecord task, int lockTaskModeState,
387 String reason, boolean andResume) {
388 // Should have already been checked, but do it again.
389 if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
390 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
391 "setLockTaskMode: Can't lock due to auth");
392 return;
393 }
394 if (isLockTaskModeViolation(task)) {
395 Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task.");
396 return;
397 }
398
399 if (mLockTaskModeTasks.isEmpty()) {
400 // Start lock task on the handler thread
401 mHandler.post(() -> performStartLockTask(
402 task.intent.getComponent().getPackageName(),
403 task.userId,
404 lockTaskModeState));
405 }
406
407 // Add it or move it to the top.
408 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
409 " Callers=" + Debug.getCallers(4));
410 mLockTaskModeTasks.remove(task);
411 mLockTaskModeTasks.add(task);
412
413 if (task.mLockTaskUid == -1) {
414 task.mLockTaskUid = task.effectiveUid;
415 }
416
417 if (andResume) {
418 mSupervisor.findTaskToMoveToFrontLocked(task, 0, null, reason,
419 lockTaskModeState != LOCK_TASK_MODE_NONE);
420 mSupervisor.resumeFocusedStackTopActivityLocked();
421 mWindowManager.executeAppTransition();
422 } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
423 mSupervisor.handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
424 task.getStackId(), true /* forceNonResizable */);
425 }
426 }
427
428 // This method should only be called on the handler thread
429 private void performStartLockTask(String packageName, int userId, int lockTaskModeState) {
430 // When lock task starts, we disable the status bars.
431 try {
432 getLockTaskNotify().show(true);
433 mLockTaskModeState = lockTaskModeState;
434 if (getStatusBarService() != null) {
435 int flags = 0;
436 if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
437 flags = STATUS_BAR_MASK_LOCKED;
438 } else if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
439 flags = STATUS_BAR_MASK_PINNED;
440 }
441 getStatusBarService().disable(flags, mToken, mContext.getPackageName());
442 }
443 mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
444 if (getDevicePolicyManager() != null) {
445 getDevicePolicyManager().notifyLockTaskModeChanged(true, packageName, userId);
446 }
447 } catch (RemoteException ex) {
448 throw new RuntimeException(ex);
449 }
450 }
451
452 /**
453 * Called when the list of packages whitelisted for lock task mode is changed. Any currently
454 * locked tasks that got removed from the whitelist will be finished.
455 */
456 // TODO: Missing unit tests
457 void onLockTaskPackagesUpdated() {
458 boolean didSomething = false;
459 for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
460 final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
461 final boolean wasWhitelisted =
462 (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
463 (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
464 lockedTask.setLockTaskAuth();
465 final boolean isWhitelisted =
466 (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
467 (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
468 if (wasWhitelisted && !isWhitelisted) {
469 // Lost whitelisting authorization. End it now.
470 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
471 lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
472 removeLockedTask(lockedTask);
473 lockedTask.performClearTaskLocked();
474 didSomething = true;
475 }
476 }
477
478 for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) {
479 ArrayList<ActivityStack> stacks = mSupervisor.getChildAt(displayNdx).mStacks;
480 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
481 final ActivityStack stack = stacks.get(stackNdx);
482 stack.onLockTaskPackagesUpdatedLocked();
483 }
484 }
485 final ActivityRecord r = mSupervisor.topRunningActivityLocked();
486 final TaskRecord task = r != null ? r.getTask() : null;
487 if (mLockTaskModeTasks.isEmpty() && task != null
488 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
489 // This task must have just been authorized.
490 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
491 "onLockTaskPackagesUpdated: starting new locktask task=" + task);
492 setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated",
493 false);
494 didSomething = true;
495 }
496 if (didSomething) {
497 mSupervisor.resumeFocusedStackTopActivityLocked();
498 }
499 }
500
501 /**
502 * @return the topmost locked task
503 */
504 private TaskRecord getLockedTask() {
505 final int top = mLockTaskModeTasks.size() - 1;
506 if (top >= 0) {
507 return mLockTaskModeTasks.get(top);
508 }
509 return null;
510 }
511
512 // Should only be called on the handler thread
513 @Nullable
514 private IStatusBarService getStatusBarService() {
515 if (mStatusBarService == null) {
516 mStatusBarService = IStatusBarService.Stub.asInterface(
517 ServiceManager.checkService(STATUS_BAR_SERVICE));
518 if (mStatusBarService == null) {
519 Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
520 }
521 }
522 return mStatusBarService;
523 }
524
525 // Should only be called on the handler thread
526 @Nullable
527 private IDevicePolicyManager getDevicePolicyManager() {
528 if (mDevicePolicyManager == null) {
529 mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
530 ServiceManager.checkService(DEVICE_POLICY_SERVICE));
531 if (mDevicePolicyManager == null) {
532 Slog.w(TAG, "warning: no DEVICE_POLICY_SERVICE");
533 }
534 }
535 return mDevicePolicyManager;
536 }
537
538 @NonNull
539 private LockPatternUtils getLockPatternUtils() {
540 if (mLockPatternUtils == null) {
541 // We don't preserve the LPU object to save memory
542 return new LockPatternUtils(mContext);
543 }
544 return mLockPatternUtils;
545 }
546
547 // Should only be called on the handler thread
548 @NonNull
549 private LockTaskNotify getLockTaskNotify() {
550 if (mLockTaskNotify == null) {
551 mLockTaskNotify = new LockTaskNotify(mContext);
552 }
553 return mLockTaskNotify;
554 }
555
556 public void dump(PrintWriter pw, String prefix) {
557 pw.print(prefix); pw.print("mLockTaskModeState=" + lockTaskModeToString());
558 pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
559 }
560
561 private String lockTaskModeToString() {
562 switch (mLockTaskModeState) {
563 case LOCK_TASK_MODE_LOCKED:
564 return "LOCKED";
565 case LOCK_TASK_MODE_PINNED:
566 return "PINNED";
567 case LOCK_TASK_MODE_NONE:
568 return "NONE";
569 default: return "unknown=" + mLockTaskModeState;
570 }
571 }
572}