Android Framework(三)Activity启动流程

news/2024/9/15 22:40:58/ 标签: android, java, 开发语言

文章目录

  • 大纲
    • 总体流程
  • 第一阶段:点击图标启动应用
    • 流程概览
    • 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 进程中。

java"># 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 的报错就在这。

java"># 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 启动。

启动请求参数的构建

java"># 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 逻辑。

java"># ActivityStartController// 返回ActivityStarterActivityStarter obtainStarter(Intent intent, String reason) {return mFactory.obtain().setIntent(intent).setReason(reason);}

所以在 ActivityTaskManagerService::startActivityAsUser 方法中的 build 模式,其实是对 ActivityStarter 对象做构建,最终调用其 execute 方法。
在内容最终执行了 ActivityStarter::executeRequest 方法,下面只以 setCallingPackage 这一个方法看一下是怎么把参数设置到 Request 中的。

java"># 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. 执行后续启动逻辑
java">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的解析

java">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 。

java"># 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 是怎么创建的:

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

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

java"># 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 上的,这个属于窗口显示第一步,后边再说。

继续主流程代码:

java"># 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

调用链

java">ActivityStarter::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskRootWindowContainer::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTaskDisplayArea::getOrCreateRootTaskTask::Build     ---创建Task

代码:

java"># 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 如果没有就新建一个。

java"># 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 。

java"># 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的创建:

java"># 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

java"># 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 。

java"># 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 的时候调用的是这段代码:

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

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

java"># 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 执行,调用链如下:

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

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

java"># 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 启动“电话”的场景来看看执行逻辑。

java"># 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 逻辑。

java"># 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 。

java"># 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 这个触发的。

java"># 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 的启动,这个流程就是阶段二。

java"># 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 处理的完整堆栈

java">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 的后续逻辑,这部分调用链如下:

java">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

java"># 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 。

java"># 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 方法,这个方法之前也看过,但是这次的逻辑肯定不一样了。

java"># 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 ,但是如果可能应用端进程还没创建,就会触发进程创建。

java"># 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 然后根据对应的条件处理想要的可见性。

java"># 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();}}

遍历所有屏幕

java"># 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 方法

java"># 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 中。

java"># 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这块执行进程创建的调用流程。

java"># 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 中。

java"># 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

java"># 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,更新生命周期状态等。

java"># 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 经过几次重载会调用下面的方法

java"># 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}

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

这部分调用链如下:

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

应用进程创建

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

java"># 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();}......}

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

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

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

system_service端处理

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

java">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。
在这里插入图片描述

java"># 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 把原来的逻辑提取新增的方法。

java"># 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

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

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

java"># 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 实现即可。

java"># 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 。

java"># 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

这部分的调用链如下:

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

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

java"># 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。

java"># 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 了。

java"># 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 的创建和生命周期的执行。


http://www.ppmy.cn/news/1520256.html

相关文章

MySQL集群技术4——MySQL路由

mysql-route MySQL 路由&#xff08;Routing&#xff09;通常指的是在 MySQL 架构中如何处理客户端请求和数据流向的问题。在 MySQL 中&#xff0c;路由可以涉及多种不同的场景和技术&#xff0c;包括但不限于反向代理、负载均衡、读写分离等。下面我将详细介绍这些场景和技术…

数学基础 -- 线性代数之酉矩阵

酉矩阵&#xff08;Unitary Matrix&#xff09; 酉矩阵是线性代数中一种重要的矩阵类型&#xff0c;特别在量子力学和信号处理等领域有广泛的应用。以下是酉矩阵的定义、性质以及使用和计算的例子。 1. 定义 酉矩阵是一个复矩阵 U U U &#xff0c;满足以下条件&#xff1a…

【tomcat详解】功能+部署+Nginx反向代理+Memcached+session会话

目录 一、Tomcat简介 二、Tomcat功能介绍 2.2 tomcat文件组成 2.3 生成tomcat启动文件 三、Tomcat部署 3.1 常见部署方式介绍 3.2 利用nginx实现反向代理 四、Memcached 4.1 memcached安装启动 4.2 memcached操作命令 五、Session共享服务器 5.1 msm介绍 一、Tomcat…

电商智能分析:阿里巴巴商品详情API返回值的挖掘与利用

电商智能分析是利用大数据和机器学习技术来深入理解用户行为、商品趋势以及市场变化的过程。阿里巴巴商品详情API作为获取商品详细信息的重要工具&#xff0c;其返回值中蕴含了丰富的数据&#xff0c;可以通过挖掘和利用这些数据来进行智能分析。下面&#xff0c;我将提供一个基…

n*n矩阵,输出矩阵中任意两点之间所有路径

题目1&#xff1a;给你一个正整数n&#xff0c; 构造一个n*n的四项链表矩阵。 要求&#xff1a; 1.使用四项链表 2.矩阵从左到右&#xff0c;从上到下值依次为1,2,3,4,......n*n 题目2&#xff1a;基于题目1&#xff0c; 在n*n链表矩阵中&#xff0c;输出矩阵中任意两点之间所有…

9、Django Admin优化查询

如果你的Admin后台中有很多计算字段&#xff0c;那么你需要对每个对象运行多个查询&#xff0c;这会使你的Admin后台变得非常慢。要解决此问题&#xff0c;你可以重写管理模型中的get_queryset方法使用annotate聚合函数来计算相关的字段。 以下示例为Origin模型的中ModelAdmin…

