当前位置: 首页 > news >正文

【Android 源码分析】Activity生命周期之onStop-1

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
                  
                  
                                           – 服装学院的IT男

本篇已收录于Activity短暂的一生系列
欢迎一起学习讨论Android应用开发或者WMS
V:WJB6995
Q:707409815

正文

生命周期系列:

  • Activity生命周期之onPause

  • onCreate,onStart,onResume-1

  • onCreate,onStart,onResume-2

  • Activity生命周期之onStop-1

  • Activity生命周期之onStop-2

  • Activity生命周期之onDestory

之前看过一遍流程的Events日志

// SystemService端创建TargetActivity  (writeWmCreateActivity)
03-27 14:41:06.428 27889 28629 I wm_create_activity: [0,253598020,21,com.google.android.dialer/.extensions.GoogleDialtactsActivity,android.intent.action.MAIN,NULL,NULL,270532608]// SystemService端触发SourceActivity的Pause (writeWmPauseActivity)
03-27 14:41:06.431 27889 28629 I wm_pause_activity: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher,userLeaving=true,pauseBackTasks]// SourceActivity应用端将执行onPause (writeWmOnPausedCalled)
03-27 14:41:06.448 28606 28606 I wm_on_paused_called: [51114540,com.android.launcher3.uioverrides.QuickstepLauncher,performPause]// SystemService端把SourceActivity添加进需要stop的集合 (writeWmAddToStopping)
03-27 14:41:06.459 27889 28630 I wm_add_to_stopping: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher,makeInvisible]// SystemService端要真正触发TargetActivity启动 (writeWmRestartActivity)
03-27 14:41:06.487 27889 28630 I wm_restart_activity: [0,253598020,21,com.google.android.dialer/.extensions.GoogleDialtactsActivity]// TargetActivity端将执行onCreate  (writeWmOnCreateCalled)
03-27 14:41:06.769  3401  3401 I wm_on_create_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,performCreate]// TargetActivity端将执行onStart (writeWmOnStartCalled)
03-27 14:41:06.900  3401  3401 I wm_on_start_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,handleStartActivity]// TargetActivity端将执行Resume (writeWmOnResumeCalled)
03-27 14:41:06.911  3401  3401 I wm_on_resume_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,RESUME_ACTIVITY]// SystemService端触发SourceActivity的stop (writeWmStopActivity)
03-27 14:41:07.097 27889 30491 I wm_stop_activity: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher]// SourceActivity应用端将执行onStop (writeWmStopActivity)
03-27 14:41:07.119 28606 28606 I wm_on_stop_called: [51114540,com.android.launcher3.uioverrides.QuickstepLauncher,STOP_ACTIVITY_ITEM]

其中可以看到很早就打印了 “wm_add_to_stopping”,但是 SourceActivity 真正执行 onPause (“wm_on_stop_called”)却是在最后。

所以按照顺序,先看看 “wm_add_to_stopping”相关的逻辑。

整个流程分为3步:

    1. addToStopping 流程,将应用添加进需要stop的列表 – system_service进程处理
    1. stopIfPossible 流程,也就是开始执行stop – system_service进程处理
    1. 应用端处理stop流程 – 应用进程处理

前面个都是system_service进程处理的,第三步是在 SourceActivity 的应用进程处理。
本篇为 onStop第一篇,介绍 system_service 进程是如何把 SourceActivity 添加进stop集合。

第一步:addToStopping 流程

1 调用链概览

通过Events日志可知“wm_add_to_stopping”的执行在真正启动 TargetActivity 之前。 在 SourceActivity 的 pause 流程之后。

“wm_add_to_stopping” 日志打印的方法在 ActivityRecord::addToStopping 中,在这个方法加上堆栈得到以下内容

03-28 14:39:03.326 23968 26756 I wm_add_to_stopping: [0,264636779,com.android.launcher3/.uioverrides.QuickstepLauncher,makeInvisible]
03-28 14:39:03.327 23968 26756 E biubiubiu: ActivityRecord  addToStopping: ActivityRecord{fc6096b u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t7}
03-28 14:39:03.327 23968 26756 E biubiubiu: java.lang.Exception
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.ActivityRecord.addToStopping(ActivityRecord.java:6225)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.ActivityRecord.makeInvisible(ActivityRecord.java:5811)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:243)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:155)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1118)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task.lambda$ensureActivitiesVisible$19(Task.java:4918)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task$$ExternalSyntheticLambda24.accept(Unknown Source:10)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task.forAllLeafTasks(Task.java:3183)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task.forAllLeafTasks(Task.java:3171)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:4917)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.DisplayContent.lambda$ensureActivitiesVisible$44(DisplayContent.java:6143)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda38.accept(Unknown Source:10)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.Task.forAllRootTasks(Task.java:3195)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2033)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2026)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.DisplayContent.ensureActivitiesVisible(DisplayContent.java:6142)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1873)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1854)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1802)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6063)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:182)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:574)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:125)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at android.os.Binder.execTransactInternal(Binder.java:1280)
03-28 14:39:03.327 23968 26756 E biubiubiu: 	at android.os.Binder.execTransact(Binder.java:1244)

根据这段堆栈很明显可以看初是 SourceActivity 执行的 activityPaused 流程,再根据之前的Events日志顺序,也知道是在 SourceActivity 执行完 pause 流程后触发的。

也就是说 activityPaused 流程再触发 TargetActivity 启动前,还执行了 addToStopping 流程,将 SourceActivity 放进来需要 stop 的列表中。

关于 【Activity启动流程-2】流程之前整理的调用链如下:

ActivityClientController::activityPausedActivityRecord::activityPausedTaskFragment::completePauseRootWindowContainer::resumeFocusedTasksTopActivities       --分支1 ,再次执行 resumeFocusedTasksTopActivitiesRootWindowContainer::resumeFocusedTasksTopActivitiesTask::resumeTopActivityUncheckedLockedTask::resumeTopActivityInnerLockedTaskFragment::resumeTopActivityActivityTaskSupervisor::startSpecificActivity                           --触发 startSpecificActivity 判断应用是否创建RootWindowContainer::ensureActivitiesVisible              --分支2RootWindowContainer::ensureActivitiesVisibleDisplayContent::ensureActivitiesVisible WindowContainer::forAllRootTasks  --忽略固定逻辑Task::ensureActivitiesVisibleTask::forAllLeafTasks --忽略固定逻辑TaskFragment::updateActivityVisibilitiesEnsureActivitiesVisibleHelper::processEnsureActivitiesVisibleHelper::setActivityVisibilityStateEnsureActivitiesVisibleHelper::makeVisibleAndRestartIfNeededActivityTaskSupervisor::startSpecificActivity       --触发 startSpecificActivity 判断应用是否创建

这2个分支在【Activity启动流程】都分析过了,但是现在关注的是生命周期相关, 分之一和生命周期相关的流程已经分析过了,现在需要看看分支2和生命周期相关的逻辑。

# TaskFragmentvoid completePause(boolean resumeNext, ActivityRecord resuming) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "completePause");// 拿到之前的Activity,也就是需要 pause的ActivityRecord prev = mPausingActivity;ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);if (prev != null) {......// 设置窗口状态为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分支Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resumeFocusedTasksTopActivities");mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,null /* targetOptions */);Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);......}......// 重点* 第2分支Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ensureActivitiesVisible");mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);......}Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}

我在代码上加了几个 Trace 稍后再看,当前分析 onStop 流程所以只看第2分支触发的 ensureActivitiesVisible 流程,这个流程就是界面上有啥风吹草动,SystemService 端需要确保手机屏幕上Activity正确的显示。

根据上面的堆栈和整理出的调用链 RootWindowContainer::ensureActivitiesVisible 最终会执行到 EnsureActivitiesVisibleHelper::process 来处理当前 Task 下 Activity 的可见性。

EnsureActivitiesVisibleHelper的相关处理后面单独放一个章节详细解释,是ensureActivitiesVisible 流程非常重要的一环,目前可以自行了解或以黑盒概念理解

直接看 EnsureActivitiesVisibleHelper::setActivityVisibilityState 对 SourceActivity 的 stop 逻辑是如何处理的。

