---
title: 'Activity 啟動 - 番外'
disqus: kyleAlien
---
Activity 啟動 - Task
===
## OverView of Content
[TOC]
## [ActivityStarter](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityStarter.java#2411) - 分析 FLAG
* 分析 FLAG:我們在啟動 Activity 時,可以對攜帶需多我們需要的 FLAG,而這些 FLAG 也會在 ActivityStarter#startActivityInner 被分析
1. 取得可以重用的 Task
2. 決定目標 Task
3. 判斷 targetTaskTop
4. 若有責使用並回收該 Task
```java=
// ActivityStarter.java
private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
...省略部分
// 1. 取得可重用的 Task
final Task reusedTask = getReusableTask();
// 2. 決定目標 Task
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
// 3. 若沒有找到 Task 則需重新創建 Task
final boolean newTask = targetTask == null;
mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
// Check if starting activity on given task or on a new task is allowed.
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
// 4. 重複使用 Task
// Recycle the target task for this launch.
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
} else {
mAddingToTask = true;
}
// 檢查 ActivityRecord 中的 flag 來判斷是否可以正常啟動 Activity
int startResult = isAllowedToStart(r, newTask, targetTask);
if (startResult != START_SUCCESS) {
return startResult;
}
...省略部分
return START_SUCCESS;
}
```
> 
### 復用 Task - getReusableTask
* **ActivityStarter#getReusableTask 這個函數主要是在判斷該 Activity 的啟動方式,並且 ++最終返回目標 Task++**,如果是 LAUNCH_SINGLE_INSTANCE、LAUNCH_SINGLE_TASK 的話,則透過 [**RootWindowContainer**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/RootWindowContainer.java)#==findActivity== 找到指定的 Task,如果找不到則返回 null
```java=
// ActivityStarter.java
private ActivityOptions mOptions;
private final RootWindowContainer mRootWindowContainer;
// 符合其中一個就 OK
private boolean isLaunchModeOneOf(int mode1, int mode2) {
return mode1 == mLaunchMode || mode2 == mLaunchMode;
}
private Task getReusableTask() {
// 檢查 ActivityOptions
if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
if (launchTask != null) {
return launchTask;
}
return null;
}
// 判斷是否放到已存在的 ActivityStack 中
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
// 一個 Stack 中只能有一個 Task
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
// 在這邊主要是靠 RootWindowContainer#findActivity 找到指定的 ActivityRecord
ActivityRecord intentActivity = null;
if (putIntoExistingTask) {
if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
// 使用 findActivity 找尋指定 Activity
intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
mStartActivity.isActivityTypeHome());
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
!(LAUNCH_SINGLE_TASK == mLaunchMode));
} else {
intentActivity =
mRootWindowContainer.findTask(mStartActivity, mPreferredTaskDisplayArea);
}
}
if (intentActivity != null
&& (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
&& intentActivity.getDisplayArea() != mPreferredTaskDisplayArea) {
// Do not reuse home activity on other display areas.
intentActivity = null;
}
// 取得該 ActivityRecord 的 Task (也就是 ActivityStack)
return intentActivity != null ? intentActivity.getTask() : null;
}
```
> 
* 來查看一下 RootWindowContainer#**findActivity** 函數
```java=
// RootWindowContainer.java
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
ActivityRecord findActivity(Intent intent, ActivityInfo info, boolean compareIntentFilters) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
final PooledPredicate p = PooledLambda.obtainPredicate(
RootWindowContainer::matchesActivity, PooledLambda.__(ActivityRecord.class),
userId, compareIntentFilters, intent, cls);
// 在 WindowContainer#getActivity 找到對應的 ActivityRecord
final ActivityRecord r = getActivity(p);
// 回收 ActivityRecord 物件
p.recycle();
return r;
}
}
```
:::info
* **管理 Task 窗口 WindowContainer**
WindowContainer 裡面有個 List 是 **==儲存當前螢幕的畫==,以 Z 軸儲存,最頂層的窗口在 List 的尾端**
```java=
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
BLASTSyncEngine.TransactionReadyListener {
... 省略部分
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList<E> mChildren = new WindowList<E>();
}
```
:::
### 判斷目標 Task - computeTargetTask
* 若上一個步驟 (**getReusableTask 函數**) 找不到重用的 Task,則用 ActivityStarter#[**computeTargetTask**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityStarter.java#1747) 函數,從目標來源、Launch Stack 取得 Task
```java=
// ActivityStarter.java
private Task computeTargetTask() {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// A new task should be created instead of using existing one.
return null;
} else if (mSourceRecord != null) {
return mSourceRecord.getTask();
} else if (mInTask != null) {
return mInTask;
} else {
final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags,
null /* task */, mOptions);
final ActivityRecord top = stack.getTopNonFinishingActivity();
if (top != null) {
return top.getTask();
} else {
// Remove the stack if no activity in the stack.
stack.removeIfPossible();
}
}
return null;
}
```
> 
### 回收 Task - [recycleTask](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityStarter.java#1851)
* 這裡的 Task 其實就是 ActivityStack,依樣是判斷傳入的 Flag 並對該 Stack 進行操控
```java=
// ActivityStarter.java
int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,
NeededUriGrants intentGrants) {
// 1. 若調用者 ID 不同則直接添加
if (targetTask.mUserId != mStartActivity.mUserId) {
mTargetStack = targetTask.getStack();
mAddingToTask = true;
return START_SUCCESS;
}
boolean clearTaskForReuse = false;
if (reusedTask != null) {
if (mStartActivity.getTask() == null) {
mStartActivity.setTaskForReuse(reusedTask);
clearTaskForReuse = true;
}
if (targetTask.intent == null) {
// This task was started because of movement of the activity based on
// affinity...
// Now that we are actually launching it, we can assign the base intent.
targetTask.setIntent(mStartActivity);
} else {
final boolean taskOnHome =
(mStartActivity.intent.getFlags() & FLAG_ACTIVITY_TASK_ON_HOME) != 0;
if (taskOnHome) {
targetTask.intent.addFlags(FLAG_ACTIVITY_TASK_ON_HOME);
} else {
targetTask.intent.removeFlags(FLAG_ACTIVITY_TASK_ON_HOME);
}
}
}
... 省略部分
// 切換紀錄的 mLastStartActivityRecord
if (mLastStartActivityRecord != null
&& (mLastStartActivityRecord.finishing || mLastStartActivityRecord.noDisplay)) {
mLastStartActivityRecord = targetTaskTop;
}
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// onResume Stack 頂部的 Activity
if (!mMovedToFront && mDoResume) {
... 省略 Debug 訊息
mTargetStack.moveToFront("intentActivityFound");
}
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
// 下面會分析 complyActivityFlags 函數
complyActivityFlags(targetTask,
reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);
if (clearTaskForReuse) {
// Clear task for re-use so later code to methods
// {@link #setTaskFromReuseOrCreateNewTask}, {@link #setTaskFromSourceRecord}, or
// {@link #setTaskFromInTask} can parent it to the task.
mStartActivity.setTaskForReuse(null);
}
if (mAddingToTask) {
return START_SUCCESS;
}
... 省略部分
mLastStartActivityRecord =
targetTaskTop.finishing ? targetTask.getTopNonFinishingActivity() : targetTaskTop;
return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}
```
* complyActivityFlags 會對針對 Flag 設定對 Stack 進行操作
| 常見 FLAG | 功能 |
| -------- | -------- |
| FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | reset Stack (清理棧) |
| FLAG_ACTIVITY_NEW_TASK | 創建新 Stack |
| FLAG_ACTIVITY_CLEAR_TASK | 清理 Stack |
| FLAG_ACTIVITY_CLEAR_TOP | 大部分是代表回到 Stack 的初始狀態(清除到活動中的 Activity 為止) |
| FLAG_ACTIVITY_REORDER_TO_FRONT | 將 Activity 拉到前台 |
```java=
// ActivityStarter.java
private void complyActivityFlags(Task targetTask, ActivityRecord reusedActivity,
NeededUriGrants intentGrants) {
// 目標最上層 Task
ActivityRecord targetTaskTop = targetTask.getTopNonFinishingActivity();
// 1. 判斷 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
final boolean resetTask =
reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0;
if (resetTask) {
targetTaskTop = mTargetStack.resetTaskIfNeeded(targetTaskTop, mStartActivity);
}
// 啟動新 Stack
// FLAG_ACTIVITY_NEW_TASK & FLAG_ACTIVITY_CLEAR_TASK 都是相同情況
if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// performClearTaskLocked 有兩個功能
// 1. 清除該 Stack
// 2. 啟用新 intent
targetTask.performClearTaskLocked();
targetTask.setIntent(mStartActivity);
mAddingToTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
// 在這種情況下,我們希望從任務中刪除所有活動,直到正在啟動的活動。
// 在大多數情況下,這意味著我們將任務重置為其初始狀態。
final ActivityRecord top = targetTask.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
if (top != null) {
if (top.isRootOfTask()) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
deliverNewIntent(top, intentGrants);
} else {
// A special case: we need to start the activity because it is not currently
// running, and the caller has asked to clear the current task to have this
// activity at the top.
mAddingToTask = true;
if (targetTask.getStack() == null) {
// Target stack got cleared when we all activities were removed above.
// Go ahead and reset it.
mTargetStack =
getLaunchStack(mStartActivity, mLaunchFlags, null /* task */, mOptions);
mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
(mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
}
}
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) == 0 && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
// 將已經啟動的 Activity 拉到前台
final ActivityRecord act =
targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
if (act != null) {
final Task task = act.getTask();
task.moveActivityToFrontLocked(act);
act.updateOptionsLocked(mOptions);
deliverNewIntent(act, intentGrants);
mTargetStack.mLastPausedActivity = null;
} else {
mAddingToTask = true;
}
} else if (mStartActivity.mActivityComponent.equals(targetTask.realActivity)) { // 判斷 Component
if (targetTask == mInTask) {
// In this case we are bringing up an existing activity from a recent task. We
// don't need to add a new activity instance on top.
} else if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| LAUNCH_SINGLE_TOP == mLaunchMode)
&& targetTaskTop.mActivityComponent.equals(mStartActivity.mActivityComponent)
&& mStartActivity.resultTo == null) {
// Top Activity 就是我們需要的 Activity,這時無須重新啟動,只需要帶入 intent 即可
if (targetTaskTop.isRootOfTask()) {
targetTaskTop.getTask().setIntent(mStartActivity);
}
deliverNewIntent(targetTaskTop, intentGrants);
} else if (!targetTask.isSameIntentFilter(mStartActivity)) {
// In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance on top.
mAddingToTask = true;
} else if (reusedActivity == null) {
mAddingToTask = true;
}
} else if (!resetTask) {
// In this case an activity is being launched in to an existing task, without
// resetting that task. This is typically the situation of launching an activity
// from a notification or shortcut. We want to place the new activity on top of the
// current task.
mAddingToTask = true;
} else if (!targetTask.rootWasReset) {
// In this case we are launching into an existing task that has not yet been started
// from its front door. The current task has been brought to the front. Ideally,
// we'd probably like to place this new task at the bottom of its stack, but that's
// a little hard to do with the current organization of the code so for now we'll
// just drop it.
targetTask.setIntent(mStartActivity);
}
}
```
### ActivityStarter - 判斷 Activity 是否可啟動
* ActivityStarter#`isAllowedToStart` 用於判斷目標 Activity 是否可以啟動
```java=
// ActivityStarter.java
private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
// packageName 不可為空
if (mStartActivity.packageName == null) {
if (mStartActivity.resultTo != null) {
mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho,
mStartActivity.requestCode, RESULT_CANCELED,
null /* data */, null /* dataGrants */);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// ++不能顯示 Home 類型的 Activity++
if (r.isActivityTypeHome()) {
if (!mRootWindowContainer.canStartHomeOnDisplayArea(r.info, mPreferredTaskDisplayArea,
true /* allowInstrumenting */)) {
Slog.w(TAG, "Cannot launch home on display area " + mPreferredTaskDisplayArea);
return START_CANCELED;
}
}
if (mRestrictedBgActivity && (newTask || !targetTask.isUidPresent(mCallingUid))
&& handleBackgroundActivityAbort(mStartActivity)) {
Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
return START_ABORTED;
}
// 當使用 FLAG_ACTIVITY_NEW_TASK & FLAG_ACTIVITY_CLEAR_TASK 時會
// 複用該 Stack,但仍須鎖定
final boolean isNewClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!newTask && mService.getLockTaskController().isLockTaskModeViolation(targetTask,
isNewClearTask)) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
return START_SUCCESS;
}
```
## Appendix & FAQ
:::info
:::
###### tags: `Android Framework`