blob: 4b2a08439f2da2c24e3605cb6856a96f6ea589e7 [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 /**
146 * The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks
147 * may be finished until there is only one entry left. If this is empty the system is not
148 * in lockTask mode.
149 */
150 private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
151
152 /**
Charles He520b2832017-09-02 15:27:16 +0100153 * Packages that are allowed to be launched into the lock task mode for each user.
154 */
155 private final SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
156
157 /**
Charles Hee078db72017-10-19 18:03:20 +0100158 * Features that are allowed by DPC to show during LockTask mode.
159 */
160 private final SparseArray<Integer> mLockTaskFeatures = new SparseArray<>();
161
162 /**
Benjamin Franza83859f2017-07-03 16:34:14 +0100163 * Store the current lock task mode. Possible values:
164 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
165 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
166 */
167 private int mLockTaskModeState;
168
169 /**
170 * This is ActivityStackSupervisor's Handler.
171 */
172 private final Handler mHandler;
173
174 LockTaskController(Context context, ActivityStackSupervisor supervisor,
175 Handler handler) {
176 mContext = context;
177 mSupervisor = supervisor;
178 mHandler = handler;
179 }
180
181 /**
182 * Set the window manager instance used in this class. This is necessary, because the window
183 * manager does not exist during instantiation of this class.
184 */
185 void setWindowManager(WindowManagerService windowManager) {
186 mWindowManager = windowManager;
187 }
188
189 /**
190 * @return the current lock task state. This can be any of
191 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
192 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
193 */
194 int getLockTaskModeState() {
195 return mLockTaskModeState;
196 }
197
198 /**
Charles He520b2832017-09-02 15:27:16 +0100199 * @return whether the given task is locked at the moment. Locked tasks cannot be moved to the
200 * back of the stack.
Benjamin Franza83859f2017-07-03 16:34:14 +0100201 */
202 boolean checkLockedTask(TaskRecord task) {
203 if (mLockTaskModeTasks.contains(task)) {
204 showLockTaskToast();
205 return true;
206 }
207 return false;
208 }
209
210 /**
211 * @return whether the given activity is blocked from finishing, because it is the root activity
212 * of the last locked task and finishing it would mean that lock task mode is ended illegally.
213 */
214 boolean activityBlockedFromFinish(ActivityRecord activity) {
215 TaskRecord task = activity.getTask();
216 if (activity == task.getRootActivity()
217 && task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
218 && mLockTaskModeTasks.size() == 1
219 && mLockTaskModeTasks.contains(task)) {
220 Slog.i(TAG, "Not finishing task in lock task mode");
221 showLockTaskToast();
222 return true;
223 }
224 return false;
225 }
226
227 /**
228 * @return whether the requested task is allowed to be launched.
229 */
230 boolean isLockTaskModeViolation(TaskRecord task) {
231 return isLockTaskModeViolation(task, false);
232 }
233
234 /**
235 * @param isNewClearTask whether the task would be cleared as part of the operation.
236 * @return whether the requested task is allowed to be launched.
237 */
238 boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
239 if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
240 showLockTaskToast();
241 return true;
242 }
243 return false;
244 }
245
246 private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
247 // TODO: Double check what's going on here. If the task is already in lock task mode, it's
248 // likely whitelisted, so will return false below.
249 if (getLockedTask() == task && !isNewClearTask) {
250 // If the task is already at the top and won't be cleared, then allow the operation
251 return false;
252 }
253 final int lockTaskAuth = task.mLockTaskAuth;
254 switch (lockTaskAuth) {
255 case LOCK_TASK_AUTH_DONT_LOCK:
256 return !mLockTaskModeTasks.isEmpty();
257 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
258 case LOCK_TASK_AUTH_LAUNCHABLE:
259 case LOCK_TASK_AUTH_WHITELISTED:
260 return false;
261 case LOCK_TASK_AUTH_PINNABLE:
262 // Pinnable tasks can't be launched on top of locktask tasks.
263 return !mLockTaskModeTasks.isEmpty();
264 default:
265 Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth);
266 return true;
267 }
268 }
269
270 /**
271 * Stop the current lock task mode.
272 *
273 * @param isSystemInitiated indicates whether this request was initiated by the system via
274 * {@link ActivityManagerService#stopSystemLockTaskMode()}.
275 * @param callingUid the caller that requested the end of lock task mode.
276 * @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
277 * they differ from the one that launched lock task mode.
278 */
279 void stopLockTaskMode(boolean isSystemInitiated, int callingUid) {
280 final TaskRecord lockTask = getLockedTask();
281 if (lockTask == null || mLockTaskModeState == LOCK_TASK_MODE_NONE) {
282 // Our work here is done.
283 return;
284 }
285
286 if (isSystemInitiated && mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
287 // As system can only start app pinning, we also only let it unlock in this mode.
288 showLockTaskToast();
289 return;
290 }
291
292 // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
293 // It is possible lockTaskMode was started by the system process because
294 // android:lockTaskMode is set to a locking value in the application manifest
295 // instead of the app calling startLockTaskMode. In this case
296 // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
297 // {@link TaskRecord.effectiveUid} instead. Also caller with
298 // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
299 if (!isSystemInitiated && callingUid != lockTask.mLockTaskUid
300 && (lockTask.mLockTaskUid != 0 || callingUid != lockTask.effectiveUid)) {
301 throw new SecurityException("Invalid uid, expected " + lockTask.mLockTaskUid
302 + " callingUid=" + callingUid + " effectiveUid=" + lockTask.effectiveUid);
303 }
304
305 clearLockTaskMode("stopLockTask");
306 }
307
308 /**
309 * Remove the given task from the locked task list. If this was the last task in the list,
310 * lock task mode is stopped.
311 */
312 void removeLockedTask(final TaskRecord task) {
313 if (!mLockTaskModeTasks.remove(task)) {
314 return;
315 }
316 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "removeLockedTask: removed " + task);
317 if (mLockTaskModeTasks.isEmpty()) {
318 // Last one.
319 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
320 " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
321 mHandler.post(() -> performStopLockTask(task.userId));
322 }
323 }
324
325 /**
326 * Remove the topmost task from the locked task list. If this is the last task in the list, it
327 * will result in the end of locked task mode.
328 */
329 void clearLockTaskMode(String reason) {
330 // Take out of lock task mode if necessary
331 final TaskRecord lockedTask = getLockedTask();
332 if (lockedTask != null) {
333 removeLockedTask(lockedTask);
334 if (!mLockTaskModeTasks.isEmpty()) {
335 // There are locked tasks remaining, can only finish this task, not unlock it.
336 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
337 "setLockTaskMode: Tasks remaining, can't unlock");
338 lockedTask.performClearTaskLocked();
339 mSupervisor.resumeFocusedStackTopActivityLocked();
340 return;
341 }
342 }
343 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
344 "setLockTaskMode: No tasks to unlock. Callers=" + Debug.getCallers(4));
345 }
346
347 // This method should only be called on the handler thread
348 private void performStopLockTask(int userId) {
349 // When lock task ends, we enable the status bars.
350 try {
Charles Hee078db72017-10-19 18:03:20 +0100351 setStatusBarState(LOCK_TASK_MODE_NONE, userId);
352 setKeyguardState(LOCK_TASK_MODE_NONE, userId);
353 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
354 lockKeyguardIfNeeded();
Benjamin Franza83859f2017-07-03 16:34:14 +0100355 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100356 if (getDevicePolicyManager() != null) {
357 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
358 }
Charles Hebfe82d12017-10-20 11:59:44 +0100359 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
360 getLockTaskNotify().showPinningExitToast();
361 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100362 } catch (RemoteException ex) {
363 throw new RuntimeException(ex);
364 } finally {
365 mLockTaskModeState = LOCK_TASK_MODE_NONE;
366 }
367 }
368
369 /**
Charles Hebfe82d12017-10-20 11:59:44 +0100370 * Show the lock task violation toast. Currently we only show toast for screen pinning mode, and
371 * no-op if the device is in locked mode.
Benjamin Franza83859f2017-07-03 16:34:14 +0100372 */
373 void showLockTaskToast() {
Charles Hebfe82d12017-10-20 11:59:44 +0100374 if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
375 mHandler.post(() -> getLockTaskNotify().showEscapeToast());
376 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100377 }
378
379 // Starting lock task
380
381 /**
382 * Method to start lock task mode on a given task.
383 *
384 * @param task the task that should be locked.
385 * @param isSystemInitiated indicates whether this request was initiated by the system via
386 * {@link ActivityManagerService#startSystemLockTaskMode(int)}.
387 * @param callingUid the caller that requested the launch of lock task mode.
388 */
389 void startLockTaskMode(@NonNull TaskRecord task, boolean isSystemInitiated,
390 int callingUid) {
391 if (!isSystemInitiated) {
392 task.mLockTaskUid = callingUid;
393 if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
394 // startLockTask() called by app, but app is not part of lock task whitelist. Show
395 // app pinning request. We will come back here with isSystemInitiated true.
396 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
397 StatusBarManagerInternal statusBarManager = LocalServices.getService(
398 StatusBarManagerInternal.class);
399 if (statusBarManager != null) {
400 statusBarManager.showScreenPinningRequest(task.taskId);
401 }
402 return;
403 }
404 }
405
406 // System can only initiate screen pinning, not full lock task mode
407 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, isSystemInitiated ? "Locking pinned" : "Locking fully");
408 setLockTaskMode(task, isSystemInitiated ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
409 "startLockTask", true);
410 }
411
412 /**
413 * Start lock task mode on the given task.
414 * @param lockTaskModeState whether fully locked or pinned mode.
415 * @param andResume whether the task should be brought to foreground as part of the operation.
416 */
417 private void setLockTaskMode(@NonNull TaskRecord task, int lockTaskModeState,
418 String reason, boolean andResume) {
419 // Should have already been checked, but do it again.
420 if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
421 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
422 "setLockTaskMode: Can't lock due to auth");
423 return;
424 }
425 if (isLockTaskModeViolation(task)) {
426 Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task.");
427 return;
428 }
429
430 if (mLockTaskModeTasks.isEmpty()) {
431 // Start lock task on the handler thread
432 mHandler.post(() -> performStartLockTask(
433 task.intent.getComponent().getPackageName(),
434 task.userId,
435 lockTaskModeState));
436 }
437
438 // Add it or move it to the top.
439 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
440 " Callers=" + Debug.getCallers(4));
441 mLockTaskModeTasks.remove(task);
442 mLockTaskModeTasks.add(task);
443
444 if (task.mLockTaskUid == -1) {
445 task.mLockTaskUid = task.effectiveUid;
446 }
447
448 if (andResume) {
Wale Ogunwale66e16852017-10-19 13:35:52 -0700449 mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
Benjamin Franza83859f2017-07-03 16:34:14 +0100450 lockTaskModeState != LOCK_TASK_MODE_NONE);
451 mSupervisor.resumeFocusedStackTopActivityLocked();
452 mWindowManager.executeAppTransition();
453 } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700454 mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700455 DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */);
Benjamin Franza83859f2017-07-03 16:34:14 +0100456 }
457 }
458
459 // This method should only be called on the handler thread
460 private void performStartLockTask(String packageName, int userId, int lockTaskModeState) {
461 // When lock task starts, we disable the status bars.
462 try {
Charles Hebfe82d12017-10-20 11:59:44 +0100463 if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
464 getLockTaskNotify().showPinningStartToast();
465 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100466 mLockTaskModeState = lockTaskModeState;
Charles Hee078db72017-10-19 18:03:20 +0100467 setStatusBarState(lockTaskModeState, userId);
468 setKeyguardState(lockTaskModeState, userId);
Benjamin Franza83859f2017-07-03 16:34:14 +0100469 if (getDevicePolicyManager() != null) {
470 getDevicePolicyManager().notifyLockTaskModeChanged(true, packageName, userId);
471 }
472 } catch (RemoteException ex) {
473 throw new RuntimeException(ex);
474 }
475 }
476
477 /**
Charles He520b2832017-09-02 15:27:16 +0100478 * Update packages that are allowed to be launched in lock task mode.
479 * @param userId Which user this whitelist is associated with
480 * @param packages The whitelist of packages allowed in lock task mode
481 * @see #mLockTaskPackages
Benjamin Franza83859f2017-07-03 16:34:14 +0100482 */
Charles He520b2832017-09-02 15:27:16 +0100483 void updateLockTaskPackages(int userId, String[] packages) {
484 mLockTaskPackages.put(userId, packages);
485
486 boolean taskChanged = false;
Benjamin Franza83859f2017-07-03 16:34:14 +0100487 for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
488 final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
Charles He520b2832017-09-02 15:27:16 +0100489 final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
490 || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
Benjamin Franza83859f2017-07-03 16:34:14 +0100491 lockedTask.setLockTaskAuth();
Charles He520b2832017-09-02 15:27:16 +0100492 final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
493 || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
494
495 if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
496 || lockedTask.userId != userId
497 || !wasWhitelisted || isWhitelisted) {
498 continue;
Benjamin Franza83859f2017-07-03 16:34:14 +0100499 }
Charles He520b2832017-09-02 15:27:16 +0100500
501 // Terminate locked tasks that have recently lost whitelist authorization.
502 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
503 lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
504 removeLockedTask(lockedTask);
505 lockedTask.performClearTaskLocked();
506 taskChanged = true;
Benjamin Franza83859f2017-07-03 16:34:14 +0100507 }
508
509 for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700510 mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated();
Benjamin Franza83859f2017-07-03 16:34:14 +0100511 }
Charles He520b2832017-09-02 15:27:16 +0100512
Benjamin Franza83859f2017-07-03 16:34:14 +0100513 final ActivityRecord r = mSupervisor.topRunningActivityLocked();
Charles He520b2832017-09-02 15:27:16 +0100514 final TaskRecord task = (r != null) ? r.getTask() : null;
515 if (mLockTaskModeTasks.isEmpty() && task!= null
Benjamin Franza83859f2017-07-03 16:34:14 +0100516 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
517 // This task must have just been authorized.
518 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
519 "onLockTaskPackagesUpdated: starting new locktask task=" + task);
Charles He520b2832017-09-02 15:27:16 +0100520 setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
521 taskChanged = true;
Benjamin Franza83859f2017-07-03 16:34:14 +0100522 }
Charles He520b2832017-09-02 15:27:16 +0100523
524 if (taskChanged) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100525 mSupervisor.resumeFocusedStackTopActivityLocked();
526 }
527 }
528
Charles He520b2832017-09-02 15:27:16 +0100529 boolean isPackageWhitelisted(int userId, String pkg) {
530 if (pkg == null) {
531 return false;
532 }
533 String[] whitelist;
534 whitelist = mLockTaskPackages.get(userId);
535 if (whitelist == null) {
536 return false;
537 }
538 for (String whitelistedPkg : whitelist) {
539 if (pkg.equals(whitelistedPkg)) {
540 return true;
541 }
542 }
543 return false;
544 }
545
Benjamin Franza83859f2017-07-03 16:34:14 +0100546 /**
Charles Hee078db72017-10-19 18:03:20 +0100547 * Update the UI features that are enabled for LockTask mode.
548 * @param userId Which user these feature flags are associated with
549 * @param flags Bitfield of feature flags
550 * @see DevicePolicyManager#setLockTaskFeatures(ComponentName, int)
551 */
552 void updateLockTaskFeatures(int userId, int flags) {
553 int oldFlags = getLockTaskFeaturesForUser(userId);
554 if (flags == oldFlags) {
555 return;
556 }
557
558 mLockTaskFeatures.put(userId, flags);
559 TaskRecord lockedTask = getLockedTask();
560 if (lockedTask != null && userId == lockedTask.userId) {
561 mHandler.post(() -> {
562 if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
563 setStatusBarState(mLockTaskModeState, userId);
564 setKeyguardState(mLockTaskModeState, userId);
565 }
566 });
567 }
568 }
569
570 /**
571 * Helper method for configuring the status bar disabled state.
572 * Should only be called on the handler thread to avoid race.
573 */
574 private void setStatusBarState(int lockTaskModeState, int userId) {
575 IStatusBarService statusBar = getStatusBarService();
576 if (statusBar == null) {
577 Slog.e(TAG, "Can't find StatusBarService");
578 return;
579 }
580
581 // Default state, when lockTaskModeState == LOCK_TASK_MODE_NONE
582 int flags1 = StatusBarManager.DISABLE_NONE;
583 int flags2 = StatusBarManager.DISABLE2_NONE;
584
585 if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
586 flags1 = STATUS_BAR_MASK_PINNED;
587
588 } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
589 int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
590 Pair<Integer, Integer> statusBarFlags = getStatusBarDisableFlags(lockTaskFeatures);
591 flags1 = statusBarFlags.first;
592 flags2 = statusBarFlags.second;
593 }
594
595 try {
596 statusBar.disable(flags1, mToken, mContext.getPackageName());
597 statusBar.disable2(flags2, mToken, mContext.getPackageName());
598 } catch (RemoteException e) {
599 Slog.e(TAG, "Failed to set status bar flags", e);
600 }
601 }
602
603 /**
604 * Helper method for configuring the keyguard disabled state.
605 * Should only be called on the handler thread to avoid race.
606 */
607 private void setKeyguardState(int lockTaskModeState, int userId) {
608 if (lockTaskModeState == LOCK_TASK_MODE_NONE) {
609 mWindowManager.reenableKeyguard(mToken);
610
611 } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
612 int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
613 if ((DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD & lockTaskFeatures) == 0) {
614 mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
615 } else {
616 mWindowManager.reenableKeyguard(mToken);
617 }
618
619 } else { // lockTaskModeState == LOCK_TASK_MODE_PINNED
620 mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
621 }
622 }
623
624 /**
625 * Helper method for locking the device immediately. This may be necessary when the device
626 * leaves the pinned mode.
627 */
628 private void lockKeyguardIfNeeded() {
629 try {
630 boolean shouldLockKeyguard = Settings.Secure.getIntForUser(
631 mContext.getContentResolver(),
632 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
633 USER_CURRENT) != 0;
634 if (shouldLockKeyguard) {
635 mWindowManager.lockNow(null);
636 mWindowManager.dismissKeyguard(null /* callback */);
637 getLockPatternUtils().requireCredentialEntry(USER_ALL);
638 }
639 } catch (Settings.SettingNotFoundException e) {
640 // No setting, don't lock.
641 }
642 }
643
644 /**
645 * Translates from LockTask feature flags to StatusBarManager disable and disable2 flags.
646 * @param lockTaskFlags Bitfield of flags as per
647 * {@link DevicePolicyManager#setLockTaskFeatures(ComponentName, int)}
648 * @return A {@link Pair} of {@link StatusBarManager#disable(int)} and
649 * {@link StatusBarManager#disable2(int)} flags
650 */
651 @VisibleForTesting
652 Pair<Integer, Integer> getStatusBarDisableFlags(int lockTaskFlags) {
653 // Everything is disabled by default
654 int flags1 = StatusBarManager.DISABLE_MASK;
655 int flags2 = StatusBarManager.DISABLE2_MASK;
656 for (int i = STATUS_BAR_FLAG_MAP_LOCKED.size() - 1; i >= 0; i--) {
657 Pair<Integer, Integer> statusBarFlags = STATUS_BAR_FLAG_MAP_LOCKED.valueAt(i);
658 if ((STATUS_BAR_FLAG_MAP_LOCKED.keyAt(i) & lockTaskFlags) != 0) {
659 flags1 &= ~statusBarFlags.first;
660 flags2 &= ~statusBarFlags.second;
661 }
662 }
663 // Some flags are not used for LockTask purposes, so we mask them
664 flags1 &= STATUS_BAR_MASK_LOCKED;
665 return new Pair<>(flags1, flags2);
666 }
667
668 /**
669 * Gets the cached value of LockTask feature flags for a specific user.
670 */
671 private int getLockTaskFeaturesForUser(int userId) {
672 return mLockTaskFeatures.get(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
673 }
674
675 /**
Benjamin Franza83859f2017-07-03 16:34:14 +0100676 * @return the topmost locked task
677 */
678 private TaskRecord getLockedTask() {
679 final int top = mLockTaskModeTasks.size() - 1;
680 if (top >= 0) {
681 return mLockTaskModeTasks.get(top);
682 }
683 return null;
684 }
685
686 // Should only be called on the handler thread
687 @Nullable
688 private IStatusBarService getStatusBarService() {
689 if (mStatusBarService == null) {
690 mStatusBarService = IStatusBarService.Stub.asInterface(
691 ServiceManager.checkService(STATUS_BAR_SERVICE));
692 if (mStatusBarService == null) {
693 Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
694 }
695 }
696 return mStatusBarService;
697 }
698
699 // Should only be called on the handler thread
700 @Nullable
701 private IDevicePolicyManager getDevicePolicyManager() {
702 if (mDevicePolicyManager == null) {
703 mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
704 ServiceManager.checkService(DEVICE_POLICY_SERVICE));
705 if (mDevicePolicyManager == null) {
706 Slog.w(TAG, "warning: no DEVICE_POLICY_SERVICE");
707 }
708 }
709 return mDevicePolicyManager;
710 }
711
712 @NonNull
713 private LockPatternUtils getLockPatternUtils() {
714 if (mLockPatternUtils == null) {
715 // We don't preserve the LPU object to save memory
716 return new LockPatternUtils(mContext);
717 }
718 return mLockPatternUtils;
719 }
720
721 // Should only be called on the handler thread
722 @NonNull
723 private LockTaskNotify getLockTaskNotify() {
724 if (mLockTaskNotify == null) {
725 mLockTaskNotify = new LockTaskNotify(mContext);
726 }
727 return mLockTaskNotify;
728 }
729
730 public void dump(PrintWriter pw, String prefix) {
Charles He520b2832017-09-02 15:27:16 +0100731 pw.println(prefix + "LockTaskController");
732 prefix = prefix + " ";
733 pw.println(prefix + "mLockTaskModeState=" + lockTaskModeToString());
734 pw.println(prefix + "mLockTaskModeTasks=");
735 for (int i = 0; i < mLockTaskModeTasks.size(); ++i) {
736 pw.println(prefix + " #" + i + " " + mLockTaskModeTasks.get(i));
737 }
738 pw.println(prefix + "mLockTaskPackages (userId:packages)=");
739 for (int i = 0; i < mLockTaskPackages.size(); ++i) {
740 pw.println(prefix + " u" + mLockTaskPackages.keyAt(i)
741 + ":" + Arrays.toString(mLockTaskPackages.valueAt(i)));
742 }
Benjamin Franza83859f2017-07-03 16:34:14 +0100743 }
744
745 private String lockTaskModeToString() {
746 switch (mLockTaskModeState) {
747 case LOCK_TASK_MODE_LOCKED:
748 return "LOCKED";
749 case LOCK_TASK_MODE_PINNED:
750 return "PINNED";
751 case LOCK_TASK_MODE_NONE:
752 return "NONE";
753 default: return "unknown=" + mLockTaskModeState;
754 }
755 }
756}