# EnsureActivitiesVisibleHelper// 当前Task栈顶是否有Activityprivate boolean mAboveTop;// 设置Activity可见性private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,final boolean resumeTopActivity) {......// SourceActivity 所在的Task 被遮挡了,所以mBehindFullyOccludedContainer为truer.updateVisibilityIgnoringKeyguard(mBehindFullyOccludedContainer);// 自然是返回不可见final boolean reallyVisible = r.shouldBeVisibleUnchecked();......if (reallyVisible) {// 忽略可见处理} else {if (DEBUG_VISIBILITY) {Slog.v(TAG_VISIBILITY, "Make invisible? " + r+ " finishing=" + r.finishing + " state=" + r.getState()+ " containerShouldBeVisible=" + mContainerShouldBeVisible+ " behindFullyOccludedContainer=" + mBehindFullyOccludedContainer+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);}// 不可见的处理 --使Activity不可见r.makeInvisible();}......// launcher处理}

所以执行 ActivityRecord::makeInvisible 方法开始设置 SourceActivity 不可见。

2 设置Activity不可见 – ActivityRecord::makeInvisible

makeInvisible 方法触发的调用链:

ActivityRecord::makeInvisibleActivityRecord::setVisibility  -- setVisibility通用流程ActivityRecord::setVisibilityActivityRecord::setVisibleRequestedActivityRecord::addToStoppingActivityTaskSupervisor.mStoppingActivities::add --添加当前Activity到集合ActivityTaskSupervisor::scheduleIdle  -- 发送IDLE_NOW_MSG--------------处理消息-------------------ActivityTaskSupervisor$ActivityTaskSupervisorHandler::handleMessageActivityTaskSupervisor$ActivityTaskSupervisorHandler::handleMessageInnerActivityTaskSupervisor$ActivityTaskSupervisorHandler::activityIdleFromMessageActivityTaskSupervisor::activityIdleInternalActivityTaskSupervisor::processStoppingAndFinishingActivities -- 热启动第一次执行到这时因条件不满足不会执行后续逻辑

看一下代码执行流程。

# ActivityRecordvoid makeInvisible() {// mVisibleRequested 为false表示当前 Activity 已经在处理可见性逻辑了,不需要执行后面的逻辑, if (!mVisibleRequested) {if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);return;}// Now for any activities that aren't visible to the user, make sure they no longer are// keeping the screen frozen.// 对于不可见的Activity,需要开始真正的处理了if (DEBUG_VISIBILITY) {Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState());}try {final boolean canEnterPictureInPicture = checkEnterPictureInPictureState("makeInvisible", true /* beforeStopping */);// Defer telling the client it is hidden if it can enter Pip and isn't current paused,// stopped or stopping. This gives it a chance to enter Pip in onPause().// 画中画相关final boolean deferHidingClient = canEnterPictureInPicture&& !isState(STARTED, STOPPING, STOPPED, PAUSED);setDeferHidingClient(deferHidingClient);// 重点* 1. 设置为不可见 ,会将 mVisibleRequested 设置为falsesetVisibility(false);switch (getState()) {case STOPPING:case STOPPED:// Reset the flag indicating that an app can enter picture-in-picture once the// activity is hiddensupportsEnterPipOnTaskSwitch = false;break;case RESUMED:case INITIALIZING:case PAUSING:case PAUSED:case STARTED:// 重点* 2. 加入到Stop列表addToStopping(true /* scheduleIdle */,canEnterPictureInPicture /* idleDelayed */, "makeInvisible");break;default:break;}} catch (Exception e) {// Just skip on any failure; we'll make it visible when it next restarts.Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e);}}
    1. 调用 setVisibility 方法设置为不可见
    1. 根据 state 做了一些处理,STOPPING 和 STOPPED 的情况下就设置了一个画中画的标志位,其他的几个状态会执行 addToStopping

方法前面的 mVisibleRequested 唯一赋值的地方在 ActivityRecord::setVisibleRequested 方法中,值为可见性,所以这个变量表示: 当前Activity被设置的可见性的值。

makeInvisible 方法是要将 Activity 设置为不可见,所以方法开始的时候如果 mVisibleRequested 是 false, 说明已经在做这件事了, 就不需要执行后面的逻辑了。

然后中间有一段画中画的逻辑处理,这段当前不需要关注。

再下面就是getState() 的返回值处理,当前执行到这里的是 SourceActivity 的 activityPaused 流程,所以这里的 getState() 返回的是 PAUSED ,这个可以通过上面的log确认。

2.1 setVisibility 方法

看一眼 setVisibility方法主要做了什么

