忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
– 服装学院的IT男
本篇已收录于Activity短暂的一生系列
欢迎一起学习讨论Android应用开辟大概WMS
V:WJB6559
Q:707409814
正文
由于篇幅原因,整个启动流程分为以下3篇进行分析:
Activity启动流程-1
Activity启动流程-2
Activity启动流程-3
Activity 的启动流程无论是 APP 开辟还是 FrameWork 开辟都是必须要认识的一个流程。
FrameWork 中有很多告急的流程都是在 Activity 启动过程中触发的,不过当前还是以分析 Activity 启动主流程为主,固然对于一些关键方法还是会着重先容,这样以后如果有碰到相干问题的修改可以通过这篇文章找到具体代码位置,然后根据具体的问题分析修改。
启动 Activity 的方式有很多,当前以在 Launcher 点击“电话”图标启动应用场景进行分析。
1. 整体先容
1.1 一级框图
对于Activity的启动流程来说,可以分为3个模块:
SourceActivity:实行 startActivity 方法的 Activity ,也就是发起请求的Activity ,当前是 Launcher 的 Activity 。
TargetActivity:被启动的 Activity 当前就是“电话”应用在清单文件配置的MainActivity
AMS: 不仅仅是指 AMS 这一个类,而是指在这个过程中 system_service 进程参与处置惩罚的相干类
举个例子,以在公司的工作流程来说, Launcher 模块的开辟,在处置惩罚一个 bug,但是涉及到了通话,那么他必要找到通讯组的同事来处置惩罚这个问题。但公司很大,他并不知道通讯模块是谁负责,更不知道这个问题必要交给通讯组具体的哪个同事处置惩罚,那么他只必要将自己的要求向公司向导(管理着)报告:必要通讯组的同事处置惩罚这个问题。
当前例子设计到 launcher 和通讯2个模块的开辟职员,还涉及到公司的管理者。在Activity 启动也是云云, 对于 SourceActivity、TargetActivity 来说他们并不知道对方模块的业务,以是这一流程必要AMS来做管理。
并且,这3个模块也对应3个进程,当前案例来说分别为:Launcher 进程,电话进程,system_service 进程。
图中AMS 对 Launcher 多了一个返回箭头的原因是 Launcher 肯定是必要实行 pause 的,但实行 pause 的时机 Launcher 自身无法控制,只能由 AMS 控制。
1.2 总体流程
这里有4个阶段,以4个颜色体现,同时还涉及到3个进程。
第一阶段:
- 由 Launcher 进程发起启动 Activity 的请求
- AMS 处置惩罚,创建对应的 ActivityRecord 和 Task ,并挂载到窗口层级树中
- AMS 触发 Launcher 的 pause 流程
-
第二阶段:
-
- pause 流程完成后触发 AMS 启动 TargetActivity
第三阶段:
-
- 应用进程创建好后会向 AMS 进行绑定,并触发 AMS 启动 TargetActivity
第四阶段:
- AMS 触发 realStartActivityLocked 方法试图应用启动 Activity
- 如果还有 Activity 没有实行完 pause 逻辑,则 realStartActivityLocked 会 return
- 如果应用 Activity 都实行完了 pause ,则触发 TargetActivity 的启动,并将生命周期会实行到 onResume
注意:其中第2,3阶段险些是同时开始的,并且 ASM 通知 Launcher 实行 pause 和通过 Zygote 创建进程是异步操作,不知道各自实行的序次。
但是看的出来最终都是会实行到 realStartActivityLocked 方法来试图启动 TargetActivity ,为什么说是“试图启动”启动呢?
一共就有2种大概:
假设第一种情况:
Launcher 先实行完 completePause 来到 ActivityTaskSupervisor::startSpecificActivity 方法,这个时间进程还没创建完毕,则不会实行 ActivityTaskSupervisor::realStartActivityLocked ,而是会再触发进程创建,固然之前已经触发过来,这次触发不会真的再创建进行了。
然后会由阶段三的流程创建好进程走到 ActivityTaskSupervisor::realStartActivityLocked ,在这个方法里会判断是不是实行完 pause 了,那当前这个情况肯定是满意的,
以是会触发启动 TargetActivity 。
假设第二种情况:
阶段三创建进程先实行完,走到 ActivityTaskSupervisor::realStartActivityLocked 方法,但是发现 pause 还没实行玩,以是就 return 了。
然后等 completePause 流程来到 ActivityTaskSupervisor::startSpecificActivity 方法时,这次发现进程已经创建好了,则一次实行后续逻辑触发启动 TargetActivity 。
也就是说不管阶段二,三谁先实行完都会试图启动 TargetActivity ,而乐成启动必须有2个条件:
也就说说这2个阶段后实行过来的流程才能正式启动 TargetActivity 。
2. 阶段一:桌面点击图标启动应用
2.1 流程概览
这一阶段调用比较简朴,堆栈如下:
整理后如下:
- ItemClickHandler::onClick
- ItemClickHandler::onClickAppShortcut
- ItemClickHandler::startAppShortcutOrInfoActivity
- QuickstepLauncher::startActivitySafely
- Launcher::startActivitySafely
- AppLauncher::startActivitySafely
- BaseQuickstepLauncher::getActivityLaunchOptions -- 构建 Option 参数
- Activity::startActivity -- 共用启动Activity流程
- Activity::startActivity
- Activity::startActivity
- Activity::startActivityForResult
- Instrumentation::execStartActivity
- ActivityTaskManagerService::startActivity -- 跨进程
复制代码 画成时序图:
其实我们正常通过 startActivity 通报 Intent 启动 Activity 的流程也是一样的,最终都会调到 Instrumentation::execStartActivity 然后开始跨进程与 AMS 通讯。
只不过这边多了一些 Launcher 自己的处置惩罚,这边只必要对 BaseQuickstepLauncher::getActivityLaunchOptions 有个印象即可,这个方法会构建 ActivityOptions 对象,包罗了一些启动参数,比如:远端动画的 RemoteAnimationAdapter 。
前面的流程就不看了,实行从 Activity::startActivityForResult 开始看代码流程。
2.2 SourceActivity 端处置惩罚
SourceActivity 发起启动 Activity 的逻辑相对简朴,无论哪种参数的 Activity::startActivity 方法,最终都是调到 Activity::startActivityForResult 方法。
然后在 Instrumentation 最后的处置惩罚,最后跨进程通报到 system_service 进程中。
- # Activity.java
- 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.java
- 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);
- ......
- }
复制代码 Instrumentation::checkStartActivityResult 这个方法有一些常见的报错,比如常见的未在 AndroidManifest.xml 注册 Activity 的报错就在这。
- # 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);
- }
- }
复制代码 3. 阶段一 : system_service 处置惩罚
3.1 流程概述
对于 system_service 来说,它收到了启动 Activity 的请求,那么它要做的就是启动 TargetActivity 。
要实现这个目标,我整理了大概要做以下几件事:
-
- 想要启动 Activity 最最少得知道具体是哪个 Activity 吧,固然还有其他很多参数,比如是谁发起的请求,requestCode等等,这些参数都是应用端带过来的。system_service 的第一件事肯定是剖析这些参数,这些参数将被剖析存放在一个叫 Request 对象中。
-
- 虽然是启动 Activity ,但是肯定涉及到窗口操作,以是这一步也是必须的
- 触发 SourceActivity 实行pause 逻辑
- 必要表现新的 TargetActivity ,那之前的 SourceActivity 肯定要实行 pause 逻辑的
-
- 当前场景是冷启动,那启动 TargetActivity 前必须要保证其所在的进程已经存在
在 Instrumentation::execStartActivity 里就开始触发跨进程通讯了,剩下的逻辑就在 system_service 进程中实行了。
这部分缩略版的的调用链如下:
- ActivityTaskManagerService::startActivity
- ActivityTaskManagerService::startActivityAsUser
- ActivityTaskManagerService::startActivityAsUser
- ActivityStartController::obtainStarter
- ActivityStarter::execute
- ActivityStarter$Request::resolveActivity -- 解析启动请求参数
- ActivityStarter::executeRequest -- 3.3 创建ActivityRecord
- ActivityStarter::startActivityUnchecked
- ActivityStarter::startActivityInner -- 3.4 关键函数startActivityInner
- ActivityStarter::getOrCreateRootTask -- 3.4.1 创建或者拿到Task
- ActivityStarter::setNewTask -- 3.4.2 将Task与activityRecord 绑定
- Task::moveToFront --3.4.3 移动Task到栈顶
- RootWindowContainer::resumeFocusedTasksTopActivities --3.4.4 显示Activity
- Task::resumeTopActivityUncheckedLocked
- Task::resumeTopActivityInnerLocked
- TaskFragment::resumeTopActivity -- 显示顶层Activity
- TaskDisplayArea::pauseBackTasks -- pause LauncherActivity
- ActivityTaskManagerService::startProcessAsync -- 创建“电话”进程
复制代码 时序图:
流程来到 ActivityTaskManagerService::startActivity ,经过2次简朴的跳转会实行 ActivityTaskManagerService::startActivityAsUser 方法。
这个方法比较告急,在这里会构建一个 ActivityStartController ,根据类名可以知道这个类是控制 Activity 启动。
3.2 启动请求参数的构建
代码如下:
- # ActivityTaskManagerService
- 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: btainStarter 返回的是 ActivityStarter 对象。
而 ActivityStarter 这个类名看着就是处置惩罚启动 Activity 的一个类,它做的是就是剖析调用者通报的参数,构建出一个 Request 然后开始实行后续的启动 Activity 逻辑。
- # ActivityStartController
- // 返回ActivityStarter
- ActivityStarter obtainStarter(Intent intent, String reason) {
- return mFactory.obtain().setIntent(intent).setReason(reason);
- }
复制代码 以是在 ActivityTaskManagerService::startActivityAsUser 方法中的 build 模式,其实是对 ActivityStarter 对象做构建,最终调用其 execute 方法。
在内容最终实行了 ActivityStarter::executeRequest 方法,下面只以 setCallingPackage 这一个方法看一下是怎么把参数设置到 Request 中的。
- # ActivityStarter
- // 启动Activity的请求
- Request mRequest = new Request();
- // 设置调用者包名
- ActivityStarter setCallingPackage(String callingPackage) {
- mRequest.callingPackage = callingPackage;
- return this;
- }
- // 设置ActivityInfo
- ActivityStarter setActivityInfo(ActivityInfo info) {
- mRequest.activityInfo = info;
- return this;
- }
- int execute() {
- ......
- // 如果 mRequest 中没有 Activity 相关信息
- if (mRequest.activityInfo == null) {
- // 解析请求数据
- mRequest.resolveActivity(mSupervisor);
- }
- ......
- // 执行启动Activity请求
- res = executeRequest(mRequest);
- ......
- }
复制代码 build 模式会把参数设置到 mRequest 中,但是并没有看到调用 ActivityStarter::setActivityInfo 以是在实行 ActivityStarter::execute 的时间 “mRequest.activityInfo”是 null 。
以是这里又分2步:
3.2.1 activityInfo 的剖析
- ActivityStarter$Request
- ResolveInfo resolveInfo;
- ActivityInfo activityInfo;
- void resolveActivity(ActivityTaskSupervisor supervisor) {
- ......
- // 解析resolveInfo
- resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
- 0 /* matchFlags */,
- computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),
- realCallingPid);
- ......
- // 解析activityInfo
- activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
- profilerInfo);
- ......
- }
复制代码 TargetActivity 所在的进程包名和 TargetActivity 的完整路径都在 activityInfo 中,这个剖析方法也是一个核心点,当前分析主流程就不细看了。
如今 mRequest 中就包罗了启动 TargetActivity 的所有数据,就可以继续后面的启动流程了。
3.3 创建ActivityRecord
ActivityStarter::executeRequest 是一个必要注意的方法,因为内部会创建 ActivityRecord 对象,而这个 ActivityRecord 对象持有 token ,这个 token 就是以后分析其他逻辑一直会出现的 token 。也可以说是 system_service 中一个 Activity 的唯一标识。
应用进程中的 Activity 在 AMS 的代表就是 ActivityRecord 。
- # ActivityStarter
- private int executeRequest(Request request) {
- ......
- // 包名在这
- ActivityInfo aInfo = request.activityInfo;
- ResolveInfo rInfo = request.resolveInfo;
- ......
- if (err == ActivityManager.START_SUCCESS) {
- // 重点* 1. 打印创建 ActivityRecord 日志
- request.logMessage.append("START u").append(userId).append(" {")
- .append(intent.toShortString(true, true, true, false))
- .append("} with ").append(launchModeToString(launchMode))
- .append(" from uid ").append(callingUid);
- if (callingUid != realCallingUid
- && realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
- request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
- }
- }
- ......
- // 重点* 2. 构造出一个ActivityRecord
- 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();
- ......
- // 重点* 3. 继续执行startActivityUnchecked
- mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
- request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
- inTask, inTaskFragment, restrictedBgActivity, intentGrants);
- ......
- }
复制代码 3个注意点:
- 虽然是个日记,但是也很关键,一般分析日记看启动了哪个 Activity 就搜“START u” ,打印的地方就在这。另外发现 U 版本上这一块还做了改变。
-
- 继续主流程
主要看第二点 ActivityRecord 是怎么创建的。
- # ActivityRecord
- private ActivityRecord(ActivityTaskManagerService _service, ......) {
- // 调用父类,创建 Token
- super(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,
- null /* displayContent */, false /* ownerCanManageAppTokens */);
- ......
- packageName = info.applicationInfo.packageName;
- .....
- }
复制代码 这里的重点其实就是创建了一个匿名 Token 然后通报到了父类的构建方法, ActivityRecord 的父类是 WindowToken 。
- # WindowToken
- protected WindowToken(WindowManagerService service, IBinder _token, int type,
- boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) {
- this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
- false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */);
- }
- protected WindowToken(WindowManagerService service, IBinder _token, int type,
- boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
- boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
- super(service);
- // token 赋值
- token = _token;
- windowType = type;
- mOptions = options;
- ......
- if (dc != null) {
- // 挂载到窗口树,
- dc.addWindowToken(token, this);
- }
- }
复制代码 将 ActivityRecord 创建的匿名 保存在了 token 对象,这个 token 就是 Activity 在 system_service 里唯一标识符。
平凡的 WindowToken 在这里会挂载的窗口层级树,但是 DisplayContent::addWindowToken 方法内部对 ActivityRecord 做了判断。也就是说 ActivityRecord 刚创建好后是不会挂载到窗口树上的,当前流程后面是要先容 ActivityRecord 是怎么挂载到层级树上的。
ActivityRecord 创建好后继续走主流程,根据前面的分析下一步是实行 ActivityStarter::startActivityUnchecked 不过这个方法也没做啥,主要是调用了 ActivityStarter::startActivityInner ,这个方法是流程的关键点。
3.4 窗口层级树处置惩罚
ActivityStarter::startActivityInner 是 Activity 启动流程最告急的函数之一,这里涉及到【窗口层级树】相干知识,上一末节说了 ActivityRecord 创建好后并不会和 WindowToken 一样挂载到层级树中,而是必要单独处置惩罚,本末节就是看这一块是怎样处置惩罚的。
先看看正常在 Launcher 界面时和启动“电话”后的层级树对比。
这里首先多了3个东西:
另外这个 Task 还移动到了DefaultTaskDisplayArea的最顶部,这里涉及到的操作如下:
-
- ActivityRecord 挂在到这个 Task 下
-
至于最下面的那个 546fce2 为什么是 WindowState 对象,又是怎么挂在到 ActivityRecord 上的,这个属于窗口表现第一步-addWindow流程当前就不单独分析了。
继续看主流程代码:
- # ActivityStarter
- // The task that the last activity was started into. We currently reset the actual start
- // activity's task and as a result may not have a reference to the task in all cases
- private Task mTargetTask;
- 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) {
- // 重点* 3. 移动到栈顶
- mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
- ......
- }
- ......
- if (mDoResume) {
- ......
- // 重点*4. task 处理完后,需要将task顶部的Activity显示(resume)
- // mTransientLaunch 一般为默认值 false
- mRootWindowContainer.resumeFocusedTasksTopActivities(
- mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
- }
- ......
- }
复制代码
-
- 我们知道 ActivityRecord 必要挂载到一个 Task 下,虽然这里调用的方法名是 getOrCreateRootTask(获取大概创建Task),但是当前场景肯定是创建一个,热启动是获取。
- 另外 Task 创建的时间就会挂载到层级树中,也就是会挂载到DefaultTaskDisplayArea 下
- 将 ActivityRecord 挂载到创建的 Task 下
-
- 因为这个新启动的 Activity 必要表现,以是必要将它所在的 Task 移到容器顶部。 不过当前场景建好就已经是栈顶了,其实这一步没做什么,这点后面代码会分析
-
- 窗口层级的处置惩罚好了,就可以处置惩罚表现逻辑了,这里后续的逻辑会触发 Activity 的启动
3.4.1 获取Task–getOrCreateRootTask
调用链
- ActivityStarter::getOrCreateRootTask
- RootWindowContainer::getOrCreateRootTask
- RootWindowContainer::getOrCreateRootTask
- TaskDisplayArea::getOrCreateRootTask
- TaskDisplayArea::getOrCreateRootTask
- Task::Build ---创建Task
复制代码 开始看代码:
- # 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.getAvoidMoveToFront 和 mLaunchTaskBehind 都为false,以是 onTop 为 true
- sourceTask 体现从哪里启动的,当前 Launcher 所在的 Task 就是 sourceTask
然后开始获取一个 Task 如果没有就新建一个。
- # 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::getOrCreateRootTask 。
- # 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();”
设置的 parent 就是层级结构树应用所在的名为“DefaultTaskDisplayArea”的 TaskDisplayArea
接下来就是真正触发Task的创建。
- # Task
- # Task.Builder
- Task build() {
- if (mParent != null && mParent instanceof TaskDisplayArea) {
- validateRootTask((TaskDisplayArea) mParent);
- }
- ......
- // 重点* 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);
- }
复制代码 3.4.1.1 小结
最后描述一下最后创建的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,结合最上面的前后对比,阐明也的往顶部添加。
3.4.2 ActivityRecord挂载到Task–setNewTask
调用链
- ActivityStarter::setNewTask
- ActivityStarer::addOrReparentStartingActivity
复制代码 主流程代码
- # 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 是同一个对象,然后进入 ActivityStarer::addOrReparentStartingActivity 。
- # 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 打印,日记如下:
3.4.2.1 小结
结合逻辑分析 + 堆栈信息 + ProtoLog ,可以确认 ActivityStarer::setNewTask 做的事情就是将 ActivityRecord 挂在到 Task 中,而且在顶部。
3.4.3 移动Task到容器顶部–moveToFront
这里提一下这个 moveToFront 方法,因为前面创建 Task 并添加到 DefaultTaskDisplayArea 时是往顶部添加,后面将 ActivityRecord 挂在到 Task 也是挂在到其顶部。以是这个函数其实没有什么现实操作。但是对于其他场景,这里也是一个重点方法。
调用链
- Task::moveToFront
- Task::moveToFrontInner
- TaskDisplayArea::positionChildAt
- TaskDisplayArea::positionChildTaskAt
- ActivityTaskSupervisor::updateTopResumedActivityIfNeeded
- ActivityRecord::onTopResumedActivityChanged --触发TopResumedActivityChangeItem
复制代码 主流程代码
首先确定一个问题:必要移动到顶部的是哪个 Task ? 这个 Task 所在的是在哪个哪个容器?
在 ActivityStarter::startActivityInner 的时间调用的是这段代码:
- // targetTask 当前场景为null
- mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
复制代码 已知 mTargetRootTask 是新创建给“电话”用的 Task, 而 mTargetRootTask.getRootTask() 返回值当前场景是 mTargetRootTask 本身。
- # Task
- void moveToFront(String reason, Task task) {
- if (!isAttached()) {
- return;
- }
- mTransitionController.recordTaskOrder(this);
- 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");
- }
- final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null;
- if (task == null) {
- // 当前场景为null,所以会赋值成新建的 Task ,也就是 mTargetRootTask 也就是电话的 Task
- task = this;
- }
- // 这里调用 getParent 就是 DefaultTaskDisplayArea 了。
- // 把当前的 Task 移动到 DefaultTaskDisplayArea 的最前面
- task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
- taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason);
- }
复制代码 再回答一下问题:移动的是新建的电话 Task ,它的父容器是 DefaultTaskDisplayArea ,以是是把这个 Task 移动到 DefaultTaskDisplayArea 的最前面。
mTargetRootTask.getRootTask 返回的是顶部的 Task, 当前 Task 上一层是 TaskDisplayArea 类型 (name为DefaultTaskDisplayArea)
而 mTargetRootTask.getParent 返回的父容器(不限制是 Task),则是 name 为 DefaultTaskDisplayArea 的 TaskDisplayArea。
getRootTask 和 getParent 的区别可以自行去源码中看看
到这里,AMS已经将必要的 ActivityRecord 和 Task 创建并且挂载到层级树中,接下来将是必要处置惩罚 TargetActivity 启动和表现逻辑了
3.4.4 表现Activity–resumeFocusedTasksTopActivities
首先看方法格局标必要表现一个栈顶的 Activity ,那说的不就是 TargetActivity 嘛,TargetActivity 的 ActivityRecord 已经创建并且移动到栈顶了。
前面该做的也都做好了,如今也确实是时间处置惩罚表现逻辑,这部分流程由 RootWindowContainer::resumeFocusedTasksTopActivities 实行,调用链如下:
- RootWindowContainer::resumeFocusedTasksTopActivities
- Task::resumeTopActivityUncheckedLocked
- Task::resumeTopActivityInnerLocked
- TaskFragment::resumeTopActivity
- TaskDisplayArea::pauseBackTasks -- pause LauncherActivity
- WindowContainer::forAllLeafTask
- TaskFragment::forAllLeafTaskFragments
- TaskFragment::startPausing
- TaskFragment::startPausing
- TaskFragment::schedulePauseActivity --构建 PauseActivityItem,这里是触发暂停launch
- ActivityTaskManagerService::startProcessAsync -- 创建“电话”进程
复制代码 重点方法在 TaskFragment::resumeTopActivity 开始处置惩罚,先简朴看一下前面的调用是怎么样的。
- # RootWindowContainer
- // 第四个参数为 false
- boolean resumeFocusedTasksTopActivities(
- Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
- boolean deferPause) {
- ......
- if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
- || getTopDisplayFocusedRootTask() == targetRootTask)) {
-
- result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
- deferPause);
- }
- ......
- }
- # Task
- boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
- boolean deferPause) {
- ......
- if (isLeafTask()) {
- if (isFocusableAndVisible()) {
- someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
- }
- }
- ......
- }
- private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
- boolean deferPause) {
- ......
- // deferPause = false
- resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
- ......
- }
复制代码 由于篇幅原因,下面的 TaskFragment::resumeTopActivity 流程放在下一篇。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |