本文基于 android-10.0.0_r41 版本讲解
上节分析到 ATMS 中的启动过程会调用到一个很长的 startActivity 重载:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
// wms 推迟布局,或者说暂停布局,这里了解
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
} finally {
// 待会儿分析
// ......
}
postStartActivityProcessing(r, result, startedActivityStack);
return result;
}
- 调用
deferSurfaceLayout
方法推迟布局,内部只是简单给一个标记量加 1 - 接着调用 startActivityUnchecked 方法,finally 中的内容我们待会再来看
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, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
// 关注点1
// ActivityStarter 对象内部参数初始化
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
final int preferredWindowingMode = mLaunchParams.mWindowingMode;
// 关注点2
// 通过 launchmode 和 flag,计算目标 Activity 的启动方式
computeLaunchingTaskFlags();
// 关注点3
//确定发起端的 ActivityStack 情况,也就是 Launcher 所在的 ActivityStack
computeSourceStack();
// ......
关注点 1 的 setInitialState 方法对 ActivityStarter 对象中的内部参数做一个初始化操作:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean restrictedBgActivity) {
//将 ActivityStarter 对象的成员初始化
reset(false /* clearRequest */);
// 将目标 ActivityRecord 赋值给成员变量 mStartActivity
mStartActivity = r;
mIntent = r.intent;
mOptions = options;
mCallingUid = r.launchedFromUid;
mSourceRecord = sourceRecord; // 启动端的 ActivityRecord,这里就是 Launcher
mVoiceSession = voiceSession; // null
mVoiceInteractor = voiceInteractor; // null
mRestrictedBgActivity = restrictedBgActivity; //false
// mLaunchParams 的类型是 LaunchParams,用于保存启动相关的参数
// reset 方法初始化内部参数
mLaunchParams.reset();
/*
static class LaunchParams {
final Rect mBounds = new Rect();
int mPreferredDisplayId;
int mWindowingMode;
// ......
}
*/
// 计算 mLaunchParams 的值
// Preferred display id is the only state we need for now and it could be updated again
// after we located a reusable task (which might be resided in another display).
mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
mPreferredDisplayId =
mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
: DEFAULT_DISPLAY;
mLaunchMode = r.launchMode;
/*
FLAG_ACTIVITY_NEW_DOCUMENT flag 处理了解
*/
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());
// 是否为后台启动任务的标志位
mLaunchTaskBehind = r.mLaunchTaskBehind
&& !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
/*
newTask 的启动模式,是无法获取到请求结果的,该方法处理这种情况
*/
sendNewTaskResultRequestIfNeeded();
// 当前情景不进入
//如果设置了 NEW_DOCUMENT 标志同时此 Activity 不是其他 Activity 启动的
//则在加上 NEW_TASK 的标志
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
// If we are actually going to launch in to a new task, there are some cases where
// we further want to do multiple task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// 对于后台启动的新任务,可以多任务运行
if (mLaunchTaskBehind
|| r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) { // 不进入
mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
}
}
// mUserLeaving 是一个布尔变量用于标识是否离开上一个 Activity
// 这里计算出 mUserLeaving 值为 true
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
// the top running activity.
mDoResume = doResume; // true
if (!doResume || !r.okToShowLocked()) { // 不进入
r.delayedResume = true;
mDoResume = false;
}
if (mOptions != null) {
// 两个分支条件都不满足,都不进入
if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
r.mTaskOverlay = true;
if (!mOptions.canTaskOverlayResume()) {
final TaskRecord task = mRootActivityContainer.anyTaskForId(
mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
if (top != null && !top.isState(RESUMED)) {
// The caller specifies that we'd like to be avoided to be moved to the
// front, so be it!
mDoResume = false;
mAvoidMoveToFront = true;
}
}
} else if (mOptions.getAvoidMoveToFront()) {
mDoResume = false;
mAvoidMoveToFront = true;
}
}
/*
FLAG_ACTIVITY_PREVIOUS_IS_TOP flag 处理
了解即可
*/
// 当前场景下 mNotTop 为空
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
mInTask = inTask; // null
// In some flows in to this function, we retrieve the task record and hold on to it
// without a lock before calling back in to here... so the task at this point may
// not actually be in recents. Check for that, and if it isn't in recents just
// consider it invalid.
if (inTask != null && !inTask.inRecents) {
Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
mInTask = null;
}
mStartFlags = startFlags; // 0
// If the onlyIfNeeded flag is set, then we can do this if the activity being launched
// is the same as the one making the call... or, as a special case, if we do not know
// the caller then we count the current top activity as the caller.
if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { //不进入
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = mRootActivityContainer.getTopDisplayFocusedStack()
.topRunningNonDelayedActivityLocked(mNotTop);
}
if (!checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
// Caller is not the same as launcher, so always needed.
mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
}
}
//是否有动画
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; // false
if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) { // 不进入
mAvoidMoveToFront = true;
mDoResume = false;
}
}
setInitialState 主要对以下的变量做了初始化:
- mStartActivity:ActivityStarter 类的成员变量,待启动目标 Activity 对应的 ActivityRecord 对象
- mIntent:ActivityStarter 类的成员变量,用于启动目标 Activity
- mOptions:ActivityStarter 类的成员变量,启动目标 Activity 的额外参数
- mCallingUid:ActivityStarter 类的成员变量,启动方的 uid
- mSourceRecord:ActivityStarter 类的成员变量,启动端的 ActivityRecord
- mVoiceSession:ActivityStarter 类的成员变量,当前情景下为 null,不太清楚作用
- mVoiceInteractor:ActivityStarter 类的成员变量,当前情景下为 null,不太清楚作用
- mRestrictedBgActivity:ActivityStarter 类的成员变量,布尔变量,表示是否限制后台启动 Activity
- mLaunchParams:ActivityStarter 类的成员变量,用于保存启动相关的参数
java
static class LaunchParams {
final Rect mBounds = new Rect();
int mPreferredDisplayId;
int mWindowingMode;
// ......
}
- mPreferredDisplayId:ActivityStarter 类的成员变量,用于指示优先显示的屏幕
- mLaunchMode:ActivityStarter 类的成员变量,目标 Activity 的启动模式
- mLaunchFlags:ActivityStarter 类的成员变量,目标 Activity 的启动 flag
- mSupervisor.mUserLeaving: ActivityStackSupervisor 类的成员变量,是一个布尔变量用于标识是否离开上一个 Activity
- mDoResume:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 是否要执行 onResume 生命周期方法
- mNotTop:ActivityStarter 类的成员变量, FLAG_ACTIVITY_PREVIOUS_IS_TOP flag 相关的变量
- mInTask:ActivityStarter 类的成员变量,目标 Activity 所在的 TaskRecord
- mNoAnimation:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 启动是否无动画
- mAvoidMoveToFront:ActivityStarter 类的成员变量,布尔变量,用于表示目标 Activity 启动是否不移动到前台
关注点 2 ,computeLaunchingTaskFlags 方法根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,
结果保存在 mLaunchFlags 中。
计算的过程不仅要考虑目标 activity 的 launchMode,也要考虑原来 activity 的 launchMode 和Intent中所带着的flag
*/
private void computeLaunchingTaskFlags() {
// If the caller is not coming from another activity, but has given us an explicit task into
// which they would like us to launch the new activity, then let's see about doing that.
if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) {
final Intent baseIntent = mInTask.getBaseIntent();
final ActivityRecord root = mInTask.getRootActivity();
if (baseIntent == null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Launching into task without base intent: "
+ mInTask);
}
// If this task is empty, then we are adding the first activity -- it
// determines the root, and must be launching as a NEW_TASK.
if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+ mStartActivity + " into different task " + mInTask);
}
if (root != null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Caller with mInTask " + mInTask
+ " has root " + root + " but target is singleInstance/Task");
}
}
// If task is empty, then adopt the interesting intent launch flags in to the
// activity being started.
if (root == null) {
final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
| FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
| (baseIntent.getFlags() & flagsOfInterest);
mIntent.setFlags(mLaunchFlags);
mInTask.setIntent(mStartActivity);
mAddingToTask = true;
// If the task is not empty and the caller is asking to start it as the root of
// a new task, then we don't actually want to start this on the task. We will
// bring the task to the front, and possibly give it a new intent.
} else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
mAddingToTask = false;
} else {
mAddingToTask = true;
}
mReuseTask = mInTask;
} else {
mInTask = null;
// Launch ResolverActivity in the source task, so that it stays in the task bounds
// when in freeform workspace.
// Also put noDisplay activities in the source task. These by itself can be placed
// in any task/stack, however it could launch other activities like ResolverActivity,
// and we want those to stay in the original task.
if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
&& mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
mAddingToTask = true;
}
}
if (mInTask == null) {
if (mSourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
// The activity being started is a single instance... it always
// gets launched into its own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
根据 launchMode 和 Intent 中的 FLAG_ACTIVITY_NEW_TASK 等 flag 综合计算 activity 的启动模式,结果保存在 mLaunchFlags 中。计算的过程不仅要考虑目标 Activity 的 launchMode,也要考虑原来 Activity 的 launchMode 和 Intent 中所带着的 flag。
细节很多,目前关注主要流程,后面单独一节来讲。这里知道计算出的结果保存在 mLaunchFlags 即可。
我们接着看关注点 3 处的 computeSourceStack 方法:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
//确定发起端的 ActivityStack
private void computeSourceStack() {
if (mSourceRecord == null) {
mSourceStack = null;
return;
}
if (!mSourceRecord.finishing) { //直接返回
mSourceStack = mSourceRecord.getActivityStack();
return;
}
//如果调用方已经finish了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加FLAG_ACTIVITY_NEW_TASK标志使activity启动到一个新的task中
// If the source is finishing, we can't further count it as our source. This is because the
// task it is associated with may now be empty and on its way out, so we don't want to
// blindly throw it in to that task. Instead we will take the NEW_TASK flow and try to find
// a task for it. But save the task information so it can be used when creating the new task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
mNewTaskInfo = mSourceRecord.info;
// It is not guaranteed that the source record will have a task associated with it. For,
// example, if this method is being called for processing a pending activity launch, it
// is possible that the activity has been removed from the task after the launch was
// enqueued.
final TaskRecord sourceTask = mSourceRecord.getTaskRecord();
mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
}
mSourceRecord = null;
mSourceStack = null;
}
这里主要确定发起端的 ActivityStack 对象。一般情况下,直接通过启动端的 mSourceRecord 的 getActivityStack 获取到。如果调用方已经 finish 了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加 FLAG_ACTIVITY_NEW_TASK 标志使 activity 启动到一个新的 task 中。
接下来,回到 startActivityUnchecked 方法中:
java
private int startActivityUnchecked(...) {
//......
// 把前面计算出的 mLaunchFlags 设置到 mIntent 中
mIntent.setFlags(mLaunchFlags);
// 查找是否有重用的 Activity
// 当前场景下为 null
ActivityRecord reusedActivity = getReusableIntentActivity();
// ......
}
getReusableIntentActivity 查找可复用的 Activity,当前场景下为 null,巨复杂,单独一节来讲,这里先梳理主干流程。
接着回到 startActivityUnchecked 方法中:
java
private int startActivityUnchecked(...) {
// ......
// 用新计算出的参数重新计算一次 mLaunchParams
mSupervisor.getLaunchParamsController().calculate(
reusedActivity != null ? reusedActivity.getTaskRecord() : mInTask,
r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
// 重新获取 mPreferredDisplayId
mPreferredDisplayId =
mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
: DEFAULT_DISPLAY;
// 冻结最近任务列表,单独一节来讲
// If requested, freeze the task list
if (mOptions != null && mOptions.freezeRecentTasksReordering()
&& mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
&& !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
mFrozeTaskList = true;
mSupervisor.mRecentTasks.setFreezeTaskListReordering();
}
// 判断是否是 Launcher 主页面,不要启动 Launcher 主页面
// Do not start home activity if it cannot be launched on preferred display. We are not
// doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
// fallback to launch on other displays.
if (r.isActivityTypeHome() && !mRootActivityContainer.canStartHomeOnDisplay(r.info,
mPreferredDisplayId, true /* allowInstrumenting */)) {
Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
return START_CANCELED;
}
// 当前情景下,没有重用,不进入
if (reusedActivity != null) {
// ......
}
// 不进入
if (mStartActivity.packageName == null) {
// ......
}
// 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.
// Launcher 的 ActivityStack
final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack();
//
final ActivityRecord topFocused = topStack.getTopActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
// false
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.mActivityComponent.equals(mStartActivity.mActivityComponent)
&& top.mUserId == mStartActivity.mUserId
&& top.attachedToProcess()
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
// This allows home activity to automatically launch on secondary display when
// display added, if home was the top activity on default display, instead of
// sending new intent to the home activity on default display.
&& (!top.isActivityTypeHome() || top.getDisplayId() == mPreferredDisplayId);
if (dontStart) { // 不进入
//......
}
boolean newTask = false;
// null
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTaskRecord() : null;
// Should this be considered a new task?
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { // 走这个分支
newTask = true;
// 查找/新建管理目标 Activity 的 TaskRecord 任务栈对象
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} 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.
result = setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
- 用新计算出的参数重新计算一次 mLaunchParams
- 重新获取 mPreferredDisplayId
- 冻结最近任务列表
- 判断是否是 Launcher 主页面,不要启动 Launcher 主页面
- 处理可重用的 Activity,当前情景下,没有重用
- 查找/新建管理目标 Activity 的 TaskRecord 任务栈对象
查找/新建管理目标 Activity 的 TaskRecord 任务栈对象通过 setTaskFromReuseOrCreateNewTask
方法实现:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
// 错误情况处理,直接返回
if (mRestrictedBgActivity && (mReuseTask == null || !mReuseTask.containsAppUid(mCallingUid))
&& handleBackgroundActivityAbort(mStartActivity)) {
return START_ABORTED;
}
// 获取/创建目标 Activity 所在的 ActivityStack
// 当前情景下,层层调用,最终实际就是 new 一个 ActivityStack
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
// Do no move the target stack to front yet, as we might bail if
// isLockTaskModeViolation fails below.
if (mReuseTask == null) { //没有可复用的任务栈,进入分支
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
// 创建新 App 对应的新的任务栈
// 当前情景下,层层调用,实际也是 new 一个 TaskRecord
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
// 将目标 ActivityRecord 插入新建的 TaskRecord 的栈顶为止
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in new task " + mStartActivity.getTaskRecord());
} else {
addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
}
if (taskToAffiliate != null) { // 不进入
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
if (mService.getLockTaskController().isLockTaskModeViolation(
mStartActivity.getTaskRecord())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
// 将 ActivityStack 设置到栈顶
// 好像就是调整 ActivityStack 在 ArrayList 中的位置
if (mDoResume) {
mTargetStack.moveToFront("reuseOrNewTask");
}
return START_SUCCESS;
}
我们为启动目标 Activity 完成了一下工作:
- new 了一个 ActivityStack 对象
- 在 ActivityStack 中 new 了一个 TaskRecord 对象
- 将目标 ActivityRecord 插入新建的 TaskRecord 的栈顶为止
注意一点就是新 new 的 TaskRecord 可能不在 ActivityStack 的栈顶位置,后面应该会调整。
java
private int startActivityUnchecked(...) {
// 给目标 Activity 授权
// https://juejin.cn/post/7138335779222355975
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
mService.getPackageManagerInternalLocked().grantEphemeralAccess(
mStartActivity.mUserId, mIntent, UserHandle.getAppId(mStartActivity.appInfo.uid),
UserHandle.getAppId(mCallingUid));
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
mStartActivity.getTaskRecord().taskId);
}
ActivityStack.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTaskRecord());
mTargetStack.mLastPausedActivity = null;
// PowerHint 设置,用于提升系统性能
// https://blog.csdn.net/zxfrdas/article/details/118118584
mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
false /* forceSend */, mStartActivity);
// mTargetStack 内部数据结构调整
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
// 目标新 ActivityRecord
final ActivityRecord topTaskActivity =
mStartActivity.getTaskRecord().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) { // 不走
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
// 也不走
if (mTargetStack.isFocusable()
&& !mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
// 走这里
mRootActivityContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
} else if (mStartActivity != null) {
mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
}
mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
preferredWindowingMode, mPreferredDisplayId, mTargetStack);
return START_SUCCESS;
}
- 给目标 Activity 进行 Uri 授权
- PowerHint 设置,用于提升系统性能
- mTargetStack 内部数据结构调整,前面说过新 new 的 TaskRecord 可能不在 ActivityStack 的栈顶位置,在这里通过调用
mTargetStack.startActivityLocked
做相应的调整 - 最后调用
mRootActivityContainer.resumeFocusedStacksTopActivities
onPause 前一个 Activity,这部分内容我们在下一节来做讲解。
接下来,我们着重看下 mTargetStack.startActivityLocked
的具体实现:
java
// frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTaskRecord();
final int taskId = rTask.taskId;
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && allowMoveToFront
&& (taskForIdLocked(taskId) == null || newTask)) { // 进入分支
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
// 将 task 放到栈顶,实际就是调整 taskrecord 在 list 中的位置
insertTaskAtTop(rTask, r);
}
TaskRecord task = null;
if (!newTask) { //当前情景不进入
// ......
}
// Place a new activity at top of stack, 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 TaskRecord activityTask = r.getTaskRecord();
// ......
task = activityTask;
// ......
if (r.mAppWindowToken == null) {
// 构建 ActivityRecord 的成员 mAppWindowToken
r.createAppWindowToken();
}
/** Call after activity movement or finish to make sure that frontOfTask is set correctly */
// 做检查修正,确保内部参数正确
task.setFrontOfTask();
// 过渡动画处理
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) { // 进入分支
final DisplayContent dc = getDisplay().mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else { // 走这个分支
int transit = TRANSIT_ACTIVITY_OPEN;
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
} else if (getDisplay().isSingleTaskInstance()) {
transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
} else {
// 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)
if (canEnterPipOnTaskSwitch(focusedTopActivity,
null /* toFrontTask */, r, options)) { //走这个分支
focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
}
transit = TRANSIT_TASK_OPEN;
}
}
// 过渡动画准备
dc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
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) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} 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.
TaskRecord prevTask = r.getTaskRecord(); // 新 Activity 对应的 TaskRecord
ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked(); // null
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.getTaskRecord() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
// 开始 Activity 启动动画
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
}
- 调整 taskrecord 在 ActivityStack 中的位置
- 做检查修正 taskrecord 内部参数
- 过渡动画处理