# ActivityRecordvoid setVisibility(boolean visible, boolean deferHidingClient) {......ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,"setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",token, visible, appTransition, isVisible(), mVisibleRequested,Debug.getCallers(6));......// 处理 DisplayContent 下的2个集合displayContent.mOpeningApps.remove(this);displayContent.mClosingApps.remove(this);......// 1. 给 mVisibleRequested 赋值setVisibleRequested(visible);......// 2. 处理 DisplayContent 下的2个集合if (visible) {displayContent.mOpeningApps.add(this);mEnteringAnimation = true;} else if (mVisible) {displayContent.mClosingApps.add(this);mEnteringAnimation = false;}......// 3. 提交可见性更新commitVisibility(visible, true /* performLayout */);updateReportedVisibilityLocked();}
    1. 执行 setVisibleRequested 方法,内部会对 mVisibleRequested 变量赋值
    1. 处理 DisplayContent类维护的2个列表, 分别对应打开和关闭的应用(这个很重要)
    1. 执行 commitVisibility 方法,这里会最终可见性

继续看主流程 addToStopping 方法。

addToStopping 流程非常重要

3. ActivityRecord::addToStopping 方法

# ActivityRecordfinal ActivityTaskSupervisor mTaskSupervisor;void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {if (!mTaskSupervisor.mStoppingActivities.contains(this)) {// 打印 event日志EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),shortComponentName, reason);// 重点* 1. 唯一将Activity添加到 mStoppingActivities 集合中的代码mTaskSupervisor.mStoppingActivities.add(this);}final Task rootTask = getRootTask();......if (scheduleIdle || forceIdle) {// 打印Proto日志ProtoLog.v(WM_DEBUG_STATES,"Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);if (!idleDelayed) {// 重点* 2. 一般都是立即执行,所以是走这(可见根据上面log的immediate值确认)mTaskSupervisor.scheduleIdle();} ......} ......}

这个方法做了2件事

    1. 将当前这个Activity 添加到 ActivityTaskSupervisor 下的 mStoppingActivities 集合
    1. 执行 ActivityTaskSupervisor::scheduleIdle 内部会发送 “IDLE_NOW_MSG” 消息,进而触发后续 stop 逻辑

这个方法正常是执行 scheduleIdle 逻辑的, 另外有 Events 和Proto 2个日志的打印,如果发现有问题可以仔细看看相关变量的打印。

ActivityTaskSupervisor::scheduleIdle 方法如下:

# ActivityTaskSupervisorfinal void scheduleIdle() {if (!mHandler.hasMessages(IDLE_NOW_MSG)) {// 发送消息,打堆栈if (DEBUG_IDLE) Slog.d(TAG_IDLE, "scheduleIdle: Callers=" + Debug.getCallers(4));mHandler.sendEmptyMessage(IDLE_NOW_MSG);}}

这个方法主要就是发送了“IDLE_NOW_MSG” 消息,并且打印了debug的堆栈。

冷启动的话 ActivityTaskSupervisor::scheduleIdle 的调用链就上面分析的一个,但是应用内启动Activity 根据log打印的堆栈发现会有3个调用链,这边也整理一下3个调用链,感兴趣的可以自己跟一下

Callers=com.android.server.wm.ActivityRecord.addToStopping:6239com.android.server.wm.ActivityRecord.makeInvisible:5810com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState:240com.android.server.wm.EnsureActivitiesVisibleHelper.process:153 
Callers=com.android.server.wm.ActivityTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded:2175com.android.server.wm.ActivityRecord.onAnimationFinished:7473com.android.server.wm.WindowContainer$$ExternalSyntheticLambda4.onAnimationFinished:2com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0$com-android-server-wm-SurfaceAnimator:133 
Callers=com.android.server.wm.ActivityTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded:2175com.android.server.wm.ActivityRecord.onWindowsVisible:6532com.android.server.wm.ActivityRecord.updateReportedVisibilityLocked:6633com.android.server.wm.WindowManagerService$4.onAppTransitionFinishedLocked:1154 

4 “IDLE_NOW_MSG”的处理 ActivityTaskSupervisor – activityIdleFromMessage

消息的执行也在 ActivityTaskSupervisor 类。

# ActivityTaskSupervisorprivate final class ActivityTaskSupervisorHandler extends Handler {@Overridepublic void handleMessage(Message msg) {synchronized (mService.mGlobalLock) {// 处理消息if (handleMessageInner(msg)) {return;}}......}private boolean handleMessageInner(Message msg) {......case IDLE_NOW_MSG: {if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);// 打印activityIdleFromMessage((ActivityRecord) msg.obj, false /* fromTimeout */);} break;......}}

