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

忽然有一天,我想要做一件事:去代码中去验证那些曾经被"灌输"的理论。

-- 服装学院的IT男

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

less 复制代码
// 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 的应用进程处理。

由于篇幅原因,分为以下2篇:

Activity生命周期之onStop-1

Activity生命周期之onStop-2

本篇为第一篇,介绍system_service进程是如何把SourceActivity添加进stop集合。

第一步:addToStopping 流程

1 调用链概览

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

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

yaml 复制代码
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】流程之前整理的调用链如下:

arduino 复制代码
ActivityClientController::activityPaused
    ActivityRecord::activityPaused
        TaskFragment::completePause
            RootWindowContainer::resumeFocusedTasksTopActivities       --分支1 ,再次执行 resumeFocusedTasksTopActivities
                RootWindowContainer::resumeFocusedTasksTopActivities
                    Task::resumeTopActivityUncheckedLocked
                        Task::resumeTopActivityInnerLocked
                            TaskFragment::resumeTopActivity
                                ActivityTaskSupervisor::startSpecificActivity                           --触发 startSpecificActivity 判断应用是否创建
            RootWindowContainer::ensureActivitiesVisible              --分支2
                RootWindowContainer::ensureActivitiesVisible
                    DisplayContent::ensureActivitiesVisible 
                        WindowContainer::forAllRootTasks  --忽略固定逻辑
                            Task::ensureActivitiesVisible
                                Task::forAllLeafTasks --忽略固定逻辑
                                    TaskFragment::updateActivityVisibilities
                                        EnsureActivitiesVisibleHelper::process
                                            EnsureActivitiesVisibleHelper::setActivityVisibilityState
                                                EnsureActivitiesVisibleHelper::makeVisibleAndRestartIfNeeded
                                                    ActivityTaskSupervisor::startSpecificActivity       --触发 startSpecificActivity 判断应用是否创建

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

scss 复制代码
# TaskFragment

    void 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) {
            ......
            // 设置窗口状态为PAUSED
            prev.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 逻辑是如何处理的。

arduino 复制代码
# EnsureActivitiesVisibleHelper

    // 当前Task栈顶是否有Activity
    private boolean mAboveTop;

    // 设置Activity可见性
    private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
            final boolean resumeTopActivity) {
        ......

        // SourceActivity 所在的Task 被遮挡了,所以mBehindFullyOccludedContainer为true
        r.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 方法触发的调用链:

php 复制代码
ActivityRecord::makeInvisible
    ActivityRecord::setVisibility  -- setVisibility通用流程
        ActivityRecord::setVisibility
            ActivityRecord::setVisibleRequested
    ActivityRecord::addToStopping
        ActivityTaskSupervisor.mStoppingActivities::add --添加当前Activity到集合
        ActivityTaskSupervisor::scheduleIdle  -- 发送IDLE_NOW_MSG

        --------------处理消息-------------------
        ActivityTaskSupervisor$ActivityTaskSupervisorHandler::handleMessage
            ActivityTaskSupervisor$ActivityTaskSupervisorHandler::handleMessageInner
                ActivityTaskSupervisor$ActivityTaskSupervisorHandler::activityIdleFromMessage
                    ActivityTaskSupervisor::activityIdleInternal
                        ActivityTaskSupervisor::processStoppingAndFinishingActivities -- 热启动第一次执行到这时因条件不满足不会执行后续逻辑

看一下代码执行流程。

java 复制代码
# ActivityRecord

    void 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 设置为false
            setVisibility(false);
            switch (getState()) {
                case STOPPING:
                case STOPPED:
                    // Reset the flag indicating that an app can enter picture-in-picture once the
                    // activity is hidden
                    supportsEnterPipOnTaskSwitch = 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方法主要做了什么

csharp 复制代码
# ActivityRecord

    void 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 方法

arduino 复制代码
# ActivityRecord

    final 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 方法如下:

scss 复制代码
# ActivityTaskSupervisor

    final 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个调用链,感兴趣的可以自己跟一下

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

4 "IDLE_NOW_MSG"的处理 ActivityTaskSupervisor -- activityIdleFromMessage

消息的执行也在 ActivityTaskSupervisor 类。

scala 复制代码
# ActivityTaskSupervisor
    private final class ActivityTaskSupervisorHandler extends Handler {
                @Override
        public 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。

继续看处理的代码

typescript 复制代码
# ActivityTaskSupervisor

        private void activityIdleFromMessage(ActivityRecord idleActivity, boolean fromTimeout) {
            activityIdleInternal(idleActivity, fromTimeout,
                    fromTimeout /* processPausingActivities */, null /* config */);
        }
        void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
            boolean processPausingActivities, Configuration config) {
            // 重点* 1 log
            if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);
            // 重点* 2. ActivityRecord 不为null才执行内部逻辑
            if (r != null) {
                // 重点* 3. log
                if (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次打印

yaml 复制代码
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 逻辑(其实啥也没干)

java 复制代码
# 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. 遍历mStoppingActivities
                for (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的log
                        ProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);
                        if (readyToStopActivities == null) {
                            readyToStopActivities = new ArrayList<>();
                        }
                        // 重点 * 2. 添加进集合
                        readyToStopActivities.add(s);
                        // 从集合中移除
                        mStoppingActivities.remove(i);
                    }
                }
                // 重点 * 3. 遍历readyToStopActivities
                final 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也有打印
ini 复制代码
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如下

bash 复制代码
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 的事务。
相关推荐
肖。354878709420 分钟前
[技巧-11]AndroidManifest.xml完善小技巧。
android
小羊子说36 分钟前
Android 车机开发中常用的adb 脚本(更新中)
android·linux·adb·性能优化·车载系统
用户76074953978343 分钟前
Android页面四大布局运行结果
android
风往哪边走1 小时前
搜索框自定义
android
用户8249281925362 小时前
把android资源类型详解
android
IT观测2 小时前
深度分析俩款主流移动统计工具Appvue和openinstall
android·java·数据库
用户338675581952 小时前
Android 四种常用布局完全解析(附实战项目截图)
android
用户5087532168442 小时前
Android 资源类型全解析:深入理解四种常用布局
android
XiaoLeisj2 小时前
Android 文件存储实战:从应用私有目录读写到网络文件落盘与公共存储接入
android·java·网络·文件操作
恋猫de小郭2 小时前
Android Studio Panda 2 ,支持 AI 用 Vibe Coding 创建项目
android·前端·flutter