Android Framework(三)Activity启动流程

2024-09-02 08:12

本文主要是介绍Android Framework(三)Activity启动流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 大纲
    • 总体流程
  • 第一阶段:点击图标启动应用
    • 流程概览
    • SourceActivity端处理
    • system_service处理
      • 启动请求参数的构建
      • activityInfo的解析
      • 创建ActivityRecord
    • 窗口层级树的处理
      • 获取Task--getOrCreateRootTask
      • ActivityRecord挂载到Task--setNewTask
      • 移动Task到容器顶部--moveToFront
    • 显示Activity--resumeFocusedTasksTopActivities
      • pause 流程--pauseBackTasks
      • PauseActivityItem
    • 阶段一总结
    • system_service 处理的完整堆栈
  • 第二阶段--completePause
      • ActivityRecord::activityPaused
      • 第一步--resumeFocusedTasksTopActivities
      • 关键方法--startSpecificActivity
      • 第二步--ensureActivitiesVisible 流程
      • 阶段二总结
  • 第三阶段:触发目标应用进程创建
      • 应用进程创建
      • system_service端处理
      • 阶段三总结
  • 第四阶段:真正启动Activity
    • 创建Activity
    • 阶段四小结

大纲

在这里插入图片描述
对于Activity的启动流程来说,可以分为3个模块:

1、SourceActivity:执行 startActivity 方法的 Activity ,也就是发起请求的Activity ,当前是 Launcher 的 Activity 。

2、TargetActivity:被启动的 Activity 当前就是“电话”应用在清单文件配置的MainActivity。

3、AMS: 不仅仅是指 AMS 这一个类,而是指在这个过程中 system_service 进程参与处理的相关类。

这3个模块也对应3个进程,当前案例来说分别为:Launcher 进程,电话进程,system_service 进程。

图中AMS 对 Launcher 多了一个返回箭头的原因是 Launcher 肯定是需要执行 pause 的,但执行 pause 的时机 Launcher 自身无法控制,只能由 AMS 控制。

总体流程

在这里插入图片描述
这里有4个阶段,以4个颜色表示。同时还涉及到3个进程。

第一阶段:
1、由 Launcher 进程发起启动 Activity 的请求
2、AMS 处理,创建对应的 ActivityRecord 和 Task ,并挂载到窗口层级树中
3、AMS 触发 Launcher 的 pause 流程
4、AMS 触发"电话"应用进程的创建

第二阶段:
1、Launcher 执行完 pause
2、pause 流程完成后触发 AMS 启动 TargetActivity

第三阶段:
1、创建应用进程
2、应用进程创建好后会向 AMS 进行绑定,并触发 AMS 启动 TargetActivity

第四阶段:
1、AMS 触发 realStartActivityLocked 方法试图应用启动 Activity
2、如果还有 Activity 没有执行完 pause 逻辑,则 realStartActivityLocked 会 return
3、如果应用 Activity 都执行完了 pause ,则触发 TargetActivity 的启动,并将生命周期会执行到 onResume

注意:其中第2,3阶段几乎是同时开始的,并且 ASM 通知 Launcher 执行 pause 和通过 Zygote 创建进程是异步操作,不知道各自执行的顺序。
但是看的出来最终都是会执行到 realStartActivityLocked 方法来试图启动 TargetActivity ,为什么说是“试图启动”启动呢?
一共就有2种可能:

  • completePause 先执行完
  • 进程先创建完

假设第一种情况:

  • Launcher 先执行完 completePause 来到 ActivityTaskSupervisor::startSpecificActivity 方法,这个时候进程还没创建完毕,则不会执行 ActivityTaskSupervisor::realStartActivityLocked ,而是会再触发进程创建,当然之前已经触发过来,这次触发不会真的再创建进行了。

  • 然后会由阶段三的流程创建好进程走到 ActivityTaskSupervisor::realStartActivityLocked ,在这个方法里会判断是不是执行完 pause 了,那当前这个情况肯定是满足的,
    所以会触发启动 TargetActivity 。

假设第二种情况:

  • 阶段三创建进程先执行完,走到 ActivityTaskSupervisor::realStartActivityLocked 方法,但是发现 pause 还没执行玩,所以就 return 了。
  • 然后等 completePause 流程来到 ActivityTaskSupervisor::startSpecificActivity 方法时,这次发现进程已经创建好了,则一次执行后续逻辑触发启动 TargetActivity 。

也就是说不管阶段二,三谁先执行完都会试图启动 TargetActivity ,而成功启动必须有2个条件:

  • 进程创建完毕
  • launcher执行完pause

第一阶段:点击图标启动应用

流程概览

堆栈:

ItemClickHandler::onClickItemClickHandler::onClickAppShortcutItemClickHandler::startAppShortcutOrInfoActivityQuickstepLauncher::startActivitySafelyLauncher::startActivitySafelyAppLauncher::startActivitySafelyBaseQuickstepLauncher::getActivityLaunchOptions    -- 构建 Option 参数Activity::startActivity  -- 共用启动Activity流程Activity::startActivityActivity::startActivityActivity::startActivityForResultInstrumentation::execStartActivityActivityTaskManagerService::startActivity -- 跨进程

画成时序图:
在这里插入图片描述
其实我们正常通过 startActivity 传递 Intent 启动 Activity 的流程也是一样的,最终都会调到 Instrumentation::execStartActivity 然后开始跨进程与 AMS 通信。
只不过这边多了一些 Launcher 自己的处理,这边只需要对 BaseQuickstepLauncher::getActivityLaunchOptions 有个印象即可,这个方法会构建 ActivityOptions 对象,包含了一起启动参数,比如:远端动画的 RemoteAnimationAdapter 。
前面的流程就不看了,执行从 Activity::startActivityForResult 开始看代码流程。

SourceActivity端处理

SourceActivity 发起启动 Activity 的逻辑相对简单,无论哪种参数的 Activity::startActivity 方法,最终都是调到 Activity::startActivityForResult 方法。
然后在 Instrumentation 最后的处理,最后跨进程传递到 system_service 进程中。

# Activity.javapublic 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.javapublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {......// 当前应用进程处理结束,开始传递给 ActivityTaskManagerServiceint result = ActivityTaskManager.getService().startActivity(whoThread,who.getOpPackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);// 对跨进程启动的结果做checkcheckStartActivityResult(result, intent);......}

Instrumentation::checkStartActivityResult 这个方法有一些常见的报错,比如常见的未在 AndroidManifest.xml 注册 Activity 的报错就在这。

# Instrumentationpublic 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);}}

system_service处理

对于 system_service 来说,它收到了启动 Activity 的请求,那么它要做的就是启动 TargetActivity 。
要实现这个目的,我整理了大概要做以下几件事:
1、解析请求参数
想要启动 Activity 最起码得知道具体是哪个 Activity 吧,当然还有其他很多参数,比如是谁发起的请求,requestCode等等,这些参数都是应用端带过来的。system_service 的第一件事肯定是解析这些参数,这些参数将被解析存放在一个叫 Request 对象中。
2、处理窗口层级树相关逻辑
虽然是启动 Activity ,但是肯定涉及到窗口操作,所以这一步也是必须的。
3、触发 SourceActivity 执行pause 逻辑,需要显示新的 TargetActivity ,那之前的 SourceActivity 肯定要执行 pause 逻辑的。
4、触发创建进程
当前场景是冷启动,那启动 TargetActivity 前必须要保证其所在的进程已经存在
在 Instrumentation::execStartActivity 里就开始触发跨进程通信了,剩下的逻辑就在 system_service 进程中执行了。