处理消息的时候也有log打印,“msg.obj” 为null。

继续看处理的代码

# ActivityTaskSupervisorprivate void activityIdleFromMessage(ActivityRecord idleActivity, boolean fromTimeout) {activityIdleInternal(idleActivity, fromTimeout,fromTimeout /* processPausingActivities */, null /* config */);}void activityIdleInternal(ActivityRecord r, boolean fromTimeout,boolean processPausingActivities, Configuration config) {// 重点* 1 logif (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);// 重点* 2. ActivityRecord 不为null才执行内部逻辑if (r != null) {// 重点* 3. logif (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternal: Callers="+ Debug.getCallers(4));......}......// Atomically retrieve all of the other things to do. 原子检索所有其他要做的事情// 重点* 4. 看方法名是处理 停止和finish的Activity辑在这里processStoppingAndFinishingActivities(r, processPausingActivities, "idle");if (DEBUG_IDLE) {// 重点* 5. log Slogf.i(TAG, "activityIdleInternal(): r=%s, mStartingUsers=%s", r, mStartingUsers);}......}

这里有5个重点,其中1,3,5都是log,很少会将log标记为重点,当前这么做是因为这个方法会执行两次,需要通过这3个log来区分

现在是分析第一次执行,根据前面的分析参数 r 是null,所以执行 processStoppingAndFinishingActivities 方法。

log中搜索"Activity idle: "可以有以下2次打印

Line 5664: 04-01 20:50:30.411  8585  8751 V ActivityTaskManager: Activity idle: null
Line 19079: 04-01 20:50:31.171  8585  9527 V ActivityTaskManager: Activity idle: ActivityRecord{95d53d7 u0 com.google.android.dialer/.extensions.GoogleDialtactsActivity} t26}

2次打印的行数和时间有很大的差距,说明不是一个时机执行的,当前分析的是第一次执行,是由 SourceActivity 执行 activityPaused 的时候会触发 addToStopping 流程。这一次参数 r 为null。

第二次打印的 r 为 TargetActivity 具体执行流程下面会分析。

4.1 processStoppingAndFinishingActivities 逻辑(其实啥也没干)

# ActivityTaskSupervisor/*** Processes the activities to be stopped or destroyed. This should be called when the resumed* 处理要停止或销毁的Activity。这应该在resumed时调用* activities are idle or drawn.*/private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,boolean processPausingActivities, String reason) {// 准备要执行 Stop 的Activity 集合 ArrayList<ActivityRecord> readyToStopActivities = null;// 重点 * 1. 遍历mStoppingActivitiesfor (int i = mStoppingActivities.size() - 1; i >= 0; --i) {// 获取到ActivityRecord (当前分析场景就1个)final ActivityRecord s = mStoppingActivities.get(i);final boolean animating = s.isAnimating(TRANSITION | PARENTS,ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)|| s.inTransition();// 日志ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "+ "finishing=%s", s, s.nowVisible, animating, s.finishing);// 条件满足才执行if (!animating || mService.mShuttingDown) {......// 打印 准备stop的logProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);if (readyToStopActivities == null) {readyToStopActivities = new ArrayList<>();}// 重点 * 2. 添加进集合readyToStopActivities.add(s);// 从集合中移除mStoppingActivities.remove(i);}}// 重点 * 3. 遍历readyToStopActivitiesfinal int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();for (int i = 0; i < numReadyStops; i++) {final ActivityRecord r = readyToStopActivities.get(i);// 检查该ActivityRecord对象是否在历史记录中。  if (r.isInHistory()) {// 如果该ActivityRecord对象正在结束(可能是用户或系统触发的结束操作)。if (r.finishing) {// TODO(b/137329632): Wait for idle of the right activity, not just any.r.destroyIfPossible(reason);} else {// 重点* 4. 如果ActivityRecord对象不在结束状态,则尝试停止它r.stopIfPossible();}}}......}

这个方法的逻辑还是很重要的,不过当前这一次执行进来,因为条件不满足,其实相当于啥也没干。

    1. 这里遍历的集合,在 ActivityRecord::addToStopping 方法中看到对其赋值
    1. 满足条件的会被添加进 readyToStopActivities 集合, 进入if的条件刚好log也有打印
