--- 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; } ``` > ![](https://i.imgur.com/KaV7Pyv.png) ### 復用 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; } ``` > ![](https://i.imgur.com/Fa0XlHI.png) * 來查看一下 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; } ``` > ![](https://i.imgur.com/lJMruxo.png) ### 回收 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`