Introduce android:lockTaskMode
The ability for tasks to be started in locktask mode or pinned is
dependent on the value of android:lockTaskMode for the root activity
of the task.
For bug 19995702
Change-Id: I514a144a3a0ff7dbdd4987da5361b94bdfe9a437
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b606353..f25808b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,10 +26,14 @@
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -3982,13 +3986,13 @@
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
}
- // Do not allow task to finish in Lock Task mode.
- if (tr == mStackSupervisor.mLockTaskModeTask) {
- if (rootR == r) {
- Slog.i(TAG, "Not finishing task in lock task mode");
- mStackSupervisor.showLockTaskToast();
- return false;
- }
+ // Do not allow task to finish if last task in lockTask mode. Launchable apps can
+ // finish themselves.
+ if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && rootR == r &&
+ mStackSupervisor.isLastLockedTask(tr)) {
+ Slog.i(TAG, "Not finishing task in lock task mode");
+ mStackSupervisor.showLockTaskToast();
+ return false;
}
if (mController != null) {
// Find the first activity that is not finishing.
@@ -4142,20 +4146,18 @@
final long origId = Binder.clearCallingIdentity();
try {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return false;
+ }
- ActivityRecord rootR = r.task.getRootActivity();
- // Do not allow task to finish in Lock Task mode.
- if (r.task == mStackSupervisor.mLockTaskModeTask) {
- if (rootR == r) {
- mStackSupervisor.showLockTaskToast();
- return false;
- }
+ // Do not allow the last non-launchable task to finish in Lock Task mode.
+ final TaskRecord task = r.task;
+ if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE &&
+ mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
+ mStackSupervisor.showLockTaskToast();
+ return false;
}
- boolean res = false;
- if (r != null) {
- res = r.task.stack.finishActivityAffinityLocked(r);
- }
- return res;
+ return task.stack.finishActivityAffinityLocked(r);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -8336,9 +8338,9 @@
final long origId = Binder.clearCallingIdentity();
try {
int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
- if (taskId >= 0) {
- if ((mStackSupervisor.mLockTaskModeTask != null)
- && (mStackSupervisor.mLockTaskModeTask.taskId == taskId)) {
+ final TaskRecord task = mRecentTasks.taskForIdLocked(taskId);
+ if (task != null) {
+ if (mStackSupervisor.isLockedTask(task)) {
mStackSupervisor.showLockTaskToast();
return false;
}
@@ -8520,47 +8522,45 @@
@Override
public void updateLockTaskPackages(int userId, String[] packages) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
throw new SecurityException("updateLockTaskPackage called from non-system process");
}
synchronized (this) {
mLockTaskPackages.put(userId, packages);
+ mStackSupervisor.onLockTaskPackagesUpdatedLocked();
}
}
- private boolean isLockTaskAuthorizedLocked(String pkg) {
- String[] packages = mLockTaskPackages.get(mCurrentUserId);
- if (packages == null) {
- return false;
- }
- for (int i = packages.length - 1; i >= 0; --i) {
- if (pkg.equals(packages[i])) {
- return true;
- }
- }
- return false;
- }
void startLockTaskModeLocked(TaskRecord task) {
- final String pkg = task.intent.getComponent().getPackageName();
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
+ return;
+ }
+
// isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
// is initiated by system after the pinning request was shown and locked mode is initiated
// by an authorized app directly
- boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
+ final int callingUid = Binder.getCallingUid();
+ boolean isSystemInitiated = callingUid == Process.SYSTEM_UID;
long ident = Binder.clearCallingIdentity();
try {
- if (!isSystemInitiated && !isLockTaskAuthorizedLocked(pkg)) {
- StatusBarManagerInternal statusBarManager =
- LocalServices.getService(StatusBarManagerInternal.class);
- if (statusBarManager != null) {
- statusBarManager.showScreenPinningRequest();
- }
- return;
- }
-
final ActivityStack stack = mStackSupervisor.getFocusedStack();
- if (!isSystemInitiated && (stack == null || task != stack.topTask())) {
- throw new IllegalArgumentException("Invalid task, not in foreground");
+ if (!isSystemInitiated) {
+ task.mLockTaskUid = callingUid;
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
+ // startLockTask() called by app and task mode is lockTaskModeDefault.
+ StatusBarManagerInternal statusBarManager =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ if (statusBarManager != null) {
+ statusBarManager.showScreenPinningRequest();
+ }
+ return;
+ }
+
+ if (stack == null || task != stack.topTask()) {
+ throw new IllegalArgumentException("Invalid task, not in foreground");
+ }
}
mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
ActivityManager.LOCK_TASK_MODE_PINNED :
@@ -8614,23 +8614,15 @@
@Override
public void stopLockTaskMode() {
- // Verify that the user matches the package of the intent for the TaskRecord
- // we are locked to or systtem. This will ensure the same caller for startLockTaskMode
- // and stopLockTaskMode.
- final int callingUid = Binder.getCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- try {
- String pkg =
- mStackSupervisor.mLockTaskModeTask.intent.getComponent().getPackageName();
- int uid = mContext.getPackageManager().getPackageUid(pkg,
- Binder.getCallingUserHandle().getIdentifier());
- if (uid != callingUid) {
- throw new SecurityException("Invalid uid, expected " + uid);
- }
- } catch (NameNotFoundException e) {
- Log.d(TAG, "stopLockTaskMode " + e);
- return;
- }
+ final TaskRecord lockTask = mStackSupervisor.getLockedTaskLocked();
+ if (lockTask == null) {
+ // Our work here is done.
+ return;
+ }
+ // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
+ if (getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED &&
+ Binder.getCallingUid() != lockTask.mLockTaskUid) {
+ throw new SecurityException("Invalid uid, expected " + lockTask.mLockTaskUid);
}
long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 2362d28..6210d60 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2875,7 +2875,7 @@
}
if (endTask) {
- mStackSupervisor.endLockTaskModeIfTaskEnding(task);
+ mStackSupervisor.removeLockedTaskLocked(task);
}
} else if (r.state != ActivityState.PAUSING) {
// If the activity is PAUSING, we will complete the finish once
@@ -3674,8 +3674,7 @@
}
Slog.i(TAG, "moveTaskToBack: " + tr);
-
- mStackSupervisor.endLockTaskModeIfTaskEnding(tr);
+ mStackSupervisor.removeLockedTaskLocked(tr);
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
@@ -4240,7 +4239,7 @@
*/
void removeTask(TaskRecord task, String reason, boolean notMoving) {
if (notMoving) {
- mStackSupervisor.endLockTaskModeIfTaskEnding(task);
+ mStackSupervisor.removeLockedTaskLocked(task);
mWindowManager.removeTask(task.taskId);
}
@@ -4345,4 +4344,10 @@
mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
return !mOverrideConfig.equals(oldConfig);
}
+
+ void onLockTaskPackagesUpdatedLocked() {
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ mTaskHistory.get(taskNdx).setLockTaskAuth();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c2f6bfd..6908483 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,10 +17,14 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
@@ -28,6 +32,10 @@
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStack.ActivityState.*;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import android.app.Activity;
import android.app.ActivityManager;
@@ -261,17 +269,17 @@
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+ private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();
/** Mapping from displayId to display current state */
- private final SparseArray<ActivityDisplay> mActivityDisplays =
- new SparseArray<ActivityDisplay>();
+ private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
InputManagerInternal mInputManagerInternal;
- /** If non-null then the task specified remains in front and no other tasks may be started
- * until the task exits or #stopLockTaskMode() is called. */
- TaskRecord mLockTaskModeTask;
+ /** The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks
+ * may be finished until there is only one entry left. If this is empty the system is not
+ * in lockTask mode. */
+ ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
/** Store the current lock task mode. Possible values:
* {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
* {@link ActivityManager#LOCK_TASK_MODE_PINNED}
@@ -282,8 +290,7 @@
*/
private LockTaskNotify mLockTaskNotify;
- final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
- = new ArrayList<PendingActivityLaunch>();
+ final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
/** Used to keep resumeTopActivityLocked() from being entered recursively */
boolean inResumeTopActivity;
@@ -796,7 +803,7 @@
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
+ ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>();
runningTaskLists.add(stackTaskList);
stack.getTasksLocked(stackTaskList, callingUid, allowed);
}
@@ -894,8 +901,8 @@
intent = new Intent(intent);
// Collect information about the target of the Intent.
- ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
- profilerInfo, userId);
+ ActivityInfo aInfo =
+ resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
ActivityContainer container = (ActivityContainer)iContainer;
synchronized (mService) {
@@ -1170,7 +1177,12 @@
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
- final ActivityStack stack = r.task.stack;
+ final TaskRecord task = r.task;
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
+ setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "lockTaskLaunchMode attribute");
+ }
+
+ final ActivityStack stack = task.stack;
try {
if (app.thread == null) {
throw new RemoteException();
@@ -1187,11 +1199,11 @@
if (andResume) {
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
r.userId, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
+ task.taskId, r.shortComponentName);
}
if (r.isHomeActivity() && r.isNotResolverActivity()) {
// Home process is the root process of the task.
- mService.mHomeProcess = r.task.mActivities.get(0).app;
+ mService.mHomeProcess = task.mActivities.get(0).app;
}
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
r.sleeping = false;
@@ -1233,7 +1245,7 @@
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
- r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
+ task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
@@ -1946,7 +1958,7 @@
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
}
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+ if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and
// the client said not to do anything if that
// is the case, so this is it! And for paranoia, make
@@ -1964,8 +1976,7 @@
}
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
- if ((launchFlags &
- (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any
// existing task with its new activity. Well that should
@@ -2128,10 +2139,6 @@
// Should this be considered a new task?
if (r.resultTo == null && inTask == null && !addingToTask
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- if (isLockTaskModeViolation(reuseTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
newTask = true;
targetStack = computeStackFocus(r, newTask);
targetStack.moveToFront("startingNewTask");
@@ -2147,6 +2154,10 @@
} else {
r.setTask(reuseTask, taskToAffiliate);
}
+ if (isLockTaskModeViolation(r.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
+ return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
if (!movedHome) {
if ((launchFlags &
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
@@ -3292,6 +3303,7 @@
pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId);
pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers);
+ pw.print(prefix); pw.println("mLockTaskModeTasks" + mLockTaskModeTasks);
}
ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -3592,6 +3604,32 @@
return list;
}
+ TaskRecord getLockedTaskLocked() {
+ final int top = mLockTaskModeTasks.size() - 1;
+ if (top >= 0) {
+ return mLockTaskModeTasks.get(top);
+ }
+ return null;
+ }
+
+ boolean isLockedTask(TaskRecord task) {
+ return mLockTaskModeTasks.contains(task);
+ }
+
+ boolean isLastLockedTask(TaskRecord task) {
+ return mLockTaskModeTasks.size() == 1 && mLockTaskModeTasks.contains(task);
+ }
+
+ void removeLockedTaskLocked(final TaskRecord task) {
+ if (mLockTaskModeTasks.remove(task) && mLockTaskModeTasks.isEmpty()) {
+ // Last one.
+ final Message lockTaskMsg = Message.obtain();
+ lockTaskMsg.arg1 = task.userId;
+ lockTaskMsg.what = LOCK_TASK_END_MSG;
+ mHandler.sendMessage(lockTaskMsg);
+ }
+ }
+
void showLockTaskToast() {
mLockTaskNotify.showToast(mLockTaskModeState);
}
@@ -3599,42 +3637,93 @@
void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
if (task == null) {
// Take out of lock task mode if necessary
- if (mLockTaskModeTask != null) {
- final Message lockTaskMsg = Message.obtain();
- lockTaskMsg.arg1 = mLockTaskModeTask.userId;
- lockTaskMsg.what = LOCK_TASK_END_MSG;
- mLockTaskModeTask = null;
- mHandler.sendMessage(lockTaskMsg);
+ final TaskRecord lockedTask = getLockedTaskLocked();
+ if (lockedTask != null) {
+ removeLockedTaskLocked(lockedTask);
+ if (!mLockTaskModeTasks.isEmpty()) {
+ // There are locked tasks remaining, can only finish this task, not unlock it.
+ lockedTask.performClearTaskLocked();
+ resumeTopActivitiesLocked();
+ return;
+ }
}
return;
}
- if (isLockTaskModeViolation(task)) {
- Slog.e(TAG, "setLockTaskMode: Attempt to start a second Lock Task Mode task.");
+
+ // Should have already been checked, but do it again.
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
}
- mLockTaskModeTask = task;
+ if (isLockTaskModeViolation(task)) {
+ Slog.e(TAG, "setLockTaskMode: Attempt to start an unauthorized lock task.");
+ return;
+ }
+
+ if (mLockTaskModeTasks.isEmpty()) {
+ // First locktask.
+ final Message lockTaskMsg = Message.obtain();
+ lockTaskMsg.obj = task.intent.getComponent().getPackageName();
+ lockTaskMsg.arg1 = task.userId;
+ lockTaskMsg.what = LOCK_TASK_START_MSG;
+ lockTaskMsg.arg2 = lockTaskModeState;
+ mHandler.sendMessage(lockTaskMsg);
+ }
+ // Add it or move it to the top.
+ mLockTaskModeTasks.remove(task);
+ mLockTaskModeTasks.add(task);
+
+ if (task.mLockTaskUid == -1) {
+ task.mLockTaskUid = task.mCallingUid;
+ }
findTaskToMoveToFrontLocked(task, 0, null, reason);
resumeTopActivitiesLocked();
-
- final Message lockTaskMsg = Message.obtain();
- lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
- lockTaskMsg.arg1 = mLockTaskModeTask.userId;
- lockTaskMsg.what = LOCK_TASK_START_MSG;
- lockTaskMsg.arg2 = lockTaskModeState;
- mHandler.sendMessage(lockTaskMsg);
}
boolean isLockTaskModeViolation(TaskRecord task) {
- return mLockTaskModeTask != null && mLockTaskModeTask != task;
+ if (getLockedTaskLocked() == task) {
+ return false;
+ }
+ final int lockTaskAuth = task.mLockTaskAuth;
+ switch (lockTaskAuth) {
+ case LOCK_TASK_AUTH_DONT_LOCK:
+ return !mLockTaskModeTasks.isEmpty();
+ case LOCK_TASK_AUTH_LAUNCHABLE:
+ case LOCK_TASK_AUTH_WHITELISTED:
+ return false;
+ case LOCK_TASK_AUTH_PINNABLE:
+ // Pinnable tasks can't be launched on top of locktask tasks.
+ return !mLockTaskModeTasks.isEmpty();
+ default:
+ Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth);
+ return true;
+ }
}
- void endLockTaskModeIfTaskEnding(TaskRecord task) {
- if (mLockTaskModeTask != null && mLockTaskModeTask == task) {
- final Message lockTaskMsg = Message.obtain();
- lockTaskMsg.arg1 = mLockTaskModeTask.userId;
- lockTaskMsg.what = LOCK_TASK_END_MSG;
- mLockTaskModeTask = null;
- mHandler.sendMessage(lockTaskMsg);
+ void onLockTaskPackagesUpdatedLocked() {
+ boolean didSomething = false;
+ for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
+ if (lockedTask.mLockTaskMode != LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED) {
+ continue;
+ }
+ final boolean wasLaunchable = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE;
+ lockedTask.setLockTaskAuth();
+ if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) {
+ // Lost whitelisting authorization. End it now.
+ removeLockedTaskLocked(lockedTask);
+ lockedTask.performClearTaskLocked();
+ didSomething = true;
+ }
+ }
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = stacks.get(stackNdx);
+ stack.onLockTaskPackagesUpdatedLocked();
+ }
+ }
+ if (didSomething) {
+ resumeTopActivitiesLocked();
}
}
@@ -3734,11 +3823,10 @@
mLockTaskModeState = msg.arg2;
if (getStatusBarService() != null) {
int flags = 0;
- if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
flags = StatusBarManager.DISABLE_MASK
& (~StatusBarManager.DISABLE_BACK);
- } else if (mLockTaskModeState ==
- ActivityManager.LOCK_TASK_MODE_PINNED) {
+ } else if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
flags = StatusBarManager.DISABLE_MASK
& (~StatusBarManager.DISABLE_BACK)
& (~StatusBarManager.DISABLE_HOME)
@@ -3776,8 +3864,7 @@
boolean shouldLockKeyguard = Settings.Secure.getInt(
mService.mContext.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
- if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
- shouldLockKeyguard) {
+ if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
mWindowManager.lockNow(null);
mWindowManager.dismissKeyguard();
new LockPatternUtils(mService.mContext)
@@ -3789,7 +3876,7 @@
} catch (RemoteException ex) {
throw new RuntimeException(ex);
} finally {
- mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
+ mLockTaskModeState = LOCK_TASK_MODE_NONE;
}
} break;
case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 82e6d47..790a78d 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -18,6 +18,10 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -121,6 +125,20 @@
boolean mResizeable; // Activities in the task resizeable. Based on the resizable setting of
// the root activity.
+ int mLockTaskMode; // Which tasklock mode to launch this task in. One of
+ // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
+ /** Can't be put in lockTask mode. */
+ final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
+ /** Can enter lockTask with user approval if not already in lockTask. */
+ final static int LOCK_TASK_AUTH_PINNABLE = 1;
+ /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
+ final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
+ /** Enters LOCK_TASK_MODE_LOCKED via startLockTask(), enters LOCK_TASK_MODE_PINNED from
+ * Overview. Can start over existing lockTask task. */
+ final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+
+ int mLockTaskUid = -1; // The uid of the application that called startLockTask().
// This represents the last resolved activity values for this task
// NOTE: This value needs to be persisted with each task
@@ -186,6 +204,8 @@
voiceInteractor = _voiceInteractor;
isAvailable = true;
mActivities = new ArrayList<>();
+ mCallingUid = info.applicationInfo.uid;
+ mCallingPackage = info.packageName;
setIntent(_intent, info);
}
@@ -201,12 +221,12 @@
voiceInteractor = null;
isAvailable = true;
mActivities = new ArrayList<>();
+ mCallingUid = info.applicationInfo.uid;
+ mCallingPackage = info.packageName;
setIntent(_intent, info);
taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
isPersistable = true;
- mCallingUid = info.applicationInfo.uid;
- mCallingPackage = info.packageName;
// Clamp to [1, max].
maxRecents = Math.min(Math.max(info.maxRecents, 1),
ActivityManager.getMaxAppRecentsLimitStatic());
@@ -215,8 +235,6 @@
mTaskToReturnTo = HOME_ACTIVITY_TYPE;
userId = UserHandle.getUserId(info.applicationInfo.uid);
lastTaskDescription = _taskDescription;
- mCallingUid = info.applicationInfo.uid;
- mCallingPackage = info.packageName;
}
private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
@@ -278,9 +296,9 @@
/** Sets the original intent, and the calling uid and package. */
void setIntent(ActivityRecord r) {
- setIntent(r.intent, r.info);
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
+ setIntent(r.intent, r.info);
}
/** Sets the original intent, _without_ updating the calling uid or package. */
@@ -362,6 +380,8 @@
autoRemoveRecents = false;
}
mResizeable = info.resizeable;
+ mLockTaskMode = info.lockTaskLaunchMode;
+ setLockTaskAuth();
}
void setTaskToReturnTo(int taskToReturnTo) {
@@ -716,6 +736,53 @@
performClearTaskAtIndexLocked(0);
}
+ private boolean isPrivileged() {
+ final ProcessRecord proc = mService.mProcessNames.get(mCallingPackage, mCallingUid);
+ if (proc != null) {
+ return (proc.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ }
+ return false;
+ }
+
+ void setLockTaskAuth() {
+ switch (mLockTaskMode) {
+ case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+ mLockTaskAuth = isLockTaskWhitelistedLocked() ?
+ LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_NEVER:
+ mLockTaskAuth = isPrivileged() ?
+ LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+ mLockTaskAuth = isPrivileged() ?
+ LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
+ mLockTaskAuth = isLockTaskWhitelistedLocked() ?
+ LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+ break;
+ }
+ }
+
+ boolean isLockTaskWhitelistedLocked() {
+ if (mCallingPackage == null) {
+ return false;
+ }
+ String[] packages = mService.mLockTaskPackages.get(userId);
+ if (packages == null) {
+ return false;
+ }
+ for (int i = packages.length - 1; i >= 0; --i) {
+ if (mCallingPackage.equals(packages[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
boolean isHomeTask() {
return taskType == HOME_ACTIVITY_TYPE;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 452b3eb..e22a2cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1638,10 +1638,13 @@
private void updateLockTaskPackagesLocked(DevicePolicyData policy, int userId) {
IActivityManager am = ActivityManagerNative.getDefault();
+ long ident = Binder.clearCallingIdentity();
try {
am.updateLockTaskPackages(userId, policy.mLockTaskPackages.toArray(new String[0]));
} catch (RemoteException e) {
// Not gonna happen.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}