V WindowManager: Stopping ActivityRecord{f40797d u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t20}: nowVisible=true animating=true finishing=false  mShuttingDown=false

animating 和 mShuttingDown 都不满足条件,所以不会进入。自如也不会有下面的"Ready to stop:"的打印,因为这里没进入执行 readyToStopActivities 集合没有元素,所以重点3也不会执行。

但是第二次执行 ActivityTaskSupervisor::activityIdleInternal 方法的时候的日志会有后续的打印,也就是说会执行到 ActivityRecord::stopIfPossible ,第二次的log如下

04-01 20:50:31.182  8585  9527 V WindowManager: Stopping ActivityRecord{f40797d u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t20}: nowVisible=false animating=false finishing=false  mShuttingDown=false
04-01 20:50:31.182  8585  9527 V WindowManager: Ready to stop: ActivityRecord{f40797d u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t20}

第二次相关的逻辑有个印象几个,后面会再分析

5 小结

在正确冷启动流程的开始 SourceActivity 执行 activityPaused 的时候会触发 addToStopping 流程,这个流程会执行到 ActivityTaskSupervisor:: processStoppingAndFinishingActivities 方法,但是由于条件不满足,在这个方法中不会有什么实质性的处理。(后续还有会流程第二次触发该方法)

因此 addToStopping 流程最重要的事就是将 SourceActivity 添加到了 ActivityTaskSupervisor 类下的 mStoppingActivities 集合中。等后面条件满足再触发 ActivityTaskSupervisor:: processStoppingAndFinishingActivities 方法时就会执行 ActivityRecord::stopIfPossible 流程了。

“wm_add_to_stopping” 日志的线索跟到这里就结束了,后面的流程还有2个线索

    1. 第二个和 stop 有关的events 日志为 “wm_stop_activity” 并且已知在 “wm_on_resume_called”后打印
    1. ActivityTaskSupervisor::activityIdleInternal 的第二次执行,并且第二次执行到 ActivityTaskSupervisor::processStoppingAndFinishingActivities 方法会触发后续逻辑创建 Stop 的事务。

相关文章:

【Android 源码分析】Activity生命周期之onStop-1

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…...

【Unity】本地化实现

个人向笔记。 1 前言 记录一下自己的本地化实现思路&#xff0c;暂时只讲本文的本地化实现。 2 文本本地化方案-个人 本地化实现是基于Luban的。自己使用Luban实现了一个“配置表模块”&#xff0c;又实现了一个“全局配置模块”&#xff0c;之后再基于这两个模块实现了“文本…...

Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案

引言 在开发过程中我们可能需要这样的树形结构: [{"data": {"name": "牛奶"},"children": [{"data": {"name": "蒙牛"}, },{"data": {"name": "伊利"}, }]},{"da…...

【Docker从入门到进阶】06.常见问题与解决方案 07.总结与资源

6. 常见问题与解决方案 在使用Docker进行开发和部署过程中&#xff0c;可能会遇到各种问题。以下是一些常见问题及其解决方案&#xff1a; 容器启动失败和调试 在使用 Docker 时&#xff0c;容器启动失败或立即退出可能会导致一定的困扰&#xff0c;以下是进一步深入解决该问…...

快速排序的非递归实现:借助栈实现、借助队列实现

目录 用栈实现快速排序 1.用栈实现非递归快速排序的思路步骤 1.1.思路步骤 2.用栈实现非递归快速排序的代码 3.用栈实现非递归快速排序的整个工程 3.1.QuickSortNonR.h 3.2.QuickSortNonR.c 3.3.Stack.h 3.4.Stack.c 用队列实现非递归快速排序 1.用队列实现非递归快…...

Finops成本优化企业实践-可视化篇

引言&#xff1a;上一章讨论了finops的一些方法论&#xff0c;笔者在拿到finops官方认证finops-engineer certificate之后&#xff0c;将方法论运用到所在项目组中&#xff0c;并于今年完成了40%的费用节省。在此将这些实践方法总结沉淀&#xff0c;与大家分享。实践包括三篇&a…...

Spring Boot中线程池使用

说明&#xff1a;在一些场景&#xff0c;如导入数据&#xff0c;批量插入数据库&#xff0c;使用常规方法&#xff0c;需要等待较长时间&#xff0c;而使用线程池可以提高效率。本文介绍如何在Spring Boot中使用线程池来批量插入数据。 搭建环境 首先&#xff0c;创建一个Spr…...

Python机器学习:自然语言处理、计算机视觉与强化学习

&#x1f4d8; Python机器学习&#xff1a;自然语言处理、计算机视觉与强化学习 目录 ✨ 自然语言处理&#xff08;NLP&#xff09; 文本预处理&#xff1a;分词、去停用词词向量与文本分类&#xff1a;使用Word2Vec与BERT &#x1f306; 计算机视觉基础 图像预处理与增强目标…...

Vue2 + ElementUI + axios + VueRouter入门

之前没有pc端开发基础&#xff0c;工作需要使用若依框架进行了一年的前端开发.最近看到一个视频框架一步步集成&#xff0c;感觉颇受启发&#xff0c;在此记录一下学习心得。视频链接:vue2element ui 快速入门 环境搭建和依赖安装 安装nodejs安装Vue Cli使用vue create proje…...

GO网络编程(四):海量用户通信系统2:登录功能核心【重难点】

目录 一、C/S详细通信流程图二、消息类型定义与json标签1. 消息类型定义2. JSON标签3.结构体示例及其 JSON 表示&#xff1a;4.完整代码与使用说明 三、客户端发送消息1. 连接到服务器2. 准备发送消息3. 创建 LoginMes 并序列化4. 将序列化后的数据嵌入消息结构5. 序列化整个 M…...

某项目实战分析代码二

某项目实战分析代码二 此次分析的是protobuf的使用操作流程具体实现 3. 业务数据分析3.1 客户端3.2 服务器端简单案例 此次分析的是protobuf的使用 Protocol Buffer( 简称 Protobuf) 是Google公司内部的混合语言数据标准&#xff0c;它是一种轻便高效的结构化数据存储格式&…...

全面指南:探索并实施解决Windows系统中“mfc140u.dll丢失”的解决方法

当你的电脑出现mfc140u.dll丢失的问题是什么情况呢&#xff1f;mfc140u.dll文件依赖了什么&#xff1f;mfc140u.dll丢失会导致电脑出现什么情况&#xff1f;今天这篇文章就和大家聊聊mfc140u.dll丢失的解决办法。希望能够有效的帮助你解决这问题。 哪些程序依赖mfc140u.dll文件…...

QT学习笔记1(QT和QT creator介绍)

QT学习笔记1&#xff08;QT和QT creator介绍&#xff09; Qt 是一个跨平台的应用开发框架&#xff0c;主要用于图形用户界面&#xff08;GUI&#xff09;应用的开发&#xff0c;但也支持非GUI程序的开发。Qt 支持多种平台&#xff0c;如Windows、macOS、Linux、iOS和Android&a…...

存储电话号码的数据类型,用 int 还是用 string?

在 Java 编程中&#xff0c;存储电话号码的选择可以通过两种常见方式进行&#xff1a;使用 int 类型或 String 类型。这种选择看似简单&#xff0c;但实际上涉及到 JVM 内部的字节码实现、内存优化、数据表示、以及潜在的可扩展性问题。 Java 基本数据类型与引用数据类型的差异…...

【目标检测】工程机械车辆数据集2690张4类VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2694 标注数量(xml文件个数)&#xff1a;2694 标注数量(txt文件个数)&#xff1a;2694 标注…...

target_link_libraries()

target_link_libraries() 是 CMake 中的一个命令&#xff0c;用于指定目标&#xff08;如可执行文件或库&#xff09;所依赖的其他库。其主要作用包括&#xff1a; 链接库&#xff1a;将指定的库链接到目标上&#xff0c;使目标能够调用这些库中的函数和使用其功能。 管理依赖…...

Javascript数组研究09_Array.prototype[Symbol.unscopables]

Symbol.unscopables 是 JavaScript 中一个相对较新的符号&#xff08;Symbol&#xff09;&#xff0c;用于控制对象属性在 with 语句中的可见性。它主要用于内置对象&#xff0c;如 Array.prototype&#xff0c;以防止某些方法被引入到 with 语句的作用域中&#xff0c;避免潜在…...

SkyWalking 自定义链路追踪

对项目中的业务方法&#xff0c;实现链路追踪&#xff0c;方便我们排查问题 引入依赖 <!‐‐ SkyWalking 工具类 ‐‐> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm‐toolkit‐trace</artifactId> <vers…...

Linux驱动开发(速记版)--设备模型

第八十章 设备模型基本框架-kobject 和 kset 80.1 什么是设备模型 设备模型使Linux内核处理复杂设备更高效。 字符设备驱动适用于简单设备&#xff0c;但对于电源管理和热插拔&#xff0c;不够灵活。 设备模型允许开发人员以高级方式描述硬件及关系&#xff0c;提供API处理设备…...

动手学深度学习(李沐)PyTorch 第 6 章 卷积神经网络

李宏毅-卷积神经网络CNN 如果使用全连接层&#xff1a;第一层的weight就有3*10^7个 观察 1&#xff1a;检测模式不需要整张图像 很多重要的pattern只要看小范围即可 简化1&#xff1a;感受野 根据观察1 可以做第1个简化&#xff0c;卷积神经网络会设定一个区域&#xff0c…...

新编英语语法教程

新编英语语法教程 1. 新编英语语法教程 (第 6 版) 学生用书1.1. 目录1.2. 电子课件 References A New English Grammar Coursebook 新编英语语法教程 (第 6 版) 学生用书新编英语语法教程 (第 6 版) 教师用书 1. 新编英语语法教程 (第 6 版) 学生用书 https://erp.sflep.cn/…...

Golang 服务器虚拟化应用案例

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…...

Elasticsearch基础_4.ES搜索功能

文章目录 一、搜索辅助功能1.1、指定返回的字段1.2、结果计数1.3、结果分页 二、搜索匹配功能2.1、查询所有文档2.2、term级别查询2.2.1、term查询2.2.2、terms查询2.2.3、range查询2.2.4、exists查询 2.3、布尔查询2.3.1、must&#xff0c;should&#xff0c;must_not2.3.2、f…...

Elasticsearch要点简记

Elasticsearch要点简记 1、ES概述2、基础概念&#xff08;1&#xff09;索引、文档、字段&#xff08;2&#xff09;映射&#xff08;3&#xff09;DSL 3、架构原理4、索引字段的数据类型5、ES的三种分页方式&#xff08;1&#xff09;深度分页&#xff08;fromsize&#xff09…...

【通信协议】IIC通信协议详解

IIC&#xff08;Inter-Integrated Circuit&#xff09;通信协议&#xff0c;又称为I2C&#xff08;Inter-Integrated Circuit 2&#xff09;协议&#xff0c;是一种广泛使用的串行通信协议。它由Philips Semiconductor&#xff08;现NXP Semiconductors&#xff09;开发&#x…...

2024年中国科技核心期刊目录(社会科学卷)

2024年中国科技核心期刊目录 &#xff08;社会科学卷&#xff09; 序号 期刊代码 期刊名称 1 SC02 JOURNAL OF S…...

用Python集成免费IP归属地查询API

IP查询的优势是什么&#xff1f; IP查询是一种强大的工具&#xff0c;能够快速提供关于IP地址的信息&#xff0c;如地理位置、互联网服务提供商&#xff08;ISP&#xff09;、连接类型等。这些数据在多种场景下都非常有用&#xff0c;帮助用户理解网络环境和用户行为。 首先&…...

C 数组

C 数组 数组是C语言中的一种基本数据结构&#xff0c;用于存储一系列相同类型的数据。它是连续的内存分配&#xff0c;允许通过索引快速访问元素。本文将详细介绍C数组的概念、使用方法、以及注意事项。 1. 数组的概念 数组是一个集合&#xff0c;可以存储一定数量的元素。在…...

【Unity】unity安卓打包参数(个人复习向/有不足之处欢迎指出/侵删)

1.Texture Compression 纹理压缩 设置发布后的纹理压缩格式 Use Player Settings:使用在播放器设置中设置的纹理压缩格式 ETC&#xff1a;使用ETC格式&#xff08;兼容&#xff09; ETC2&#xff1a;使用ETC2格式&#xff08;很多设备不支持&#xff09; ASTC&#xff1a;使用…...

C0016.Clion中qDebug()打印输出中文时,都是问号??????的解决办法

问题描述 在clion中使用qDebug打印输出中文内容时&#xff0c;都是&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;如下图&#xff1a; 注意&#xff1a;修改该文件的编码格式就行&#xff0c;该文件名为apr.cpp&#xff1b; 解决办法...