赣州市城乡建设局官方网站,中关村网站建设公司,潍坊大型网站建设,wordpress 首页弹窗忽然有一天#xff0c;我想要做一件事#xff1a;去代码中去验证那些曾经被“灌输”的理论。 – 服装… 忽然有一天我想要做一件事去代码中去验证那些曾经被“灌输”的理论。 – 服装学院的IT男 本篇已收录于Activity短暂的一生系列 欢迎一起学习讨论Android应用开发或者WMS VWJB6995 Q707409815 正文
由于篇幅原因整个启动流程分为以下3篇进行分析
Activity启动流程-1
Activity启动流程-2
Activity启动流程-3
继续上一篇执行到 TaskFragment::resumeTopActivity 分析。 当前分析进度还处于阶段一的逻辑阶段一最后是需要触发2个逻辑 触发 SourceActivity 执行 pause 触发创建 TargetActivity 所在进程
1. 阶段一 : system_service 处理
1.1 显示顶层 Activity–TaskFragment::resumeTopActivity
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个主线: pause 当前 Activity 也就是 Launcher 异步创建“电话”的进程
在第一步将 Launcher 的 Activity 执行 pause 这一步执行到最后也会触发电话应用 MainActivity 的启动。 第二步创建“电话”进程进程创建完肯定也会执行电话应用 MainActivity 的启动这么看来就有2个地方触发了。
这是因为是异步创建进程不知道谁先执行完但是可以明确的是电话应用 MainActivity 必须有2个条件 前一个Activity执行完pause 进程创建完成
所以无论2个分支哪一个先执行完都需要等后一个执行完的来触发后续电话应用 MainActivity 的启动。 这个方法还有2个需要注意的地方 变量 pausing 表示当前是否正在执行 Activity 的 pause 流程。这个值受2个因素影响
先看 Launcher 的 pause 流程。
1.2 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 事件。
这块相关的日志输入如图: 因为是后面补充的所以对象不一样但是能确定这里处理的 TaskFragment 和 mResumedActivity 都是 Launcher 对象的. State movement 这段的输出是在 ActivityRecord::setState 只要状态改变都会输出 1.2.1 PauseActivityItem
触发 pause 流程就是通过 PauseActivityItem 这个触发的。
# PauseActivityItemOverridepublic 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执行后调用 postExecuteOverridepublic void postExecute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {if (mDontReport) {return;}// 重点*2. 触发启动新的ActivityActivityClient.getInstance().activityPaused(token);}
这里先执行 execute 方法也就是 Launcher 的 pause 流程这个不是主线。
然后执行 postExecute这里会触发新 Activity 的启动这个流程就是阶段二。
# ActivityClientpublic void activityPaused(IBinder token) {try {getActivityClientController().activityPaused(token);} catch (RemoteException e) {e.rethrowFromSystemServer();}}1.3 启动进程
这一步就是 TaskFragment::resumeTopActivity 触发的 TargetActivity 所在的进程创建这一步的后续逻辑是阶段三。
2. 第一阶段总结
本篇对整个 Activity 启动流程做了介绍然后重点分析第一阶段的事情这一阶段的二级框图如下 在 Launcher 进程构建了启动参数放在了 ActivityOption 中然后通过 Bundle 传递给 system_service 端 AMS 先解析参数放在了 Request 这个类中保存 AMS 构建出一个 ActivityRecord 这个类在 system_service 端就代表着 Activity 同时也是一个窗口容器 再构建出一个 Task 挂载到窗口树上 将 ActivityRecord 挂载到 Task 中这样 ActivityRecord 也就挂载到窗口层级树中了 触发 Launcher 执行 pause 逻辑也就是阶段二 触发 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.2 将Task与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 创建“电话”进程2.1 容器变化
之前看过窗口层级树在冷启动前面的对比 其中 WindowState 部分和其他 Task 和启动流程无关先不管。
在桌面的时候 DefaultTaskDisplayArea 下只有 Launcher 所在的 Task 有元素如下图 忽略掉其他的空 Task 所有 DefaultTaskDisplayArea 下的顶层 Task 就是 Launcher 所在的 Task 1Task 1 下是一个 Task 8 然后内部才是 Launcher 的 ActivityRecord 这个 ActivityRecord 目前也是整个手机系统里的顶层 Activity这个时候用户角度看到的 Activity 也是 Launcher 的 Activity
在阶段一处理完后主要操作集中在 ActivityStarter::startActivityInner 方法对窗口容器的操作操作完后如下图 经过阶段一的处理已经创建了 TargetActivity 所在的 Task 和对应的 ActivityRecord 并也挂载到 DefaultTaskDisplayArea 下了而且还将其移到了顶部所以得到上面主要的一个关系。 但是这个时候用户还是只能看到 Launcher 的 Activity 。这是因为 TargetActivity 都还没启动甚至连它的进程这会都没创建。
阶段一 DefaultTaskDisplayArea 下结构已经如图了为了能让用户的实际视觉也这样所以要让 TargetActivity 启动起来所以触发了 RootWindowContainer::resumeFocusedTasksTopActivities 方法但是在执行到 TaskFragment::resumeTopActivity 方法的时候发现想显示 TargetActivity 的条件2个都没满足所以就需要触发 Launcher 的pause 和 TargetActivity 所在进程的创建。也就是后面要看的阶段 二三 。
2.1 后续阶段预览
按照之前说的整个启动流程分为4个阶段目前已经分析完了第一阶段。也知道为啥要执行二三阶段了后面要分析的二三阶段由于提过多次是异步的取决执行速度这个是不确定的。也是因为这个原因所以网上有很多博客关于 Activity 启动流程的分析都不太一样其实也许都没有错只是各自分析的具体执行顺序不同。
经过二三阶段后就要触发应用进程启动 TargetActivity 了第一阶段和第四阶段的流程是固定的第二三阶段还是有点不确定性的。
既然从触发顺序上是先执行 pause 再触发进程创建那么后面的逻辑就以先完成 completePause 再完成进程创建的执行循序分析当然在后面的分析中一些关键的分歧点也会着重标记尽量让读者能区分各个场景的执行逻辑。
3. 阶段二–completePause
3.1 流程概述
应用完成 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对应的时序图如下 根据堆栈信息发现有2个地方都会触发 ActivityTaskSupervisor::startSpecificActivity 。 resumeFocusedTasksTopActivities 流程。这个方法在阶段一看过目的就是要显示一个顶层 Activity但是第一阶段因为目标进程没起来SourceActivity 也没 pause 所以最终也没触发 TargetActivity 的启动。 ensureActivitiesVisible 流程。这个流程执行的概率很高界面有个风吹草动可能影响 Activity 显示的都会执行这个方法这个方法的目的就是确保当前设备上的 Activity 正确显示。 比如当前这个场景一个 Activity 完成了 completePause 那肯定要有新的 Activity 显示那整个手机系统的 Activity 规则肯定发生了改变所以需要执行 ensureActivitiesVisible 流程来确保正确的显示。 注意ensureActivitiesVisible 流程并不是针对1个 Activity 而是整个设备上所有的 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 。否则会根据具体情况处理一下其可见性。 这里其实还有一个可能的逻辑那就是在 resumeFocusedTasksTopActivities 流程下进程没创建好但是在走的 ensureActivitiesVisible 的时候进程创建好了并触发了启动TargetActivity 的启动逻辑那这个时候 ensureActivitiesVisible 则就“处理一下其可见性”。 有个注意点这个图里提到的ActivityRecord::attachedToProcess 方法的返回值并不严格等于“进程是否创建”详细区别在 3.1.2 小节分析 理论知识建设完毕下面来说跟代码从 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 ............}打印如下
WindowManager: Moving to PAUSED: ActivityRecord{1f58beb u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t8} (pause complete)
流程来到 TaskFragment::completePause 注意传递过来的参数分别为 true 和 null 。
# TaskFragmentVisibleForTestingvoid 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步走了。
3.1 第一步–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 ,至于最后是不是真的能启动还是要看进程起来没。 至于next.attachedToProcess()这个条件冷启动是不会走进去的这里的逻辑我是有疑问的放在后面 3.1.2 讲先看主流程。 这一步会打印日志:
WindowManager: resumeTopActivity: Restarting ActivityRecord{1cf0e8 u0 com.google.android.apps.messaging/.ui.ConversationListActivity t30}3.1.1 关键方法–startSpecificActivity
这个方法已经提过多次了简单说目的是想去让应用端启动 Activity 但是如果可能应用端进程还没创建就会触发进程创建。
# ActivityTaskSupervisorfinal ActivityTaskManagerService mService;void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {// Is this activitys 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 暂时就先不看了。
3.1.2 疑问 – ActivityRecord::attachedToProcess
这一小节是一个小细节倒也不影响主流程分析如果进程启动的快当前这个分析的流程是可以直接进入 realStartActivityLocked 方法启动 Activity 的。比如下面这个堆栈
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.ActivityTaskSupervisor.realStartActivityLocked(ActivityTaskSupervisor.java:787)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.ActivityTaskSupervisor.startSpecificActivity(ActivityTaskSupervisor.java:1074)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1551)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5050)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4980)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2296)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2282)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1816)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6399)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:219)
07-10 23:22:32.960 18666 18944 E biubiubiu: at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:663)
07-10 23:22:32.960 18666 18944 E biubiubiu: at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:153)
07-10 23:22:32.960 18666 18944 E biubiubiu: at android.os.Binder.execTransactInternal(Binder.java:1344)
07-10 23:22:32.960 18666 18944 E biubiubiu: at android.os.Binder.execTransact(Binder.java:1275)
但是在 TaskFragment::resumeTopActivity 方法有其实有next.attachedToProcess()这个条件判断进程是不是启动了这个日志是直接走了 startSpecificActivity 然后在 startSpecificActivity 方法发现进程启动了所以就走进了 realStartActivityLocked 。 我的疑问点就是 resumeTopActivity 到 realStartActivityLocked 中间的调用链就1层执行时间完全可以忽略不计难倒在这么短时间内进程刚好就启动了
所以问题点就在于2个地方对于“进程是否启动的判断”条件。
# TaskFragmentfinal boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,boolean deferPause) {......// ActivityRecord 下的 app 变量是否有值并且进程已经执行if (next.attachedToProcess()) {......} ......}# ActivityTaskSupervisorfinal ActivityTaskManagerService mService;void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {// Is this activitys application already running?// 拿到目标进程信息final WindowProcessController wpc mService.getProcessController(r.processName, r.info.applicationInfo.uid);boolean knownToBeDead false;//进程是否存在且主线程已执行if (wpc ! null wpc.hasThread()) {......}......}2个地方都是拿到 WindowProcessController 对象判断下是不是不为空并且 hasThread 返回 true 那么区别就在于拿到 WindowProcessController 对象的方式不一样。
后者 startSpecificActivity 方法是通过 ATMS::startSpecificActivity ,代码如下:
# ActivityTaskManagerServiceWindowProcessController getProcessController(int pid, int uid) {final WindowProcessController proc mProcessMap.getProcess(pid);if (proc null) return null;if (UserHandle.isApp(uid) proc.mUid uid) {return proc;}return null;}这种方式拿到的进程信息是靠谱的没啥问题再看看 ActivityRecord 的。
# ActivityRecordpublic WindowProcessController app; // if non-null, hosting applicationvoid setProcess(WindowProcessController proc) {// 赋值app proc;......}boolean hasProcess() {return app ! null;}boolean attachedToProcess() {return hasProcess() app.hasThread();}ActivityRecord::attachedToProcess 方法没问题但是发现 app 这边变量是通过 ActivityRecord::setProcess 方法设置的而这个方法的调用在 ActivityTaskSupervisor::realStartActivityLocked 里当在这里执行 ActivityRecord::setProcess 时应用进程肯定是真的创建了并且 ActivityRecord 下的 app 变量也有值了。
所以冷启动没有执行到 ActivityTaskSupervisor::realStartActivityLocked 方法之前 ActivityRecord::attachedToProcess 方法 肯定是返回 false 的。
3.2 第二步–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()) {// Dont 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可见的。 在这定义了一个专门的类来处理。 不过需要注意的是这个方法会执行多次因为他是遍历每一个符合条件的子容器从上到下遍历。
3.2.1 EnsureActivitiesVisibleHelper::process
这个方法是调用 EnsureActivitiesVisibleHelper 的的方法Task 通过这个方法来处理当前容器下的元素可见性。
# EnsureActivitiesVisibleHelpervoid process(Nullable ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients) {// 1. 对参数进行重置处理reset(starting, configChanges, preserveWindows, notifyClients);......final boolean resumeTopActivity mTopRunningActivity ! null !mTopRunningActivity.mLaunchTaskBehind mTaskFragment.canBeResumed(starting) (starting null || !starting.isDescendantOf(mTaskFragment));// 遍历容器下所有元素for (int i mTaskFragment.mChildren.size() - 1; i 0; --i) {// 获取当前子元素final WindowContainer child mTaskFragment.mChildren.get(i);// 将当前子元素转换为TaskFragment只有TaskFragment重写了asTaskFragment()方法Task或ActivityRecord为null// 而Task的孩子一般就是ActivityRecord或者Task。 当前分析逻辑大部分场景Task下面是ActivityRecord// 所以这里childTaskFragment 为 nullfinal TaskFragment childTaskFragment child.asTaskFragment();if (childTaskFragment ! null childTaskFragment.getTopNonFinishingActivity() ! null) {......} else {// 只有ActivityRecord重写了 asActivityRecord()setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);}}}执行到这里对当前的 Task 遍历了他下面的所有元素我们目前关系的是 Activity 所以看对每个 ActivityRecord 做了什么 。
3.2.2 EnsureActivitiesVisibleHelper::setActivityVisibilityState
# EnsureActivitiesVisibleHelperprivate void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,final boolean resumeTopActivity) {......if (reallyVisible) {.......if (!r.attachedToProcess()) {// 主流程makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop,resumeTopActivity isTop, r);} else {......}} else {......// 不可见调用makeInvisibler.makeInvisible();}}这里的 r 表示当前Task 下的 ActivityRecord 。所有 ActivityRecord 都会执行这个方法目前关心的是 SourceActivity 和 TargetActivity 。SourceActivity 也就是 Launcher 走到这里会执行 “r.makeInvisible();” 进而触发 onStop 逻辑TargetActivity 也就是 “电话” 走到这里则是去走可见逻辑
SourceActivity 的就不管了不是主线继续看 TargetActivity 在 makeVisibleAndRestartIfNeeded 方法是怎么处理的。
# EnsureActivitiesVisibleHelperprivate void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,boolean isTop, boolean andResume, ActivityRecord r) {......if (!r.mVisibleRequested || r.mLaunchTaskBehind) {if (DEBUG_VISIBILITY) {Slog.v(TAG_VISIBILITY, Starting and making visible: r);}// 1. 设置Visibilityr.setVisibility(true);}if (r ! starting) {// 2. 试图启动 ActivitymTaskFragment.mTaskSupervisor.startSpecificActivity(r, andResume,true /* checkConfig */);}}设置可见。 这个是 ensureActivitiesVisible 流程最主要做的事这个流程就是为了确保所有 Activity 正确的可见性 。 试图启动 Activity 。 发现当前的显示的 Activity 和正在处理的 Activity 不是一个则视图启动。starting 这个参数之前注释了为null
后面的 ActivityTaskSupervisor::startSpecificActivity 方法就不看了刚看过了如果进程启动了才会执行后续逻辑启动 TargetActivity。
4. 阶段二总结
阶段二的逻辑其实比较简单只是我分析的比较细节。 阶段二其实就是 SourceActivity 完成 pause 后执行 ActivityRecord::activityPaused 流程AMS 需要显示当前顶层 Activity 所以执行了 RootWindowContainer::resumeFocusedTasksTopActivities 方法但是这一次是不是真的能显示顶层 Activity 还是要看其进程是否已经创建好了。
在操作了 Activity 的显示逻辑后为了确保系统 Activity 正常的可见性所以又执行了一次 ensureActivitiesVisible 流程。
流程相对简单就是下面这个图