这部分缩略版的的调用链如下:

ActivityTaskManagerService::startActivityActivityTaskManagerService::startActivityAsUserActivityTaskManagerService::startActivityAsUserActivityStartController::obtainStarterActivityStarter::executeActivityStarter$Request::resolveActivity           -- 解析启动请求参数ActivityStarter::executeRequest                    -- 3.3 创建ActivityRecordActivityStarter::startActivityUncheckedActivityStarter::startActivityInner        -- 3.4 关键函数startActivityInnerActivityStarter::getOrCreateRootTask   -- 3.4.1 创建或者拿到Task                ActivityStarter::setNewTask            -- 3.4.2 将Task与activityRecord 绑定Task::moveToFront                       --3.4.3 移动Task到栈顶RootWindowContainer::resumeFocusedTasksTopActivities    --3.4.4 显示ActivityTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivity      --  显示顶层ActivityTaskDisplayArea::pauseBackTasks                   -- pause LauncherActivity ActivityTaskManagerService::startProcessAsync     -- 创建“电话”进程

时序图:
在这里插入图片描述
流程来到 ActivityTaskManagerService::startActivity ,经过2次简单的跳转会执行 ActivityTaskManagerService::startActivityAsUser 方法。
这个方法比较重要,在这里会构建一个 ActivityStartController ,根据类名可以知道这个类是控制 Activity 启动。

启动请求参数的构建

# ActivityTaskManagerServiceprivate 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) {......// 返回的是ActivityStartControllerreturn 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 对象。
而 ActivityStarter 这个类名看着就是处理启动 Activity 的一个类,它做的是就是解析调用者传递的参数,构建出一个 Request 然后开始执行后续的启动 Activity 逻辑。

# ActivityStartController// 返回ActivityStarterActivityStarter 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;}// 设置ActivityInfoActivityStarter 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步:

  1. 解析获取activityInfo
  2. 执行后续启动逻辑
ActivityStarter$RequestResolveInfo resolveInfo;ActivityInfo activityInfo;void resolveActivity(ActivityTaskSupervisor supervisor) {......// 解析resolveInforesolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,0 /* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),realCallingPid);......// 解析resolveInfoactivityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,profilerInfo);......}

activityInfo的解析

ActivityStarter$RequestResolveInfo resolveInfo;ActivityInfo activityInfo;void resolveActivity(ActivityTaskSupervisor supervisor) {......// 解析resolveInforesolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,0 /* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),realCallingPid);......// 解析resolveInfoactivityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,profilerInfo);......}

TargetActivity 所在的进程包名和 TargetActivity 的完整路径都在 activityInfo 中,这个解析方法也是一个核心点。

创建ActivityRecord

ActivityStarter::executeRequest 是一个需要注意的方法,因为内部会创建 ActivityRecord 对象,而这个 ActivityRecord 对象持有 token ,这个 token 就是以后分析其他逻辑一直会出现的 token 。也可以说是 system_service 中一个 Activity 的唯一标识。

应用进程中的 Activity 在 AMS 的代表就是 ActivityRecord 。

# ActivityStarterprivate 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. 构造出一个ActivityRecordfinal 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. 继续执行startActivityUncheckedmLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,inTask, inTaskFragment, restrictedBgActivity, intentGrants);......}

3个注意点:
1、虽然是个日志,但是也很关键,一般分析日志看启动了哪个 Activity 就搜“START u” ,打印的地方就在这。另外发现 U 版本上这一块还做了改变。
2、构建出一个 ActivityRecord 对象
3、继续执行主流程

主要看ActivityRecord 是怎么创建的:

# ActivityRecordprivate ActivityRecord(ActivityTaskManagerService _service, ......) {// 调用父类,创建 Tokensuper(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,null /* displayContent */, false /* ownerCanManageAppTokens */);......packageName = info.applicationInfo.packageName;.....}

这里的重点其实就是创建了一个匿名 Token 然后传递到了父类的构建方法, ActivityRecord 的父类是 WindowToken。

# WindowTokenprotected 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 ,这个方法是流程的关键点。

窗口层级树的处理

ActivityStarter::startActivityInner 是 Activity 启动流程最重要的函数之一,这里涉及到【窗口层级树】相关知识,上一小节说了 ActivityRecord 创建好后并不会和 WindowToken 一样挂载到层级树中,而是需要单独处理,本小节就是看这一块是如何处理的。
先看看正常在 Launcher 界面时和启动“电话”后的层级树对比。

在这里插入图片描述
这里首先多了3个东西:
1、Task
2、上一步创建的 ActivityRecord
3、WindowState

另外这个 Task 还移动到了DefaultTaskDisplayArea的最顶部,这里涉及到的操作如下:
1、创建Task
2、ActivityRecord 挂在到这个 Task 下
3、将这个 Task 移动到最上面

至于最下面的那个 546fce2 为什么是 WindowState 对象,又是怎么挂在到 ActivityRecord 上的,这个属于窗口显示第一步,后边再说。

继续主流程代码:

# 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 casesprivate 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,最终也为nullfinal Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();// 那么newTask为true, 表示需要新建一个taskfinal boolean newTask = targetTask == null;// 同样为nullmTargetTask = targetTask;......if (mTargetRootTask == null) {// 重点* 1. 创建Task   23mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,mOptions);}if (newTask) {// taskToAffiliate 为nullfinal 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 一般为默认值 falsemRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);}......}
  1. 创建 Task
    • 我们知道 ActivityRecord 需要挂载到一个 Task 下,虽然这里调用的方法名是 getOrCreateRootTask(获取或者创建Task),但是当前场景肯定是创建一个,热启动是获取。
    • 另外 Task 创建的时候就会挂载到层级树中,也就是会挂载到DefaultTaskDisplayArea 下
  2. 将 ActivityRecord 挂载到创建的 Task 下
    • 上一小节没做的事,在这里就完成了挂载
  3. 移动 Task 到栈顶
    • 因为这个新启动的 Activity 需要显示,所以需要将它所在的 Task 移到容器顶部。 不过当前场景建好就已经是栈顶了,其实这一步没做什么,这点后面代码会分析
  4. 显示顶部的 Activity
    • 窗口层级的处理好了,就可以处理显示逻辑了,这里后续的逻辑会触发 Activity 的启动

获取Task–getOrCreateRootTask

调用链

ActivityStarter::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTask::Build     ---创建Task

代码:

# ActivityStarterprivate 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);}

1、onTop 表示是否要移到到当前栈顶,那肯定是要的,新启动的 Activity 当前要在最上面,这里 aOptions 为 null ,所以为 true
2、sourceTask 表示从哪里启动的,当前 Launcher 所在的 Task 就是 sourceTask

然后开始获取一个 Task 如果没有就新建一个。

# RootWindowContainerTask 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. 传递到TaskDisplayAreareturn taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,sourceTask, launchParams, launchFlags, activityType, onTop);} else {taskDisplayArea = null;}}......}

经过同名方法调用后,逻辑进入到 TaskDisplayArea::getOrCreateRootTask 。

# TaskDisplayAreaTask getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,@Nullable Task candidateTask, @Nullable Task sourceTask,@Nullable ActivityOptions options, int launchFlags) {if(....) {// 拿到之前创建的Taskreturn candidateTask.getRootTask();}......// 第一次显示所以是新建Taskreturn 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的创建:

# Task# Task.BuilderTask build() {if (mParent != null && mParent instanceof TaskDisplayArea) {validateRootTask((TaskDisplayArea) mParent);}......// 重点* 1. 创建taskfinal 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 为trueif (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个重点部分:
1、看到通过 buildInner 创建了一个 Task,而 buildInner 也很简单粗暴,通过各个变量直接 new 出一个 Task 对象。
2、mParent 不为 null ,是因为在创建的时候 setParent(this),当前的这个 this 就是 getDefaultTaskDisplayArea 返回的。就是 37层的第二层应用 Activity 存在的"DefaultTaskDisplayArea"

在 RootWindowContainer::getOrCreateRootTask 体现。
在这里插入图片描述
注意 log 里的 #17 的这个 Task 与前面的层级结构树新增的 Task 是对应的上的。而且"this= DefaultTaskDisplayArea "说明也确实是往 DefaultTaskDisplayArea 里添加了。
另外 log 里 index 为3,结合最上面的前后对比,说明也的往顶部添加。

ActivityRecord挂载到Task–setNewTask

# ActivityStarerprivate void setNewTask(Task taskToAffiliate) {// 为truefinal boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;// 就是mTargetRootTask,也就是刚刚创建的Taskfinal 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 。

# ActivityStarerprivate void addOrReparentStartingActivity(@NonNull Task task, String reason) {//  newParent = task 都是刚刚创建的TaskTaskFragment 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 ,可以确认 ActivityStarer::setNewTask 做的事情就是将 ActivityRecord 挂在到 Task 中,而且在顶部。

移动Task到容器顶部–moveToFront

这里提一下这个 moveToFront 方法,因为前面创建 Task 并添加到 DefaultTaskDisplayArea 时是往顶部添加,后面将 ActivityRecord 挂在到 Task 也是挂在到其顶部。所以这个函数其实没有什么实际操作。但是对于其他场景,这里也是一个重点方法。

Task::moveToFrontTask::moveToFrontInnerTaskDisplayArea::positionChildAtTaskDisplayArea::positionChildTaskAtActivityTaskSupervisor::updateTopResumedActivityIfNeededActivityRecord::onTopResumedActivityChanged      --触发TopResumedActivityChangeItem

首先确定一个问题:需要移动到顶部的是哪个 Task ? 这个 Task 所在的是在哪个哪个容器? 在 ActivityStarter::startActivityInner 的时候调用的是这段代码:

// targetTask 当前场景为null
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);

已知 mTargetRootTask 是新创建给“电话”用的 Task, 而 mTargetRootTask.getRootTask() 返回值当前场景是 mTargetRootTask 本身。

# Taskvoid 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 也就是电话的 Tasktask = 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 启动和显示逻辑了

显示Activity–resumeFocusedTasksTopActivities

首先看方法名目的需要显示一个栈顶的 Activity ,那说的不就是 TargetActivity 嘛,TargetActivity 的 ActivityRecord 已经创建并且移动到栈顶了。
前面该做的也都做好了,现在也确实是时候处理显示逻辑,这部分流程由 RootWindowContainer::resumeFocusedTasksTopActivities 执行,调用链如下:

RootWindowContainer::resumeFocusedTasksTopActivitiesTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivity TaskDisplayArea::pauseBackTasks  --   pause LauncherActivity WindowContainer::forAllLeafTaskTaskFragment::forAllLeafTaskFragmentsTaskFragment::startPausingTaskFragment::startPausingTaskFragment::schedulePauseActivity --构建 PauseActivityItem,这里是触发暂停launchActivityTaskManagerService::startProcessAsync     -- 创建“电话”进程

重点方法在 TaskFragment::resumeTopActivity 开始处理,先简单看一下前面的调用是怎么样的。

# RootWindowContainer// 第四个参数为 falseboolean resumeFocusedTasksTopActivities(Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,boolean deferPause) {......if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()|| getTopDisplayFocusedRootTask() == targetRootTask)) {result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,deferPause);}......}
# Taskboolean 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 = falseresumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);......}

TaskFragment::resumeTopActivity 方法是 FrameWork 中非常常见的一个方法,方法名和它的功能是一样的:显示顶层 Activity 。
抛开多窗口场景,设备上显示 Activity 的逻辑就是显示 DefaultTaskDisplayArea 下的顶层 Task 中的顶层 Activity ,代码流程有很多场景都可能会导致屏幕显示内容的修改,也就需要执行当前方法来确保屏幕上有一个正确的 Activity 显示。
以后会经常看到这个方法,当前还是只分析 Launcher 启动“电话”的场景来看看执行逻辑。

# TaskFragmentfinal boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,boolean deferPause) {// 这里的next返回的是电话的 MainActivity,表示下一个需要显示的ActivityActivityRecord next = topRunningActivity(true /* focusableOnly */);......// 如果跳过的这些逻辑都没执行return,则正在开始执行 resume 流程,打印关键日志。    // 前面流程如果返回也有日志的打印// 打印日志,需要显示哪个Activityif (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);......// 重点* 1. 这里会将 Launcher 的Activity pause 。参数是电话的 ActivityRecord// 注意 1:如果有 Activity 被 pauseBackTasks 方法触发了 pause,则返回 true,表示有 Activity 正在 pausingboolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);......if (pausing) {ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"+ " start pausing");if (next.attachedToProcess()) {......} else if (!next.isProcessRunning()) {// 重点*2. 进程没有运行,则触发异步创建进程。 当前逻辑肯定是执行这一条final boolean isTop = this == taskDisplayArea.getFocusedRootTask();mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY: HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);}......// 注意2:这里会returnreturn true;} else if ............//后面还有重要逻辑,当前可忽略   }

上面说过这个函数非常复杂,在当前逻辑有2个主线:

  1. pause 当前 Activity 也就是 Launcher
  2. 异步创建“电话”的进程

在第一步将 Launcher 的 Activity 执行 pause ,这一步执行到最后也会触发"电话"应用 MainActivity 的启动。
第二步创建“电话”进程,进程创建完肯定也会执行"电话"应用 MainActivity 的启动,这么看来就有2个地方触发了。
这是因为是异步创建进程,不知道谁先执行完,但是可以明确的是,"电话"应用 MainActivity 必须有2个条件:

  1. 前一个Activity执行完pause
  2. 进程创建完成

所以无论2个分支哪一个先执行完,都需要等后一个执行完的来触发后续电话"应用 MainActivity 的启动。 这个方法还有2个需要注意的地方:

变量 pausing 表示当前是否正在执行 Activity 的 pause 流程。这个值受2个因素影响,先看 Launcher 的 pause 流程。

pause 流程–pauseBackTasks

需要显示新的 Activity 那之前的 Activity 肯定是要执行 pause ,参数 next 为“电话”的 ActivityRecord 。 这一步主要是触发 SourceActivity 的pause 逻辑。

# TaskDisplayArea// 可以看到“电话”ActivityRecord在这里就被称为resumingboolean pauseBackTasks(ActivityRecord resuming) {final int[] someActivityPaused = {0};forAllLeafTasks(leafTask -> {// Check if the direct child resumed activity in the leaf task needed to be paused if// the leaf task is not a leaf task fragment.if (!leafTask.isLeafTaskFragment()) {// 当前不会走这里......}leafTask.forAllLeafTaskFragments((taskFrag) -> {final ActivityRecord resumedActivity = taskFrag.getResumedActivity();if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {someActivityPaused[0]++;}}}, true /* traverseTopToBottom */);}, true /* traverseTopToBottom */);return someActivityPaused[0] > 0;}

forAllLeafTasks 和 forAllLeafTaskFragments 在WMS/AMS 常见方法调用提取有解释,那么当前这段方法其实就是让 DefaultTaskDisplayArea 下的每个叶子 LeafTaskFragments 执行 startPausing 。

# TaskFragmentboolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,String reason) {......// 日志输出当前 TaskFragment 和 mResumedActivity 的关系。后面会贴上日志证明// 注意这里的是需要 pause 的,不是需要 resume 的ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,mResumedActivity);......// 后面的prev就是launcher的ActivityRecord了ActivityRecord prev = mResumedActivity;......// 输出日志ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);mPausingActivity = prev;......// 设置window状态为PAUSINGprev.setState(PAUSING, "startPausingLocked");prev.getTask().touchActiveTime();......if (prev.attachedToProcess()) {// launcher的进程肯定是满足启动条件的if (shouldAutoPip) {// 当前场景与画中画模式无关,不走这boolean didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "+ "directly: %s, didAutoPip: %b", prev, didAutoPip);} else {// 重点*1. 上面的PIP日志没输出,肯定走的是这schedulePauseActivity(prev, userLeaving, pauseImmediately,false /* autoEnteringPip */, reason);}}......}void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,boolean pauseImmediately, boolean autoEnteringPip, String reason) {// 输出日志ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);try {// 输出events 日志EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),prev.shortComponentName, "userLeaving=" + userLeaving, reason);// 重点* 构建并执行PauseActivityItemmAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,prev.configChangeFlags, pauseImmediately, autoEnteringPip));} catch (Exception e) {......}}

最终在 TaskFragment::schedulePauseActivity 构建 PauseActivityItem 并执行了 Launcher 的 pause 事件。

这块相关的日志输入如图:

在这里插入图片描述

PauseActivityItem

触发 pause 流程就是通过 PauseActivityItem 这个触发的。

# PauseActivityItem@Overridepublic void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");// 重点*1. 触发 handlePauseActivity 流程client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions,"PAUSE_ACTIVITY_ITEM");Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}@Overridepublic int getTargetState() {return ON_PAUSE;}//  pauser执行后调用 postExecute@Overridepublic void postExecute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {if (mDontReport) {return;}//  重点*2. 触发启动新的ActivityActivityClient.getInstance().activityPaused(token);}

这里先执行 execute 方法也就是 Launcher 的 pause 流程,这个不是主线,可以移步Activity生命周期之onPause。

然后执行 postExecute,这里会触发新 Activity 的启动,这个流程就是阶段二。

# ActivityClientpublic void activityPaused(IBinder token) {try {getActivityClientController().activityPaused(token);} catch (RemoteException e) {e.rethrowFromSystemServer();}}

阶段一总结

本篇对整个 Activity 启动流程做了介绍,然后重点分析第一阶段的事情,这一阶段的二级框图如下:
在这里插入图片描述
1、在 Launcher 进程构建了启动参数放在了 ActivityOption 中,然后通过 Bundle 传递给 system_service 端

2、AMS 先解析参数,放在了 Request 这个类中保存

3、AMS 构建出一个 ActivityRecord ,这个类在 system_service 端就代表着 Activity ,同时也是一个窗口容器

4、再构建出一个 Task 挂载到窗口树上

5、将 ActivityRecord 挂载到 Task 中,这样 ActivityRecord 也就挂载到窗口层级树中了

6、触发 Launcher 执行 pause 逻辑,也就是阶段二

7、触发 TargetActivity 所在的进程创建,也就是阶段三

system_service 处理的完整堆栈

ActivityTaskManagerService::startActivityActivityTaskManagerService::startActivityAsUserActivityTaskManagerService::startActivityAsUserActivityStartController::obtainStarterActivityStarter::executeActivityStarter$Request::resolveActivity           -- 解析启动请求参数ActivityTaskSupervisor::resolveIntentActivityTaskSupervisor::resolveActivityActivityStarter::executeRequest                    -- 3.3 创建ActivityRecordActivityStarter::startActivityUncheckedActivityStarter::startActivityInner        -- 3.4 关键函数startActivityInnerActivityStarter::getOrCreateRootTask   -- 3.4.1 创建或者拿到TaskRootWindowContainer::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTask::Build     ---创建Task                    ActivityStarter::setNewTask            -- 3.4.2Task与activityRecord 绑定ActivityStarer::addOrReparentStartingActivityTask::moveToFront                       --3.4.3 移动Task到栈顶Task::moveToFrontInnerTaskDisplayArea::positionChildAtTaskDisplayArea::positionChildTaskAtActivityTaskSupervisor::updateTopResumedActivityIfNeededActivityRecord::onTopResumedActivityChanged      --触发TopResumedActivityChangeItemRootWindowContainer::resumeFocusedTasksTopActivities    --3.4.4 显示ActivityTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivity      -- 1. 显示顶层ActivityTaskDisplayArea::pauseBackTasks  -- 1.2 pause LauncherActivity WindowContainer::forAllLeafTaskTaskFragment::forAllLeafTaskFragmentsTaskFragment::startPausingTaskFragment::startPausingTaskFragment::schedulePauseActivity --构建 PauseActivityItem,这里是触发暂停launchActivityTaskManagerService::startProcessAsync     -- 1.3 创建“电话”进程

第二阶段–completePause

应用完成 Pause 会执行 ActivityClientController::activityPaused 来通知 system_service 当前分析主流程继续看 completePause 的后续逻辑,这部分调用链如下:

ActivityClientController::activityPausedActivityRecord::activityPausedTaskFragment::completePauseRootWindowContainer::resumeFocusedTasksTopActivities       -- 显示顶层ActivityRootWindowContainer::resumeFocusedTasksTopActivitiesTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivityActivityTaskSupervisor::startSpecificActivity        -- 试图启动 ActivityRootWindowContainer::ensureActivitiesVisible              -- 确保设备上 Activity 的可见性RootWindowContainer::ensureActivitiesVisibleDisplayContent::ensureActivitiesVisible WindowContainer::forAllRootTasks  --忽略固定逻辑Task::ensureActivitiesVisibleTask::forAllLeafTasks --忽略固定逻辑TaskFragment::updateActivityVisibilitiesEnsureActivitiesVisibleHelper::processEnsureActivitiesVisibleHelper::setActivityVisibilityStateEnsureActivitiesVisibleHelper::makeVisibleAndRestartIfNeededActivityTaskSupervisor::startSpecificActivity       -- 试图启动 Activity

之前看了第一阶段的窗口图:
在这里插入图片描述
冷启动的目标肯定是希望最后显示的是 TargetActivity ,也就是下面这图的状态:
在这里插入图片描述
其实在 system_service 这边的 DefaultTaskDisplayArea 并没有变化,只是用户看到的 Activity 变成了 TargetActivity 。
要实现这个最终状态就是需要目标应用端创建 TargetActivity 。而要触发这一步骤是2个条件就是:

  • 其他Activity完成pause
  • TargetActivity进程在运行

所以现在看到的阶段二就一直在试图来启动 TargetActivity ,这一阶段的大概流程图如下:
在这里插入图片描述

可以看到对应代码 TaskFragment::completePause 后有2个流程都试图执行 ActivityTaskSupervisor::startSpecificActivity 来启动 TargetActivity。

  • 如果在 resumeFocusedTasksTopActivities 流程的时候进程启动了,则会走完触发 TargetActivity 的启动逻辑。如果进程还未启动,则会在 startSpecificActivity 方法里触发一下创建进程
  • resumeFocusedTasksTopActivities 流程执行完后会执行 ensureActivitiesVisible 流程来遍历整个手机系统的所有 Activity 处理他们的可见性,如果这个时候发现顶层 Activity 的ActivityRecord::attachedToProcess 返回false,则又会执行到 startSpecificActivity 。否则会根据具体情况处理一下其可见性。

理论知识建设完毕,下面来说跟代码,从 ActivityRecord::activityPaused 方法开始。

ActivityRecord::activityPaused

# ActivityRecordvoid activityPaused(boolean timeout) {......if (pausingActivity == this) {// 打印日志ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,(timeout ? "(due to timeout)" : " (pause complete)"));mAtmService.deferWindowLayout();try {// 注意2个产出taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);} finally {mAtmService.continueWindowLayout();}return;} else ............}

流程来到 TaskFragment::completePause ,注意传递过来的参数分别为 true 和 null 。

# TaskFragment@VisibleForTestingvoid completePause(boolean resumeNext, ActivityRecord resuming) {// 拿到之前的Activity,也就是需要 pause 的ActivityRecord prev = mPausingActivity;ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);if (prev != null) {......// 设置 SourceActivity 对应的ActivityRecord 状态为PAUSEDprev.setState(PAUSED, "completePausedLocked");if (prev.finishing) {...... 如果已经finish的处理,上面还在设置 pause,那正常应该是还没finish} else if (prev.hasProcess()) {// 打印状态日志ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "+ "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,prev.mVisibleRequested);......}else {......}if (resumeNext) {......// 重点*1. 第1个分支mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,null /* targetOptions */);......} else {......}......// 重点*2. 确保设置所有Activity正确的可见性,注意是3个参数的,且第一个参数为nullmRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);......}}

这里的 topRootTask 就是 SourceActivity “电话”的 Activity, prev 是 launcher 的 ActivityRecord , resuming 为null。 这里又分为2步走了。

第一步–resumeFocusedTasksTopActivities

执行过来的流程是上一个 Activity 完成了 pause ,那说明需要显示一个新的 Activity ,显示哪个呢?
自然是最前面的 Task 下的 最前面的 Activity ,下面看看代码中是如何实现这一步的。
直接的调用链之前看过了,所有直接看 TaskFragment::resumeTopActivity 方法,这个方法之前也看过,但是这次的逻辑肯定不一样了。

# TaskFragmentfinal boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,boolean deferPause) {......// 这一次没有要 pause 的Activity了,所以为falseboolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);......if (pausing) {......return true;}......// ActivityRecord 下的 app 变量是否有值,并且进程已经执行if (next.attachedToProcess()) {if (DEBUG_SWITCH) {// 日志Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped+ " visibleRequested=" + next.isVisibleRequested());}......} else {......// 打印logProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);// 重点* 执行startSpecificActivity mTaskSupervisor.startSpecificActivity(next, true, true);......}return true;}

这一次执行 TaskFragment::resumeTopActivity 方法和之前还说有区别的,首先由于这一次没有要 pause 的 Activity 了,所以 pausing = false ,也就不会走 “if (pausing)” 内部逻辑。
走的是下面的 ActivityTaskSupervisor::startSpecificActivity 试图启动 TargetActivity ,至于最后是不是真的能启动,还是要看进程起来没。

这一步会打印日志:
WindowManager: resumeTopActivity: Restarting ActivityRecord{1cf0e8 u0 com.google.android.apps.messaging/.ui.ConversationListActivity t30}

关键方法–startSpecificActivity

这个方法已经提过多次了,简单说目的是想去让应用端启动 Activity ,但是如果可能应用端进程还没创建,就会触发进程创建。

# ActivityTaskSupervisorfinal ActivityTaskManagerService mService;void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {// Is this activity's application already running?// 拿到目标进程信息final WindowProcessController wpc =mService.getProcessController(r.processName, r.info.applicationInfo.uid);boolean knownToBeDead = false;// 重点* 1. 进程是否存在,且主线程已执行if (wpc != null && wpc.hasThread()) {try {// 进程存在 则执行 realStartActivityLocked 流程realStartActivityLocked(r, wpc, andResume, checkConfig);// 重点* 会返回return;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);1111111111}......}......// 重点* 2. 触发启动进程mService.startProcessAsync(r, knownToBeDead, isTop,isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY: HostingRecord.HOSTING_TYPE_ACTIVITY);}

以当前分析的条件,肯定又是触发进程创建了,所以 ActivityTaskSupervisor::realStartActivityLocked 暂时就先不看了。

第二步–ensureActivitiesVisible 流程

前面看了 resumeFocusedTasksTopActivities 的流程,挺简单的,目前暂且假设因为进程没启动,所以没有触发 TargetActivity 的启动,现在继续看 ensureActivitiesVisible 流程。
这个方法的目的之前也说过了,就是确保一下手机上所有的 Activity 的正确可见性,也就是遍历所有 Task 下的所有 ActivityRecord 然后根据对应的条件处理想要的可见性。

# RootWindowContainer// starting = null  configChanges = 0  preserveWindows = falsevoid ensureActivitiesVisible(ActivityRecord starting, int configChanges,boolean preserveWindows) {ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);}void ensureActivitiesVisible(ActivityRecord starting, int configChanges,boolean preserveWindows, boolean notifyClients) {// 已经正常处理可见性就不重复执行了if (mTaskSupervisor.inActivityVisibilityUpdate()|| mTaskSupervisor.isRootVisibilityUpdateDeferred()) {// Don't do recursive work.return;}try {// 开始处理mTaskSupervisor.beginActivityVisibilityUpdate();// First the front root tasks. In case any are not fullscreen and are in front of home.// 遍历屏幕for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {final DisplayContent display = getChildAt(displayNdx);display.ensureActivitiesVisible(starting, configChanges, preserveWindows,notifyClients);}} finally {// 处理结束mTaskSupervisor.endActivityVisibilityUpdate();}}

遍历所有屏幕

# DisplayContentvoid ensureActivitiesVisible(ActivityRecord starting, int configChanges,boolean preserveWindows, boolean notifyClients) {......mInEnsureActivitiesVisible = true;mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();try {forAllRootTasks(rootTask -> {// 遍历所有根 Task rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,notifyClients);});......} finally {mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();mInEnsureActivitiesVisible = false;}}

遍历所有根 Task ,使其执行 ensureActivitiesVisible 方法

# Taskvoid ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,boolean preserveWindows, boolean notifyClients) {mTaskSupervisor.beginActivityVisibilityUpdate();try {// 遍历每个叶子TaskforAllLeafTasks(task -> {task.updateActivityVisibilities(starting, configChanges, preserveWindows,notifyClients);}, true /* traverseTopToBottom */);......} finally {mTaskSupervisor.endActivityVisibilityUpdate();}}

遍历所有叶子 Task ,使其执行 updateActivityVisibilities 方法,这个方法定义在父类 TaskFragmet 中。

# TaskFragmet// 帮助类private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =new EnsureActivitiesVisibleHelper(this);final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges,boolean preserveWindows, boolean notifyClients) {mTaskSupervisor.beginActivityVisibilityUpdate();try {// 重点处理mEnsureActivitiesVisibleHelper.process(starting, configChanges, preserveWindows, notifyClients);} finally {mTaskSupervisor.endActivityVisibilityUpdate();}}

我们知道这一条线都是为了处理Activity可见的。 在这定义了一个专门的类来处理。 不过需要注意的是,这个方法会执行多次,因为他是遍历每一个符合条件的子容器,从上到下遍历。

阶段二总结

阶段二的逻辑其实比较简单,其实就是 SourceActivity 完成 pause 后,执行 ActivityRecord::activityPaused 流程,AMS 需要显示当前顶层 Activity 所以执行了 RootWindowContainer::resumeFocusedTasksTopActivities 方法,但是这一次是不是真的能显示顶层 Activity 还是要看其进程是否已经创建好了。
在操作了 Activity 的显示逻辑后,为了确保系统 Activity 正常的可见性,所以又执行了一次 ensureActivitiesVisible 流程。
流程相对简单,就是下面这个图:
在这里插入图片描述

第三阶段:触发目标应用进程创建

执行pause后会执行 ActivityTaskManagerService::startProcessAsync,最后也是通过 ActivityManagerService来触发启动进程的。 看看AMS这块执行进程创建的调用流程。

# ActivityTaskManagerServicevoid startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,String hostingType) {try {if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"+ activity.processName);}// 发送消息,启动进程,调用 ActivityManagerInternal::startProcessfinal Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,isTop, hostingType, activity.intent.getComponent());mH.sendMessage(m);} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}

这里通过 Handler 来完成,ActivityManagerInternal::startProcess 的实现在 ActivityManagerService 的内部类 LocalService 中。

# ActivityManagerService$LocalServicepublic void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,boolean isTop, String hostingType, ComponentName hostingName) {try {if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"+ processName);}synchronized (ActivityManagerService.this) {// 继续调用startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,new HostingRecord(hostingType, hostingName, isTop),ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,false /* isolated */);}} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}@GuardedBy("this")final ProcessRecord startProcessLocked(String processName,ApplicationInfo info, boolean knownToBeDead, int intentFlags,HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,boolean isolated) {return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,null /* sdkSandboxClientAppPackage */,null /* ABI override */, null /* entryPoint */,null /* entryPointArgs */, null /* crashHandler */);}

流程走到:ProcessList::startProcessLocked

# ProcessListboolean startProcessLocked(......) {......mService.mProcStartHandler.post(() -> handleProcessStart(app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,requiredAbi, instructionSet, invokeWith, startSeq));     ......   }private void handleProcessStart(......) {创建一个用于启动进程的 Runnable 对象final Runnable startRunnable = () -> {try {    // 调用 startProcess 方法启动进程,并获取启动结果 ProcessStartResultfinal Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,app.getStartTime());// 在锁定 ActivityManagerService 后,处理进程启动结果synchronized (mService) {// 更新应用的状态,如设置PID,更新生命周期状态等handleProcessStartedLocked(app, startResult, startSeq);}} catch (RuntimeException e) {......异常处理}};......}

通过 ProcessList::startProcess 来启动应用进程
启动玩之后 ProcessList::handleProcessStartedLocked 会更新应用的状态,如设置PID,更新生命周期状态等。

# ProcessListboolean startProcessLocked(......) {......mService.mProcStartHandler.post(() -> handleProcessStart(app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,requiredAbi, instructionSet, invokeWith, startSeq));     ......   }private void handleProcessStart(......) {创建一个用于启动进程的 Runnable 对象final Runnable startRunnable = () -> {try {    // 调用 startProcess 方法启动进程,并获取启动结果 ProcessStartResultfinal Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,app.getStartTime());// 在锁定 ActivityManagerService 后,处理进程启动结果synchronized (mService) {// 更新应用的状态,如设置PID,更新生命周期状态等handleProcessStartedLocked(app, startResult, startSeq);}} catch (RuntimeException e) {......异常处理}};......}

1、通过 ProcessList::startProcess 来启动应用进程
2、启动玩之后 ProcessList::handleProcessStartedLocked 会更新应用的状态,如设置PID,更新生命周期状态等

ProcessList::handleProcessStartedLocked 经过几次重载会调用下面的方法

# ProcessListActivityManagerService mService = null;boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,long expectedStartSeq, boolean procAttached) {......StringBuilder buf = mStringBuilder;buf.append("Start proc ");buf.append(pid);buf.append(':');buf.append(app.processName);buf.append('/');UserHandle.formatUid(buf, app.getStartUid());if (app.getIsolatedEntryPoint() != null) {buf.append(" [");buf.append(app.getIsolatedEntryPoint());buf.append("]");}buf.append(" for ");buf.append(app.getHostingRecord().getType());if (app.getHostingRecord().getName() != null) {buf.append(" ");buf.append(app.getHostingRecord().getName());}// 输出日志mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.getStartUid());......}

创建进程会打印一些关键日志:

07-26 19:19:05.477 8737 8782 I ActivityManager: Start proc 19643:com.example.myapplication/u0a198 for next-top-activity {com.example.myapplication/com.example.myapplication.MainActivity}

经常看日志看启动了哪个进程搜的日志就是在这里打印的。

这部分调用链如下:

ActivityTaskManagerService::startProcessAsyncActivityManagerService$LocalService::startProcessActivityManagerService::startProcessLockedProcessList::startProcessLockedProcessList::handleProcessStartProcessList::startProcess                               -- 启动进程ProcessList::handleProcessStartedLockedActivityManagerService::reportUidInfoMessageLocked  -- 打印日志

应用进程创建

进程创建完成后会执行 ActivityThread::main 方法,所以应用端进程创建结束的逻辑从这个方法开始分析。

# ActivityThread// ApplicationThread 是 AMS 作为 C 端时,与应用进程通信的方式final ApplicationThread mAppThread = new ApplicationThread();public static void main(String[] args) {......// 主线程LooperLooper.prepareMainLooper();......ActivityThread thread = new ActivityThread();// 下一步thread.attach(false, startSeq);// 主线程LooperLooper.loop();}private void attach(boolean system, long startSeq) {......final IActivityManager mgr = ActivityManager.getService();try {//重点 *2. 将mAppThread告知AMS,用于AMS与应用进程通信mgr.attachApplication(mAppThread, startSeq);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}......}

应用端的调用链比较简单:

ActivityThread::mainLooper::prepareMainLooperActivityThread::initActivityThread::attachActivityManagerService::attachApplication  -- 跨进程Looper::loop

应用进程(电话)创建完毕后,在 main 方法里会执行 attach 就是要将自己的信息告知AMS,毕竟 AMS 是管理模块。

system_service端处理

system_service 端 ActivityManagerService 知道有进程启动了,这个行为也可能会触发系统组显示逻辑的改变,所以比如也会做响应处理

ActivityManagerService::attachApplicationActivityManagerService::attachApplicationLockedActivityThread::bindApplicationActivityTaskManagerService.LocalService::attachApplication  WindowContainer::forAllRootTasks  --- 省略forAllRootTasks等固定堆栈Task::forAllRootTasksWindowContainer::forAllActivitiesActivityRecord::forAllActivitiesRootWindowContainer.AttachApplicationHelper::testRootWindowContainer.AttachApplicationHelper::testActivityTaskSupervisor::realStartActivityLocked  -- 构建LaunchActivityItem

在这里插入图片描述
接上一篇知道如果进程启动了 ActivityTaskSupervisor::startSpecificActivity 就会走进去ActivityTaskSupervisor::realStartActivityLocked 。
但是可能会好奇怎么就知道要执行应用 MainActivity 到 onCreate 就一定是在这个方法里呢? 调试方法有很多,比如加 log ,打堆栈,但是对应这个逻辑比较简单的是,需要执行 Activity 启动到 onCreate 的控制在 LaunchActivityItem 中,而 LaunchActivityItem在 framework 的引用除了本身,就只有在 ActivityTaskSupervisor。
在这里插入图片描述

# ActivityManagerService// 当应用进程调用attachApplication 执行public final void attachApplication(IApplicationThread thread, long startSeq) {if (thread == null) {throw new SecurityException("Invalid application interface");}synchronized (this) {// 获取 应用进程的信息后执行attachApplicationLockedint callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();// 执行attachApplicationLocked(thread, callingPid, callingUid, startSeq);Binder.restoreCallingIdentity(origId);}}private boolean attachApplicationLocked(@NonNull IApplicationThread thread,int pid, int callingUid, long startSeq) {// 需要启动应用的进程数据ProcessRecord app;......if (pid != MY_PID && pid >= 0) {synchronized (mPidsSelfLocked) {// 通过mPidsSelfLocked获取app = mPidsSelfLocked.get(pid);}......} ...... // 触发ActivityThread::bindApplication 逻辑if (app.getIsolatedEntryPoint() != null) {......} else if (instr2 != null) {// bindApplication......    } else {// 重点* 1. bindApplicationthread.bindApplication(processName, appInfo,app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,providerList, null, profilerInfo, null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.getCompat(), getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions,app.getDisabledCompatChanges(), serializedSystemFontMap,app.getStartElapsedTime(), app.getStartUptime());}......if (!mConstants.mEnableWaitForFinishAttachApplication) {// 重点* 2. finishAttachApplicationInner(startSeq, callingUid, pid);} else {app.setPendingFinishAttach(true);}......}

ActivityManagerService::finishAttachApplicationInner 是 U 把原来的逻辑提取新增的方法。

# ActivityManagerServicepublic ActivityTaskManagerInternal mAtmInternal;private void finishAttachApplicationInner(long startSeq, int uid, int pid) {......if (normalMode) {try {// 重点 触发构建 LaunchActivityItem 流程didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());} catch (Exception e) {Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);badApp = true;}}......}

这里是触发 LaunchActivityItem 的流程主线, mAtmInternal是 ATMS 的内部类 LocalService

# ActivityTaskManagerService$LocalService@Overridepublic boolean attachApplication(WindowProcessController wpc) throws RemoteException {......return mRootWindowContainer.attachApplication(wpc);......}

流程来到 RootWindowContainer 预感要开始处理窗口显示逻辑。

# RootWindowContainerprivate final AttachApplicationHelper mAttachApplicationHelper = new AttachApplicationHelper();boolean attachApplication(WindowProcessController app) throws RemoteException {try {return mAttachApplicationHelper.process(app);} finally {mAttachApplicationHelper.reset();}}# RootWindowContainer// 实现 Consumer 接口private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {......boolean process(WindowProcessController app) throws RemoteException {mApp = app;for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {// 重点* 调用每个容器的 forAllRootTasksgetChildAt(displayNdx).forAllRootTasks(this);......}......}......}

这里看到传递了“this”,所以 AttachApplicationHelper 必然实现了 Consumer 接口, 直接看其 accept 实现即可。

# RootWindowContainer$AttachApplicationHelperprivate class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {......boolean process(WindowProcessController app) throws RemoteException {mApp = app;for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {// 重点*1. 调用每个容器的 forAllRootTasksgetChildAt(displayNdx).forAllRootTasks(this);......}......}@Overridepublic void accept(Task rootTask) {......if (rootTask.getVisibility(null /* starting */)== TASK_FRAGMENT_VISIBILITY_INVISIBLE) {// 如果Task 不可见则不需要处理return;}// 执行 topRunningActivitymTop = rootTask.topRunningActivity();// 重点*2. 执行accept 让容器下的每个 ActivityRecord 执行 testrootTask.forAllActivities(this);}@Overridepublic boolean test(ActivityRecord r) {// 判断 ActivityRecord 是否满足需要启动条件if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard|| r.app != null || mApp.mUid != r.info.applicationInfo.uid|| !mApp.mName.equals(r.processName)) {return false;}try {// 重点*3. 执行 realStartActivityLocked  尝试实际启动 Activityif (mTaskSupervisor.realStartActivityLocked(r, mApp,mTop == r && r.getTask().canBeResumed(r) /* andResume */,true /* checkConfig */)) {mHasActivityStarted = true;}} catch (RemoteException e) {......}return false;}}

这部分的逻辑也就是一路执行,比较疑惑的点也许是进入 AttachApplicationHelper::proces 方法后的几个 Lambda 表达式容易绕晕。
简单梳理一下,首先是从 RootWindowContainer 开始执行的,目的就是想要执行到所有 ActivityRecord 然后判断一下它的情况是不是需要启动对应的 Activity 。

阶段三总结

阶段三的流程相对来逻辑简单一些,知道个调用链就好,流程目的就是执行 ActivityTaskSupervisor::realStartActivityLocked 。
这部分的堆栈如下图:
在这里插入图片描述
加上应用端的调用链,完成调用链如下:

ActivityThread::mainLooper::prepareMainLooperActivityThread::initActivityThread::attachActivityManagerService::attachApplication  -- 跨进程ActivityManagerService::attachApplicationLockedActivityThread::bindApplicationActivityManagerService::finishAttachApplicationInnerActivityTaskManagerService$LocalService::attachApplicationRootWindowContainer::attachApplicationRootWindowContainer$AttachApplicationHelper::process -- 开始遍历WindowContainer::forAllRootTasks  --- 省略forAllRootTasks等固定堆栈Task::forAllRootTasks  -- 1. 遍历所有root TaskRootWindowContainer$AttachApplicationHelper::accept  -- 1.1 root Task执行acceptWindowContainer::forAllActivities  -- 2. 遍历下面的所有ActivityRecordActivityRecord::forAllActivities RootWindowContainer$AttachApplicationHelper::test  -- 2.1 ActivityRecord执行testActivityTaskSupervisor::realStartActivityLocked  -- 试图启动ActivityLooper::loop

对应时序图:
在这里插入图片描述
大概流程图如下:
在这里插入图片描述
这一阶段主要就是应用进程启动后,试图拉起对应的 Activity ,能不能启动的条件就是没有正在 pause 的 Activity 了。 主要逻辑就是触发 ActivityTaskSupervisor::realStartActivityLocked

第四阶段:真正启动Activity

这个方法是要真去触发 Activity 启动的,根据前面的流程图,阶段二,三的最终就是想执行到这个方法里面,来触发 Activity 启动。
这个方法的最终目的就是通过事务执行 LaunchActivityItem 和 PauseActivityItem ,也就是会触发应用端 TargetActivity 启动,并执行生命周期到 onCreate 和 onResume 。

# ActivityTaskSupervisor boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,boolean andResume, boolean checkConfig) throws RemoteException {//  重点* 1. 判断是否执行完了pause if (!mRootWindowContainer.allPausedActivitiesComplete()) {// While there are activities pausing we skipping starting any new activities until// pauses are complete. NOTE: that we also do this for activities that are starting in// the paused state because they will first be resumed then paused on the client side.// 如果还有Activity没完成pause,则打印日志并returnProtoLog.v(WM_DEBUG_STATES,"realStartActivityLocked: Skipping start of r=%s some activities pausing...",r);return false;}// 重点* 2. 表示ActivityRecord已连接到相应的进程r.setProcess(proc);......// event日志: wm_restart_activity EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),task.mTaskId, r.shortComponentName);......// 重点* 3.1 创建事务,用于Activity启动// Create activity launch transaction.final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);final boolean isTransitionForward = r.isTransitionForward();// 获取Activity所在 TaskFragment Tokenfinal IBinder fragmentToken = r.getTaskFragment().getFragmentToken();// 重点* 3.2 将构建的 LaunchActivityItem 添加到 clientTransaction 中clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),System.identityHashCode(r), r.info,// TODO: Have this take the merged configuration instead of separate global// and override configs.mergedConfiguration.getGlobalConfiguration(),mergedConfiguration.getOverrideConfiguration(), r.compat,r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),results, newIntents, r.takeOptions(), isTransitionForward,proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));// 重点* 3.3 设置预期的最终状态为 ResumeActivityItemfinal ActivityLifecycleItem lifecycleItem;if (andResume) {// Resume逻辑,启动走的这。 表示需要执行到onCreatelifecycleItem = ResumeActivityItem.obtain(isTransitionForward);} else {//  Pause 逻辑lifecycleItem = PauseActivityItem.obtain();}clientTransaction.setLifecycleStateRequest(lifecycleItem);// 重点* 3.4 执行事务mService.getLifecycleManager().scheduleTransaction(clientTransaction);......}

根据代码的标注解释:
1、根据注释,如果有 Activity 正在 pause 则不允许任何 Activity 启动。换句话说就是想要启动一个 Activity 必须其他的 Activity 需要 pause 的都完成了 pause 流程
2、对应之前提到的 ActivityRecord::attachedToProcess 方法如果需要返回 true ,则必须在这里执行 setProcess 方法,否则 ActivityRecord 下的 app 变量就是 null
3、这里就是开始真正执行启动 Activity 的地方了,是通过事务执行的,分为以下几步
3.1 构建一个事务
3.2 设置 LaunchActivityItem ,这一步会将 Activity 的生命周期执行到 onCreate
3.3 设置 ResumeActivityItem ,这一步会将 Activity 的生命周期执行到 onResume
3.4 执行事务

后续逻辑就是在应用端执行 Activity 的创建,以及生命周期处理了,这部分本篇大概看一遍流程。

创建Activity

这部分的调用链如下:

LaunchActivityItem::executeActivityThread::handleLaunchActivityActivityThread::performLaunchActivityInstrumentation::newActivity -- 创建ActivityActivity::attach  -- 处理Window相关Window::initWindow::setWindowManagerInstrumentation::callActivityOnCreate -- onCreate流程Activity::performCreateActivity::onCreate  --over

时序图图下:
在这里插入图片描述
接下来看 LaunchActivityItem::execute

# LaunchActivityItem public void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,mTaskFragmentToken);client.handleLaunchActivity(r, pendingActions, null /* customIntent */);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}

这里的 client 是 ClientTransactionHandler 类型, 而 ActivityThread 是 ClientTransactionHandler 子类。
重点是这边创建了 ActivityClientRecord ,第一个参数就是我们要找的token

逻辑来到应用进程 ActivityThread。

# ActivityThreadpublic Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {......final Activity a = performLaunchActivity(r, customIntent);......}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {......Activity activity = null;try {// 重点* 1. 通过Instrumentation 反射创建Activityjava.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);......}try {......// 重点* 2. 执行 attach 流程activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.activityConfigCallback,r.assistToken, r.shareableActivityToken);......if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {重点* 3. onCreate流程mInstrumentation.callActivityOnCreate(activity, r.state);}}......}

这里有3个重点:

  • Activity 是通过反射创建的。 到这里其实 Activity 启动流程基本分析完了
  • 执行 Activity::attach 。这里会触发创建 Window
  • 触发 Activity::onCreate

Activity 已经创建好了,那就剩下 onCreate 了。

# Instrumentationpublic void callActivityOnCreate(Activity activity, Bundle icicle) {prePerformCreate(activity);// onCreate流程activity.performCreate(icicle);postPerformCreate(activity);}# Activityfinal void performCreate(Bundle icicle) {performCreate(icicle, null);}final void performCreate(Bundle icicle, PersistableBundle persistentState) {......if (persistentState != null) {onCreate(icicle, persistentState);} else {// 执行onCreateonCreate(icicle);}......}

写过应用的都知道,默认都是一个参数的onCreate。

至此,Activity 启动流程分析完毕。

阶段四小结

在这里插入图片描述
无论是阶段二还是阶段三触发了 ActivityTaskSupervisor::realStartActivityLocked 方法,并且还满足启动 Activity 条件,则会触发应用端进程 Activity 的创建和生命周期的执行。

这篇关于Android Framework(三)Activity启动流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129452

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存