虽然学习的是WMS,但是对于用户来说,直观看到和接触到的就是Activity,而且很多WMS的逻辑,最终的呈现也是和Activity相关,所以Activity相关的逻辑的分析是必不可少的。比如Activity启动流程作为最基础的,肯定是需要掌握的。
对于分析Activity启动流程,依然是只关心主流程代码,不看具体细节,当然对于一些关键方法会着重介绍,这样以后如果有遇到相关问题的修改可以通过这篇笔记找到具体代码位置,然后根据具体的问题分析修改。 对于一些方法重载调用的,为了减少文字篇幅,尽量保持精简,所以对于这部分简单的逻辑会进行跳过。
启动Activity的方式有很多,当前笔记以在Launch中点击"电话"图标启动应用为例。
模块框图
一级框图
对于Activity的启动流程来说,可以分为3个模块:
SourceActivity:执行startActivity方法的Activity,发起请求的Activity,当前就是Launch的Activity
TargetActivity:需要被启动的Activity,当前就是"电话"应用在清单文件配置的MainActivity
AMS: 不仅仅是指AMS这一个类,而是指处理整个启动流程的管理类。
举个例子, 以在公司的工作流程来说, launch模块的开发,在处理一个bug,但是涉及到了通话,那么他肯定是需要找到通讯组的同事来处理这个问题。 但是公司很大,他并不知道通讯模块是谁负责,更不知道这个问题需要交给通讯组具体的哪个同事处理,那么他只需要将自己的要求向公司领导(管理)汇报:需要通讯组的同事处理这个问题。
当前例子设计到launcher和通讯2个模块的开发人员,还涉及到公司的管理者。在Activity启动也是如此, 对于sourceActivity、targetActivity他们并不知道直接作用对方的行为,所以这一流程需要AMS来做管理。
并且,这3个模块也对应3个进程,当前案例来说分别为:launch进程,电话进程,system_service进程。
这里AMS对launch多了一个返回箭头的原因是因为launch肯定是需要执行pause的,但是整个启动流程非常复杂,执行pause的时机launch自身无法控制,只能由AMS控制。
二级框图
这里有3个颜色,代表3个阶段。
第一阶段:
- 由launcher 进程发起启动Activity的请求
- AMS处理,创建对应的ActivityRecord和Task,并挂载到窗口层级树中
第二阶段:
- AMS 触发launcher 的pause流程
- AMS 触发"电话"应用进程的创建
- launcher执行pause流程
- launcher执行完pause后执行调用AMS的startSpecificActivity方法启动"电话"Activity
ASM 通知 launcher 执行pause和通过 Zygote 创建进程都是异步的,不知道执行的顺序。所以launcher执行completePause后调用启动Activity时,会判断进程是否已经创建完毕。
第三阶段:
- "电话"进程创建完毕,通知AMS
- AMS触发realStartActivityLocked,通知应用启动Activity
- 应用进程执行Activity的启动流程,生命周期 走到onCreate和onResume
这里第二步,里面会判断launcher是否执行完pause了, 如果没有执行则直接return。
也就是说需要启动"电话"的Activity,必须有2个条件:1. 进程创建完毕 2. launcher执行完pause
在新的Activity显示前, launch肯定是要执行pause的。
1. launch点击图标启动应用进程
这一阶段调用比较简单,堆栈如下:
其实我们正常通过 startActivity 传递 intent 启动Activity的流程也是一样的。 最终都会调到Instrumentation::execStartActivity。然后开始跨进程与AMS通信。
调用链
Activity::startActivity
arduino
Activity::startActivity
Activity::startActivityForResult
Instrumentation::execStartActivity
ActivityTaskManagerService::startActivity
主流程跟踪
在发起启动Activity的这个应用端,逻辑相对简单,无论哪种参数的 startActivity 方法,最终都是调到 startActivityForResult 方法。 然后在 Instrumentation 最后的处理,然后开始跨进程传递到 system_service 进程中
less
# Activity
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
......
}
......
}
# Instrumentation
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
......
// 当前应用进程处理结束,开始传递给ActivityTaskManagerService
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
// 对跨进程启动的结果做check
checkStartActivityResult(result, intent);
......
}
checkStartActivityResult 这个方法,比如常见的未在AndroidManifest.xml注册Activity的报错就在这。
java
# Instrumentation
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND: // 未在AndroidManifest.xml注册
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml"
+ ", or does your intent not match its declared <intent-filter>?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start voice activity on a hidden session");
case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startAssistantActivity does not match active session");
case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start assistant activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for "
+ intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
2. system_service 处理
调用链
arduino
ActivityTaskManagerService::startActivity
ActivityTaskManagerService::startActivityAsUser
ActivityTaskManagerService::startActivityAsUser
ActivityStartController::obtainStarter
ActivityStarter::execute
ActivityStarter::executeRequest -- 构建 ActivityRecord --2..1 创建ActivityRecord
ActivityStarter::startActivityUnchecked
ActivityStarter::startActivityInner -- 2.2 关键函数startActivityInner
ActivityStarter::getOrCreateRootTask -- 2.2.1 创建或者拿到Task
ActivityStarter::setNewTask -- 2.2.2 将task与activityRecord 绑定
RootWindowContainer::resumeFocusedTasksTopActivities --2.2.3 显示Activity
主流程跟踪
流程来到ActivityTaskManagerService::startActivity,经过2次简单的跳转会执行 startActivityAsUser 方法。 这个方法比较重要,在这里会构建一个 ActivityStartController ,根据类名可以知道这个类是控制Activity启动。
代码如下:
scss
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
......
// 返回的是ActivityStartController
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
ActivityStartController getActivityStartController() {
return mActivityStartController;
}
ActivityStartController::obtainStarter返回的是ActivityStarter对象
scss
# ActivityStartController
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
所以在ActivityTaskManagerService::startActivityAsUser方法中的build模式,其实是对 ActivityStarter 对象做构建。最终调用其 execute 方法。 然后调用 executeRequest 方法。
csharp
# ActivityStarter
int execute() {
......
res = executeRequest(mRequest);
......
}
2.1创建ActivityRecord
ActivityStarter::executeRequest是一个需要注意的方法,因为内部会创建 ActivityRecord 对象,而这个 ActivityRecord 对象持有 token ,这个token就是以后分析其他逻辑一直会出现的token。
应用进程中的Activity在AMS的代表就是ActivityRecord
scss
# ActivityStarter
private int executeRequest(Request request) {
......
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession != null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
......
// 继续执行startActivityUnchecked
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
inTask, inTaskFragment, restrictedBgActivity, intentGrants);
......
}
而 startActivityUnchecked 主要调用的是 startActivityInner , 这个方法是流程的关键点。
2.2 关键函数startActivityInner
这个函数是AMS在Activity启动流程最重要的函数之一,这里涉及到【层级结构树】相关,先看看正常在launch的和启动"电话"后的层级树对比。
这里首先多了3个东西:1个Task,1个上一步创建的ActivityRecord,还有一个就是WindowState。
另外这个Task还移动到了DefaultTaskDisplayArea的最顶部。这里涉及到的操作如下:
- 创建Task
- ActivityRecord挂在到这个Task下
- 将这个Task移动到最上面
至于最下面的那个 546fce2 为什么是WindowState对象,又是怎么挂在到ActivityRecord上的,这个在【应用的addWindow流程】详细说明了。
java
# ActivityStarter
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean restrictedBgActivity,
NeededUriGrants intentGrants) {
......
/ computeTargetTask内部会根据具体条件返回Task(比如标志位FLAG_ACTIVITY_NEW_TASK姐需要重新创建Task )
// 这里reusedTask为 null,因为是新启动的应用,所以computeTargetTask也找不到task,最终也为null
/
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
// 那么newTask为true, 表示需要新建一个task
final boolean newTask = targetTask == null;
// 同样为null
mTargetTask = targetTask;
......
if (mTargetRootTask == null) {
// 重点* 1. 创建Task 23
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
mOptions);
}
if (newTask) {
// taskToAffiliate 为null
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// 重点* 2. 将需要启动的ActivityRecord与 新创建的Task 进行绑定
setNewTask(taskToAffiliate);
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
if (!mAvoidMoveToFront && mDoResume) {
// 移动到栈顶
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
......
}
......
if (mDoResume) {
......
// 重点*3. task 处理完后,需要将task顶部的Activity显示(resume)
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
......
}
具体原因在代码加了注释,那么第一步就是需要创建一个Task了。
2.2.1 创建Task getOrCreateRootTask
调用链
arduino
ActivityStarter::getOrCreateRootTask
RootWindowContainer::getOrCreateRootTask
RootWindowContainer::getOrCreateRootTask
TaskDisplayArea::getOrCreateRootTask
TaskDisplayArea::getOrCreateRootTask
Task::Build ---创建Task
主流程代码
less
# ActivityStarter
private Task getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
final Task sourceTask = mSourceRecord != null ? mSourceRecord.getTask() : null;
return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,
mLaunchParams, launchFlags);
}
// onTop 表示是否要移到到当前栈顶,那肯定是要的,新启动的Activity当前要再最上面,这里 aOptions 为null,所以为true
// sourceTask 表示从哪里启动的,当前launch所在的Task 就是sourceTask
# RootWindowContainer
Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task candidateTask, boolean onTop) {
return getOrCreateRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
null /* launchParams */, 0 /* launchFlags */);
}
Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
......
final int activityType = resolveActivityType(r, options, candidateTask);
if (taskDisplayArea != null) {
if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) {
// 重点*1. 传递到TaskDisplayArea
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
} else {
taskDisplayArea = null;
}
}
......
}
// 经过同名调用后,逻辑进入到 TaskDisplayArea
# TaskDisplayArea
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
if(....) {
// 拿到之前创建的Task
return candidateTask.getRootTask();
}
......// 第一次显示所以是新建Task
return new Task.Builder(mAtmService)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setOnTop(onTop)
.setParent(this) // 主要这个this被设置为Parent。所以直接挂载到了DefaultTaskDisplayArea下
.setSourceTask(sourceTask)
.setActivityOptions(options)
.setLaunchFlags(launchFlags)
.build();
}
// 看方法名是获取或创建Task, 这边是新启动的Activity所以需要创建Task。如果是以默认启动方式打开应用内的另一个Activity,就走的是上面的 return candidateTask.getRootTask();
接下来就是真正触发Task的创建。
// 另外设置的parent就是层级结构树应用所在的名为"DefaultTaskDisplayArea"的TaskDisplayArea
# Task
# Task.Builder
Task build() {
if (mParent != null && mParent instanceof TaskDisplayArea) {
validateRootTask((TaskDisplayArea) mParent);
}
if (mActivityInfo == null) {
mActivityInfo = new ActivityInfo();
mActivityInfo.applicationInfo = new ApplicationInfo();
}
mUserId = UserHandle.getUserId(mActivityInfo.applicationInfo.uid);
mTaskAffiliation = mTaskId;
mLastTimeMoved = System.currentTimeMillis();
mNeverRelinquishIdentity = true;
mCallingUid = mActivityInfo.applicationInfo.uid;
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
if (mActivityOptions != null) {
mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
}
// 重点* 1. 创建task
final Task task = buildInner();
task.mHasBeenVisible = mHasBeenVisible;
// Set activity type before adding the root task to TaskDisplayArea, so home task can
// be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded().
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
task.setActivityType(mActivityType);
}
// 重点* 2. 入栈 这里的 mOnTop为true
if (mParent != null) {
if (mParent instanceof Task) {
final Task parentTask = (Task) mParent;
parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM,
(mActivityInfo.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
} else {
mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM);
}
}
// Set windowing mode after attached to display area or it abort silently.
if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
task.setWindowingMode(mWindowingMode, true /* creating */);
}
// 返回
return task;
}
// 创建
Task buildInner() {
return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);
}
小结:
最后描述一下最后创建的2个重点部分:
- 看到通过buildInner 创建了一个task,而buildInner 也很简单粗暴,通过各个变量直接new Task 对象。
- mParent 不为null, 是 因为在创建的时候 setParent(this),当前的这个this,就是 getDefaultTaskDisplayArea返回的。就是 37层的第二层应用Activity存在的"DefaultTaskDisplayArea"。
在 RootWindowContainer::getOrCreateRootTask 体现。
注意log里的 #17 的这个Task,与前面的层级结构树新增的Task,是对应的上的。而且this= DefaultTaskDisplayArea 说明也确实是往DefaultTaskDisplayArea里添加了。 另外 log里index为3,结合最上面的前后对比,说明也的往顶部添加。
2.2.2 将task与activityRecord setNewTask
调用链
arduino
ActivityStarer::setNewTask
ActivityStarer::addOrReparentStartingActivity
主流程代码
java
# ActivityStarer
private void setNewTask(Task taskToAffiliate) {
// 为true
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
// 就是mTargetRootTask,也就是刚刚创建的Task
final Task task = mTargetRootTask.reuseOrCreateTask(
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
task.mTransitionController.collectExistenceChange(task);
// ActivityRecord的挂载
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask");
// 需要注意这里的日志打印
ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
mStartActivity, mStartActivity.getTask());
// mLaunchTaskBehind 为false,所以taskToAffiliate 为null
if (taskToAffiliate != null) {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
}
这里的task 和mTargetRootTask是同一个对象, 进源码跟到流程也是一样。 然后进入 addOrReparentStartingActivity
less
# ActivityStarer
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
// newParent = task 都是刚刚创建的Task
TaskFragment newParent = task;
......
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
// 重点, 将 ActivityRecord挂在到新创建的Task中,并且是顶部
newParent.addChild(mStartActivity, POSITION_TOP);
} else {
mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason);
}
}
这里的逻辑设计到的Task就是上一步创建的Task,mStartActivity则是"电话"在之前逻辑创建的ActivityRecord。
setNewTask的堆栈信息如下
另外这段逻辑里有个ProtoLog打印,日志如下:
小结:
结合逻辑分析+堆栈信息+ProtoLog,可以确认setNewTask做的事情就是将ActivityRecord挂在到Task中,而且在顶部
2.2.2.3 移动Task到容器顶部 moveToFront
这里提一下这个moveToFront方法,因为前面创建Task并添加到 DefaultTaskDisplayArea 时是往顶部添加,后面将ActivityRecord挂在到Task,也是挂在到其顶部。所以这个函数其实没有什么实际操作。但是对于其他场景,这里也是一个重点方法。
调用链
arduino
Task::moveToFront -- 2.1.3 移动Task
Task::moveToFrontInner
TaskDisplayArea::positionChildAt
TaskDisplayArea::positionChildTaskAt
ActivityTaskSupervisor::updateTopResumedActivityIfNeeded
ActivityRecord::onTopResumedActivityChanged --触发TopResumedActivityChangeItem
主流程代码
首先确定一个问题。 需要移动到顶部的是哪个task? 这个task所在的是在哪个task? 这里设计到了2个task 在ActivityStarter::startActivityInner的时候调用的是这段代码
scss
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
已知mTargetRootTask是新创建给"电话"用的Task, mTargetRootTask.getRootTask()肯定就是还是本身。
tip :getRootTask返回的是顶部的Task, 当天Task上一层是TaskDisplayArea类型 (name为DefaultTaskDisplayArea) 而mTargetRootTask.getParent返回的父容器,则是 name为DefaultTaskDisplayArea的TaskDisplayArea。 具体不深入,以主流程为主.。
到这里,AMS已经将需要的ActivityRecord和Task创建并且挂载到层级树中接下来将是需要处理新的Activity启动和显示逻辑了
2.2.3 显示Activity resumeFocusedTasksTopActivities
篇幅原因,后续流程在下一篇