嵌入式Linux:常见信号的默认行为

信号是一种软件中断&#xff0c;用于通知进程发生了某种异步事件。信号可以由用户、其他进程或操作系统内核产生。进程可以选择捕获并处理这些信号&#xff0c;或者忽略它们&#xff0c;让系统执行默认操作。 不可靠信号&#xff08;非实时信号&#xff09;&#xff1a;编号为 …

使用QTcpSocket在两台ubuntu之间实现通讯

重点提取&#xff1a; 1.保证服务端和客户端端口号一致 2.保证服务端和客户端在同一网段(可以通过网线连接) 3保证客户端界面输入的ip是服务段的ip 实现步骤&#xff1a; 首先&#xff0c;构造服务端界面和客户端界面如下 服务端界面 客户端界面 其次具体代码 在.pro文件…

Linux 命令行快捷键

Linux 命令行快捷键_linux删除一个单词-CSDN博客 涉及在linux命令行下进行快速移动光标、命令编辑、编辑后执行历史命令、Bang(!)命令、控制命令等。让basher更有效率。 常用 Ctrl左右键:在单词之间跳转 Ctrla: 跳到本行的行首 Ctrle: 跳到页尾 Ctrlu&#xff1a;删除当前光标…

SpringWeb 重定向

现在前端后分离&#xff1a;如何确认是跳转到前端页面还是后端的方法呢&#xff1f;RedirectView&#xff1a;重定向如何区分重定向的是前端页面还是后端的一个controller呢 先看下&#xff1a;SpringBoot系列教程web篇之重定向-阿里云开发者社区 ## 根据浏览器中返回的状态码…

数据结构串的模式匹配算法--BF暴力匹配

BF&#xff08;Brute-Force&#xff0c;暴力匹配&#xff09;算法是一种简单的字符串匹配算法&#xff0c;其基本思想是将目标串S逐个字符与模式串P进行比对&#xff0c;直到找到匹配或遍历完S为止。下面是一个使用C语言实现的BF算法示例&#xff1a; #include <stdio.h>…

用友U8 CRM exportdictionary.php SQL注入漏洞复现

0x01 产品简介 用友U8 CRM客户关系管理系统是一款专业的企业级CRM软件,旨在帮助企业高效管理客户关系、提升销售业绩和提供优质的客户服务。 0x02 漏洞概述 用友 U8 CRM客户关系管理系统 exportdictionary.php 文件存在SQL注入漏洞,未经身份验证的攻击者通过漏洞执行任意S…

全志Linux磁盘操作基础命令

磁盘操作 fdisk命令 fidsk是一个用来创建和维护磁盘设备分区的一个实用工具。 [ubuntubook:~]$ fdisk -l //列出当前系统所有的磁盘设备 [ubuntubook:~]$ fdisk /dev/sdc //操作设备节点为 /dev/sdc的一个设备。p : 显示所有的分区。d: 删除分区。n: 创建一个新的分区。t : …

使用QT开发一些特殊相机的思路:个人经验

前言&#xff1a; 去年使用QT开发过Dalsa线扫相机的应用程序&#xff0c;去获取数据&#xff0c;显示图片&#xff0c;实时分析等&#xff0c;测试demo的链接如下&#xff1a; Dalsa线扫相机-二次开发-QT-C 可用Demo&#xff08;一&#xff09;_dalsa开发-CSDN博客 前段时间&am…

基于Java+SpringBoot+Vue+MySQL的在线装修管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的在线装修管理系统【附源码文档】、前后…

解决Springboot项目Maven下载依赖速度慢的问题

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

数学建模笔记

1.三级表的制作 打开word找到插入并点击表格 随机生成一个表格&#xff0c;然后去修改表格样式&#xff0c;把格式应用于选到标题行&#xff0c;然后点击格式&#xff0c;选到边框和底纹&#xff0c;把宽度改为1.5磅&#xff0c;然后点击上下俩个田字&#xff0c;预览图会出现…

RabbitMQ中间件监控指标解读

监控易是一款全面的IT监控软件&#xff0c;能够实时监控各种IT资源和应用&#xff0c;确保系统的稳定运行。在RabbitMQ中间件的监控方面&#xff0c;监控易提供了详尽的监测指标&#xff0c;帮助用户深入了解RabbitMQ集群的运行状态和性能表现。 一、集群监控&#xff08;sdds…

飞思相机存储卡格式化数据如何恢复?提供全面指南

在数字摄影时代&#xff0c;‌飞思相机以其卓越的成像质量和专业的性能&#xff0c;‌赢得了众多摄影师的青睐。‌然而&#xff0c;‌即使是专业的设备也难免遭遇数据丢失的困境&#xff0c;‌尤其是当存储卡不幸被格式化时。‌面对这一突如其来的灾难&#xff0c;‌许多摄影师…

thinkphp8 定时任务 addArgument

在ThinkPHP8中&#xff0c;我们可以使用addArgument方法来添加命令行参数。这个方法允许我们定义命令行参数&#xff0c;并且可以指定参数的模式&#xff08;例如&#xff1a;是否必须&#xff0c;是否可选&#xff09;。 以下是一个简单的例子&#xff0c;演示如何在ThinkPHP…