diff options
| author | 2019-04-25 16:08:30 +0100 | |
|---|---|---|
| committer | 2019-05-02 18:18:55 +0000 | |
| commit | b147fa12637af828dbcca1976e99f246f95c79d8 (patch) | |
| tree | feca01239d8a82053fe7beb9a20432aace5dd6fd | |
| parent | ec4c269f94c8278ddb1c5a48f62525a460bd038a (diff) | |
Restrict background activity start by task
We now also allow apps to start activity in its own background task, while
that task won't move to front.
Background activity is not allowed to be started in new task or app
is not in that task stack.
Also, task moving / reparent task is not allowed.
Bug: 128772406
Test: atest android.server.wm.BackgroundActivityLaunchTest
Change-Id: I20f501e755f30f9ef581f7f8c39a2875f959e5b8
| -rw-r--r-- | services/core/java/com/android/server/wm/ActivityStarter.java | 102 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/TaskRecord.java | 13 |
2 files changed, 96 insertions, 19 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 4ef8753bd131..fe937c28aa46 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -160,6 +160,10 @@ class ActivityStarter { private int mCallingUid; private ActivityOptions mOptions; + // If it is true, background activity can only be started in an existing task that contains + // an activity with same uid. + private boolean mRestrictedBgActivity; + private int mLaunchMode; private boolean mLaunchTaskBehind; private int mLaunchFlags; @@ -455,6 +459,7 @@ class ActivityStarter { mIntent = starter.mIntent; mCallingUid = starter.mCallingUid; mOptions = starter.mOptions; + mRestrictedBgActivity = starter.mRestrictedBgActivity; mLaunchTaskBehind = starter.mLaunchTaskBehind; mLaunchFlags = starter.mLaunchFlags; @@ -551,7 +556,8 @@ class ActivityStarter { mLastStartActivityTimeMs = System.currentTimeMillis(); mLastStartActivityRecord[0] = r; mLastStartActivityResult = startActivity(r, sourceRecord, voiceSession, voiceInteractor, - startFlags, doResume, options, inTask, mLastStartActivityRecord); + startFlags, doResume, options, inTask, mLastStartActivityRecord, + false /* restrictedBgActivity */); mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult, mLastStartActivityRecord[0]); return mLastStartActivityResult; @@ -760,22 +766,17 @@ class ActivityStarter { abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); - boolean abortBackgroundStart = false; + boolean restrictedBgActivity = false; if (!abort) { try { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "shouldAbortBackgroundActivityStart"); - abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, + restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, originatingPendingIntent, allowBackgroundActivityStart, intent); } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } - abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled()); - // TODO: remove this toast after feature development is done - if (abortBackgroundStart) { - showBackgroundActivityBlockedToast(abort, callingPackage); - } } // Merge the two options bundles, while realCallerOptions takes precedence. @@ -918,8 +919,10 @@ class ActivityStarter { || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) { if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid, "Activity start")) { - mController.addPendingActivityLaunch(new PendingActivityLaunch(r, - sourceRecord, startFlags, stack, callerApp)); + if (!restrictedBgActivity) { + mController.addPendingActivityLaunch(new PendingActivityLaunch(r, + sourceRecord, startFlags, stack, callerApp)); + } ActivityOptions.abort(checkedOptions); return ActivityManager.START_SWITCHES_CANCELED; } @@ -929,7 +932,7 @@ class ActivityStarter { mController.doPendingActivityLaunches(false); final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, - true /* doResume */, checkedOptions, inTask, outActivity); + true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity); mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]); return res; } @@ -1395,13 +1398,13 @@ class ActivityStarter { private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, - ActivityRecord[] outActivity) { + ActivityRecord[] outActivity, boolean restrictedBgActivity) { int result = START_CANCELED; final ActivityStack startedActivityStack; try { mService.mWindowManager.deferSurfaceLayout(); result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, - startFlags, doResume, options, inTask, outActivity); + startFlags, doResume, options, inTask, outActivity, restrictedBgActivity); } finally { final ActivityStack currentStack = r.getActivityStack(); startedActivityStack = currentStack != null ? currentStack : mTargetStack; @@ -1437,14 +1440,40 @@ class ActivityStarter { return result; } + /** + * Return true if background activity is really aborted. + * + * TODO(b/131748165): Refactor the logic so we don't need to call this method everywhere. + */ + private boolean handleBackgroundActivityAbort(ActivityRecord r) { + // TODO(b/131747138): Remove toast and refactor related code in Q release. + boolean abort = !mService.isBackgroundActivityStartsEnabled(); + showBackgroundActivityBlockedToast(abort, r.launchedFromPackage); + if (!abort) { + return false; + } + ActivityRecord resultRecord = r.resultTo; + String resultWho = r.resultWho; + int requestCode = r.requestCode; + if (resultRecord != null) { + ActivityStack resultStack = resultRecord.getActivityStack(); + resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, + RESULT_CANCELED, null); + } + // We pretend to the caller that it was really started to make it backward compatible, but + // they will just get a cancel result. + ActivityOptions.abort(r.pendingOptions); + return true; + } + // Note: This method should only be called from {@link startActivity}. private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, - ActivityRecord[] outActivity) { - + ActivityRecord[] outActivity, boolean restrictedBgActivity) { setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, - voiceInteractor); + voiceInteractor, restrictedBgActivity); + final int preferredWindowingMode = mLaunchParams.mWindowingMode; computeLaunchingTaskFlags(); @@ -1652,7 +1681,7 @@ class ActivityStarter { } else { // This not being started from an existing activity, and not part of a new task... // just put it in the top task, though these days this case should never happen. - setTaskToCurrentTopOrCreateNewTask(); + result = setTaskToCurrentTopOrCreateNewTask(); } if (result != START_SUCCESS) { return result; @@ -1725,6 +1754,7 @@ class ActivityStarter { mIntent = null; mCallingUid = -1; mOptions = null; + mRestrictedBgActivity = false; mLaunchTaskBehind = false; mLaunchFlags = 0; @@ -1764,7 +1794,8 @@ class ActivityStarter { private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask, boolean doResume, int startFlags, ActivityRecord sourceRecord, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) { + IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, + boolean restrictedBgActivity) { reset(false /* clearRequest */); mStartActivity = r; @@ -1774,6 +1805,7 @@ class ActivityStarter { mSourceRecord = sourceRecord; mVoiceSession = voiceSession; mVoiceInteractor = voiceInteractor; + mRestrictedBgActivity = restrictedBgActivity; mLaunchParams.reset(); @@ -1874,6 +1906,11 @@ class ActivityStarter { } mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; + + if (restrictedBgActivity) { + mAvoidMoveToFront = true; + mDoResume = false; + } } private void sendNewTaskResultRequestIfNeeded() { @@ -2271,6 +2308,9 @@ class ActivityStarter { // isLockTaskModeViolation fails below. if (mReuseTask == null) { + if (mRestrictedBgActivity && handleBackgroundActivityAbort(mStartActivity)) { + return START_ABORTED; + } final TaskRecord task = mTargetStack.createTaskRecord( mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId), mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info, @@ -2283,6 +2323,11 @@ class ActivityStarter { if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity + " in new task " + mStartActivity.getTaskRecord()); } else { + if (mRestrictedBgActivity && !mReuseTask.containsAppUid(mCallingUid)) { + if (handleBackgroundActivityAbort(mStartActivity)) { + return START_ABORTED; + } + } addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask"); } @@ -2322,6 +2367,12 @@ class ActivityStarter { final TaskRecord sourceTask = mSourceRecord.getTaskRecord(); final ActivityStack sourceStack = mSourceRecord.getActivityStack(); + if (mRestrictedBgActivity && !sourceTask.containsAppUid(mCallingUid)) { + if (handleBackgroundActivityAbort(mStartActivity)) { + return START_ABORTED; + } + return START_ABORTED; + } // We only want to allow changing stack in two cases: // 1. If the target task is not the top one. Otherwise we would move the launching task to // the other side, rather than show two side by side. @@ -2483,20 +2534,33 @@ class ActivityStarter { } } - private void setTaskToCurrentTopOrCreateNewTask() { + private int setTaskToCurrentTopOrCreateNewTask() { mTargetStack = computeStackFocus(mStartActivity, false, mLaunchFlags, mOptions); if (mDoResume) { mTargetStack.moveToFront("addingToTopTask"); } final ActivityRecord prev = mTargetStack.getTopActivity(); + if (mRestrictedBgActivity && prev == null) { + if (handleBackgroundActivityAbort(mStartActivity)) { + return START_ABORTED; + } + return START_ABORTED; + } final TaskRecord task = (prev != null) ? prev.getTaskRecord() : mTargetStack.createTaskRecord( mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId), mStartActivity.info, mIntent, null, null, true, mStartActivity, mSourceRecord, mOptions); + if (mRestrictedBgActivity && !task.containsAppUid(mCallingUid)) { + if (handleBackgroundActivityAbort(mStartActivity)) { + return START_ABORTED; + } + return START_ABORTED; + } addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask"); mTargetStack.positionChildWindowContainerAtTop(task); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.getTaskRecord()); + return START_SUCCESS; } private void addOrReparentStartingActivity(TaskRecord parent, String reason) { diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 15060e1fc712..c26e3fd41247 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -1161,6 +1161,19 @@ class TaskRecord extends ConfigurationContainer { return false; } + /** + * Return true if any activities in this task belongs to input uid. + */ + boolean containsAppUid(int uid) { + for (int i = mActivities.size() - 1; i >= 0; --i) { + final ActivityRecord r = mActivities.get(i); + if (r.getUid() == uid) { + return true; + } + } + return false; + } + void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) { if (mStack != null) { for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { |