本文基于 android-14.0.0_r15 版本讲解:
1. 整体流程
接上一节,我们接着看 startActivityUnchecked
方法的实现:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants, int realCallingUid) {
// ......
try {
mService.deferWindowLayout();
transitionController.collect(r);
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
// 关注点
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, options, inTask, inTaskFragment, balCode,
intentGrants, realCallingUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityRootTask = handleStartResult(r, options, result, newTransition,
remoteTransition);
}
} finally {
mService.continueWindowLayout();
}
postStartActivityProcessing(r, result, startedActivityRootTask);
return result;
}
接着调用到 startActivityInner 方法:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
* Start an activity and determine if the activity should be adding to the top of an existing
* task or delivered new intent to an existing activity. Also manipulating the activity task
* onto requested or valid root-task/display.
*
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/
// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
@VisibleForTesting
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants, int realCallingUid) {
// 初始化各类参数
setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
voiceSession, voiceInteractor, balCode, realCallingUid);
// 根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,
// 结果保存在 mLaunchFlags 中。计算的过程不仅要考虑目标 activity 的 launchMode,
// 也要考虑原来 activity 的 launchMode 和 Intent 中所带着的 flag
computeLaunchingTaskFlags();
mIntent.setFlags(mLaunchFlags); //270532608
boolean dreamStopping = false;
// ......
// launcher 中有两个 Task
// launcher 中的根 Task
final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
// launcher 中的叶子 Task
final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null;
// null,没有可以复用的 Task
final Task reusedTask = getReusableTask();
// ......
// null,computeTargetTask 查找是否已经存在目标 Task,当前场景下没有,返回 null
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
// true
final boolean newTask = targetTask == null;
mTargetTask = targetTask; // null
// 计算启动参数,结果保存在 mLaunchParams 中
computeLaunchParams(r, sourceRecord, targetTask);
// Check if starting activity on given task or on a new task is allowed.
int startResult = isAllowedToStart(r, newTask, targetTask); // 0
// ......
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity(); // null
if (targetTaskTop != null) { // 不进入
// ......
} else { //进入
mAddingToTask = true;
}
// 启动当前已经在栈顶的 Activity 情况的处理
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
if (topRootTask != null) { // 进入
startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants); // 0
if (startResult != START_SUCCESS) { //不进入
return startResult;
}
}
if (mTargetRootTask == null) { // 进入
// 关注点 1
// 创建一个 Task 对象,也就是目标 Task
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
mOptions);
}
if (newTask) { // 进入
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null; // null
// 关注点2
setNewTask(taskToAffiliate); // 把目标 ActivityRecord 插入新创建的 Task
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
if (!mAvoidMoveToFront && mDoResume) { // 进入
// 关注点 3
// 移动新创建的 Task 到 TaskDisplayArea 的子节点的栈顶
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
&& !dreamStopping) { // 不进入
// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
// -behind transition so the Activity gets created and starts in visible state.
mLaunchTaskBehind = true;
r.mLaunchTaskBehind = true;
}
}
// 给目标 Activity 添加 Uri 权限
mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
mStartActivity.getUriPermissionsLocked());
// ......\
final Task startedTask = mStartActivity.getTask();
if (newTask) {
EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId,
startedTask.getRootTaskId(), startedTask.getDisplayId());
}
mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
mStartActivity.getTaskFragment().clearLastPausedActivity();
// 电源管理,了解
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
final boolean isTaskSwitch = startedTask != prevTopTask;
// 关注点 4
// 调整目标 Task 相关参数,开启转场动画,为启动 Activity 做好准备
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
mOptions, sourceRecord);
if (mDoResume) { // 进入
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) { // 不进入
// ......
} else {
// ......
// 关注点 5
// 生命周期处理
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(startedTask);
mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);
// If Activity's launching into PiP, move the mStartActivity immediately to pinned mode.
// Note that mStartActivity and source should be in the same Task at this point.
if (mOptions != null && mOptions.isLaunchIntoPip()
&& sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()
&& balCode != BAL_BLOCK) {
mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity,
sourceRecord, "launch-into-pip");
}
return START_SUCCESS;
}
- setInitialState 方法用于初始化一堆参数
- computeLaunchingTaskFlags 方法,根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,结果保存在 mLaunchFlags 中。计算的过程不仅要考虑目标 activity 的 launchMode,也要考虑原来 activity 的 launchMode 和 Intent 中所带着的 flag
- getOrCreateRootTask 这个是我们的关注点 1,后面会详细分析其实现,用于创建一个 Task 对象,也就是目标 Task。
- setNewTask(taskToAffiliate) 是关注点 2,其主要作用是把目标 ActivityRecord 插入新创建的 Task
- 关注点 3
mTargetRootTask.getRootTask().moveToFront
移动新创建的 Task 到 TaskDisplayArea 的子节点的栈顶 - 调用 grantUriPermissionUncheckedFromIntent 给目标 Activity 添加 uri 权限
- 关注点 4
TargetRootTask.startActivityLocked
:调整目标 Task 内部参数,开启转场动画,为启动 Activity 做好准备 - 关注点 5
resumeFocusedTasksTopActivities
:生命周期处理
2. 核心要点分析
在了解了总体流程以后,接下来我们就来分析重要的几个关注点:
关注点 1,getOrCreateRootTask 方法创建一个目标 Task 对象:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private Task getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind; // true
final Task sourceTask = mSourceRecord != null ? mSourceRecord.getTask() : null; // QuickStepLauncher
return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,
mLaunchParams, launchFlags);
}
计算出两个参数后,接着调用 getOrCreateRootTask 方法:
java
// frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
// ......
TaskDisplayArea taskDisplayArea = null;
if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) { // 进入
taskDisplayArea = launchParams.mPreferredTaskDisplayArea; // 拿到 TaskDisplayArea 对象
} else if (options != null) { // 不进入
//......
}
final int activityType = resolveActivityType(r, options, candidateTask); // 1
if (taskDisplayArea != null) {
if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) { // 进入
// 直接返回了
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
} else {
taskDisplayArea = null;
}
}
// ......
}
接着调用 taskDisplayArea.getOrCreateRootTask 方法:
java
// frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java
Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) {
int windowingMode = WINDOWING_MODE_UNDEFINED;
if (launchParams != null) {
// If launchParams isn't null, windowing mode is already resolved.
windowingMode = launchParams.mWindowingMode;
} else if (options != null) {
// If launchParams is null and options isn't let's use the windowing mode in the
// options.
windowingMode = options.getLaunchWindowingMode();
}
// Validate that our desired windowingMode will work under the current conditions.
// UNDEFINED windowing mode is a valid result and means that the new root task will inherit
// it's display's windowing mode.
windowingMode = validateWindowingMode(windowingMode, r, candidateTask); // 0
return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask,
options, launchFlags);
}
计算出 windowmode,当前情景下是 0(WINDOWING_MODE_UNDEFINED),接着调用另一个重载 getOrCreateRootTask:
java
// frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
final int resolvedWindowingMode =
windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode; // 1
// .......
return new Task.Builder(mAtmService)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setOnTop(onTop)
.setParent(this)
.setSourceTask(sourceTask)
.setActivityOptions(options)
.setLaunchFlags(launchFlags)
.build();
}
最后,调用 Task.Builder 构建一个 Task 对象,需要注意的是,这里通过 setParent 将当前 TaskDisplayArea 对象设置为父节点。
目标 Task 就创建好了,并且插入了窗口容器树中,成为了 TaskDisplayArea 的子节点。
接着我们看关注点2 setNewTask(taskToAffiliate)
该方法的主要作用是把目标 ActivityRecord 插入新创建的 Task 中。
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private void setNewTask(Task taskToAffiliate) {
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
// reuseOrCreateTask 实际就是返回之前新创建的 Task 对象
final Task task = mTargetRootTask.reuseOrCreateTask(
mStartActivity.info, mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
task.mTransitionController.collectExistenceChange(task);
// addOrReparentStartingActivity 方法将目标 ActivityRecord 插入新创建的 Task 中
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask");
ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
mStartActivity, mStartActivity.getTask());
if (taskToAffiliate != null) {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
}
接着调用 addOrReparentStartingActivity 方法:
java
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task; // 刚刚新创建的 Task
if (mInTaskFragment != null) { // 不进入
// ......
} else {
TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null; // null
if (candidateTf == null) { // 进入
final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */); // null
if (top != null) {
candidateTf = top.getTaskFragment();
}
}
if (candidateTf != null && candidateTf.isEmbedded()
&& canEmbedActivity(candidateTf, mStartActivity, task) == EMBEDDING_ALLOWED) { // 不进入
// Use the embedded TaskFragment of the top activity as the new parent if the
// activity can be embedded.
newParent = candidateTf;
}
}
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
// 实际就是执行 TaskFragment 的 addChild,TaskFragment 就是刚刚创建的 Task
newParent.addChild(mStartActivity, POSITION_TOP);
} else {
mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason);
}
}
我们接着看 addChild:
java
// frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java
// child 就是之前创建的目标 ActivityRecord
// index:POSITION_TOP
@Override
void addChild(WindowContainer child, int index) {
ActivityRecord r = topRunningActivity(); //null
mClearedTaskForReuse = false;
mClearedTaskFragmentForPip = false;
mClearedForReorderActivityToFront = false;
final ActivityRecord addingActivity = child.asActivityRecord();
final boolean isAddingActivity = addingActivity != null;
final Task task = isAddingActivity ? getTask() : null;
// If this task had any activity before we added this one.
boolean taskHadActivity = task != null && task.getTopMostActivity() != null;
// getActivityType() looks at the top child, so we need to read the type before adding
// a new child in case the new child is on top and UNDEFINED.
final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
// 调用父类的 addChild
super.addChild(child, index);
if (isAddingActivity && task != null) {
// TODO(b/207481538): temporary per-activity screenshoting
if (r != null && BackNavigationController.isScreenshotEnabled()) {
ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
r.mActivityComponent.flattenToString());
Rect outBounds = r.getBounds();
ScreenCapture.ScreenshotHardwareBuffer backBuffer = ScreenCapture.captureLayers(
r.mSurfaceControl,
new Rect(0, 0, outBounds.width(), outBounds.height()),
1f);
mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
}
addingActivity.inHistory = true;
task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
}
final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(addingActivity);
if (hostProcess != null) {
hostProcess.addEmbeddedActivity(addingActivity);
}
}
接着调用父类的 addChild 方法:
java
// frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void addChild(E child, int index) {
if (!child.mReparenting && child.getParent() != null) { // 不进入
throw new IllegalArgumentException("addChild: container=" + child.getName()
+ " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName()
+ "\n callers=" + Debug.getCallers(15, "\n"));
}
if ((index < 0 && index != POSITION_BOTTOM)
|| (index > mChildren.size() && index != POSITION_TOP)) { // 不进入
throw new IllegalArgumentException("addChild: invalid position=" + index
+ ", children number=" + mChildren.size());
}
if (index == POSITION_TOP) {
index = mChildren.size();
} else if (index == POSITION_BOTTOM) {
index = 0;
}
mChildren.add(index, child); // 添加到 Task 的子节点
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
核心的流程就是将 ActivityRecord 添加到 Task 的子节点 mChildren 中。
关注点 3 mTargetRootTask.getRootTask().moveToFront
移动新创建的 Task 到 TaskDisplayArea 的子节点的栈顶
java
// frameworks/base/services/core/java/com/android/server/wm/Task.java
void moveToFront(String reason, Task task) {
if (!isAttached()) {
return;
}
mTransitionController.recordTaskOrder(this);
// 获取到 TaskDisplayArea 对象
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (!isActivityTypeHome() && returnsToHomeRootTask()) { // 不进入
// Make sure the root home task is behind this root task since that is where we
// should return to when this root task is no longer visible.
taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome");
}
// 就是新创建的 Task
final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null;
if (task == null) { // 进入,this 也是新创建的 Task
task = this;
}
// 将新创建的 Task 放到 TaskDisplayArea 的子节点的栈顶
task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
// 更新 mLastFocusedRootTask 的值
taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason);
}
关注点 4 TargetRootTask.startActivityLocked
:调整 Task 相关参数,开启转场动画,为启动 Activity 做好准备:
java
// frameworks/base/services/core/java/com/android/server/wm/Task.java
// r:目标 ActivityRecord 对象
void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,
boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {
// null
final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask);
// 新创建的 Task 对象
Task rTask = r.getTask();
// true
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
// false
final boolean isOrhasTask = rTask == this || hasChild(rTask);
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { // 进入
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
// 把 Task 放到父节点的栈顶,感觉这里有点重复了
positionChildAtTop(rTask);
}
Task task = null;
if (!newTask && isOrhasTask && !r.shouldBeVisible()) { // 不进入
ActivityOptions.abort(options);
return;
}
// Place a new activity at top of root task, so it is next to interact with the user.
// If we are not placing the new activity frontmost, we do not want to deliver the
// onUserLeaving callback to the actual frontmost activity
final Task activityTask = r.getTask();
// ......
task = activityTask;
// Slot the activity into the history root task and proceed
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
+ "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
// ......
final DisplayContent dc = mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { // 不进入
// ......
} else { // 进入
dc.prepareAppTransition(TRANSIT_OPEN); // 准备过渡动画
mTaskSupervisor.mNoAnimActivities.remove(r);
}
if (newTask && !r.mLaunchTaskBehind) { // 进入
// If a new task is being launched, then mark the existing top activity as
// supporting picture-in-picture while pausing only if the starting activity
// would not be considered an overlay on top of the current activity
// (eg. not fullscreen, or the assistant)
enableEnterPipOnTaskSwitch(pipCandidate,
null /* toFrontTask */, r, options); // 多窗口相关的设置
}
boolean doShow = true;
if (newTask) { // 进入
// Even though this activity is starting fresh, we still need
// to reset it to make sure we apply affinities to move any
// existing activities from other tasks in to it.
// If the caller has requested that the target task be
// reset, then do so.
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { // 进入
resetTaskIfNeeded(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r; // true
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
// ......
if (r.mLaunchTaskBehind) { // 不进入
// ......
} else if (SHOW_APP_STARTING_PREVIEW && doShow) { // 进入
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
Task baseTask = r.getTask();
final ActivityRecord prev = baseTask.getActivity(
a -> a.mStartingData != null && a.showToCurrentUser());
// 开启转场动画
mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,
isTaskSwitch, sourceRecord);
}
}
总结
代码非常繁琐,总结一下,核心的要点其实不多:
- 创建好目标 Task 对象
- 将 Task 对象放到正确的位置
- 开启转场动画
- Pause 前一个 Activity