Android Framework AMS(06)startActivity分析-3(补充:onPause和onStop相关流程解读)

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要解读AMS通过startActivity启动Activity的整个流程的补充,更新了startActivity流程分析部分。

一般来说,有Activity启动,就有Activity退到后台。那么后者这个操作具体是怎样的呢?我们以startPausingLocked方法和stopActivityLocked方法为入口分别对到activity的onPause和AMS到onStop流程进行分析。

该部分是AMS.startActivity运行中生命周期的补充,毕竟startActivity关注onCreate、onStart、onResume ,但activity的生命周期还涉及onPause、onStop、onDestroy。本章主要介绍onPause、onStop。最后以onStop为例介绍了下APP中回调超时的设计理念。

1 startPausingLocked方法解读(onPause处理)

在之前AMS.startActivity的流程分析中执行resume相关操作时就已经开始执行startPausingLocked方法了。startPausingLocked的调用入口是resume相关函数,代码如下所示:

java 复制代码
//ActivityStack
    //关键流程:step1
    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        // 检查是否已经在执行恢复顶部 Activity 的操作,防止递归调用
        if (mStackSupervisor.inResumeTopActivity) {
            return false;   // 如果已经在执行恢复操作,则直接返回 false
        }
 
        // 初始化结果变量,用于记录恢复操作是否成功
        boolean result = false;
 
        try {
            // 设置一个标志,表示正在执行恢复顶部 Activity 的操作,防止递归
            mStackSupervisor.inResumeTopActivity = true;
            //锁屏状态相关处理
            //...
            //关键方法:调用内部方法实际执行恢复顶部 Activity 的操作
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            // 恢复完成后,重置正在执行恢复操作的标志
            mStackSupervisor.inResumeTopActivity = false;
        }
 
        // 返回恢复操作的结果
        return result;
    }
 
    //关键流程:step2
    final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
        //... 
        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        if (mResumedActivity != null) {
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }
        if (pausing) {
            if (next.app != null && next.app.thread != null) {
                mService.updateLruProcessLocked(next.app, true, null);
            }
            return true;
        }
        //...
        return true;
    }

这里调用了startPausingLocked方法,当新启动一个activity时,系统将先处理当前的activity,即调用该方法来pause当前activity,代码实现如下:

java 复制代码
//ActivityStack
    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        // 如果已经在暂停一个 Activity,完成暂停操作。
        if (mPausingActivity != null) {
            completePauseLocked(false);
        }
        // 记录当前处于前台的 Activity。
        ActivityRecord prev = mResumedActivity;
        // 如果没有前台 Activity,且不是正在恢复状态,尝试恢复顶层 Activity。
        if (prev == null) {
            if (!resuming) {
                mStackSupervisor.resumeTopActivitiesLocked();
            }
            return false; // 如果没有前台 Activity,返回 false。
        }

        // 如果当前 Activity 没有父 Activity,暂停所有子栈。
        if (mActivityContainer.mParentActivity == null) {
            mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
        }

        // 将当前前台 Activity 设置为 null,准备暂停。
        mResumedActivity = null;
        // 标记 prev 为正在暂停的 Activity。
        mPausingActivity = prev;
        // 记录最后一个暂停的 Activity。
        mLastPausedActivity = prev;
        // 确定最后一个没有历史记录的 Activity。
        mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
        // 更新 prev Activity 的状态为 PAUSING。
        prev.state = ActivityState.PAUSING;
        // 更新任务的活动时间。
        prev.task.touchActiveTime();
        // 清除启动时间。
        clearLaunchTime(prev);
        // 获取顶层运行的 Activity。
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
        // 如果支持最近任务并且下一个 Activity 为空或者不显示或者不在同一个任务或者 UI 休眠,则更新缩略图。
        if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
            prev.updateThumbnailLocked(screenshotActivities(prev), null);
        }
        // 停止完全绘制的跟踪(可能是性能监控的一部分)。
        stopFullyDrawnTraceIfNeeded();

        // 更新 CPU 统计信息。
        mService.updateCpuStats();

        // 如果 prev 的应用和线程不为空,发送暂停 Activity 的请求。
        if (prev.app != null && prev.app.thread != null) {
            try {
                mService.updateUsageStats(prev, false);
                // 关键方法:调用当前Activity所在进程的schedulePauseActivity方法
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            } catch (Exception e) {
                // 异常处理(代码省略)。
            }
        } else {
            // 如果应用或线程为空,清除暂停的 Activity 记录。
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }

        // 如果系统不是在休眠或关闭状态,获取启动锁。
        if (!mService.isSleepingOrShuttingDown()) {
            mStackSupervisor.acquireLaunchWakelock();
        }

        // 如果正在暂停一个 Activity,处理是否等待暂停完成。
        if (mPausingActivity != null) {
            if (!uiSleeping) {
                // 如果 UI 不在休眠状态,暂停按键分发。
                prev.pauseKeyDispatchingLocked();
            }
            if (dontWait) {
                // 如果不需要等待,完成暂停并返回 false。
                completePauseLocked(false);
                return false;

            } else {
                // 如果需要等待,发送暂停超时的消息,并设置超时时间。
                Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
                msg.obj = prev;
                prev.pauseTime = SystemClock.uptimeMillis();
                mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
                return true;
            }

        } else {
            // 如果没有 Activity 正在暂停,尝试恢复顶层 Activity。
            if (!resuming) {
                mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
            }
            return false;
        }
    }

startPausingLocked 方法用于处理 Activity 的暂停逻辑。它首先检查是否有正在进行的暂停操作,如果有,则完成它。然后,它检查是否有前台 Activity,如果没有,则尝试恢复顶层 Activity。如果有前台 Activity,它会更新一些状态和变量,准备暂停操作。如果系统支持最近任务并且条件满足,它会更新 Activity 的缩略图。然后注意:关键点来了,它发送一个暂停 Activity 的请求到应用线程。如果系统不是在休眠或关闭状态,它会获取一个启动锁。最后,根据是否需要等待暂停完成,它要么立即返回,要么设置一个超时消息来处理暂停超时情况。这个方法返回一个布尔值,表示是否成功启动了暂停操作。

接下来关注schedulePauseActivity方法实现,主要是通过消息处理最后调用handlePauseActivity方法,过程中的代码实现如下:

java 复制代码
//ActivityThread
    //ApplicationThread
        public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            sendMessage(finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,token,
                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),configChanges);
        }
        //...
        //Handler消息处理
        private class H extends Handler {
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    //...
                    case PAUSE_ACTIVITY:
                        handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,(msg.arg1&2) != 0);
                        maybeSnapshot();
                        break;
                    //...
                }
            }
            //...
        }
        //...
        private void handlePauseActivity(IBinder token, boolean finished,
                        boolean userLeaving, int configChanges, boolean dontReport) {
            // 根据 token 查找对应的 ActivityClientRecord 对象。
            ActivityClientRecord r = mActivities.get(token);
            // 如果找到了对应的 ActivityClientRecord。
            if (r != null) {
                if (userLeaving) { // 如果用户正在离开 Activity,执行相关的处理。
                    performUserLeavingActivity(r);
                }

                r.activity.mConfigChangeFlags |= configChanges;
                // 关键方法:执行暂停 Activity 的操作。
                performPauseActivity(token, finished, r.isPreHoneycomb());

                // 如果应用的 target SDK 版本低于 Honeycomb(3.0),等待所有队列工作完成。
                if (r.isPreHoneycomb()) {
                    QueuedWork.waitToFinish();
                }

                // 如果不应该报告 Activity 暂停,跳过报告步骤。
                if (!dontReport) {
                    try {
                        // 关键方法:向 ActivityManager 报告 Activity 已暂停。
                        ActivityManagerNative.getDefault().activityPaused(token);
                    } catch (RemoteException ex) {
                        //...
                    }
                }
                mSomeActivitiesChanged = true;
            }
        }

这里开始我们关注关键方法performPauseActivity和通知AMS做其他处理的操作。详细解读如下。

1.1 performPauseActivity方法解读

接下来,一条路线是为了启动activity并调用activity的onPause方法,关键方法为:

java 复制代码
//ActivityThread
    //关键流程:step1
    final Bundle performPauseActivity(IBinder token, boolean finished,
            boolean saveState) {
        ActivityClientRecord r = mActivities.get(token);
        return r != null ? performPauseActivity(r, finished, saveState) : null;
    }
    //关键流程:step2
    final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState) {
        try {
            // 如果 Activity 没有完成(即没有调用过 finish()),并且需要保存状态,则调用 onSaveInstanceState()。
            if (!r.activity.mFinished && saveState) {
                callCallActivityOnSaveInstanceState(r);
            }
            // 标记 Activity 为已调用 onPause() 状态。
            r.activity.mCalled = false;
            // 调用 Activity 的 onPause() 方法。
            mInstrumentation.callActivityOnPause(r.activity);
        } catch (SuperNotCalledException e) {
            //...
        }
        // 标记 Activity 为已暂停状态。
        r.paused = true;

        // 获取所有注册的 onPaused 监听器,这些监听器将在 Activity 暂停时被通知。
        ArrayList<OnActivityPausedListener> listeners;
        synchronized (mOnPauseListeners) {
            listeners = mOnPauseListeners.remove(r.activity);
        }
        // 获取监听器列表的大小。
        int size = (listeners != null ? listeners.size() : 0);
        // 遍历所有监听器,调用它们的 onPaused() 方法。
        for (int i = 0; i < size; i++) {
            listeners.get(i).onPaused(r.activity);
        }

        // 如果 Activity 没有完成并且需要保存状态,则返回保存的状态 Bundle;否则返回 null。
        return !r.activity.mFinished && saveState ? r.state : null;
    }

这里较为简单,主要就是调用activty的onPause方法了(mInstrumentation.callActivityOnPause)。另一条路线是调用完通知AMS。接下来看看通知AMS都干了些啥。

1.2 通知AMS处理Pause的相关操作

在handlePauseActivity中最后部分执ActivityManagerNative.getDefault().activityPaused(token);调用到activityPaused方法,代码实现如下:

java 复制代码
//ActivityManagerService
    //...
    @Override
    public final void activityPaused(IBinder token) {
        final long origId = Binder.clearCallingIdentity();
        synchronized(this) {
            // 根据提供的 token 查找对应的 ActivityStack。
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                // 关键方法:传递 token 和 false。
                stack.activityPausedLocked(token, false);
            }
        }
        Binder.restoreCallingIdentity(origId);
    }

这里主要关注activityPausedLocked方法的实现,代码实现如下:

java 复制代码
//ActivityStack
    //关键流程:step1
    final void activityPausedLocked(IBinder token, boolean timeout) {
        // 根据提供的 token 查找对应的 ActivityRecord
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            // 从消息队列中移除任何与 PAUSE_TIMEOUT_MSG 相关的消息,避免暂停超时
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            // 如果当前正在暂停的 Activity 与找到的 ActivityRecord 相匹配
            if (mPausingActivity == r) {
                // 关键方法:完成暂停操作,传递 true
                completePauseLocked(true);
            }
            //...
        }
    }
    //关键流程:step2
    private void completePauseLocked(boolean resumeNext) {
        // 获取当前正在暂停的 ActivityRecord
        ActivityRecord prev = mPausingActivity;

        if (prev != null) {
            // 将 Activity 的状态设置为 PAUSED
            prev.state = ActivityState.PAUSED;

            // 如果 Activity 正在结束,则调用 finishCurrentActivityLocked 方法完成结束操作
            if (prev.finishing) {
                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
            } else if (prev.app != null) { // 如果 Activity 关联的应用不为空
                // 如果 Activity 正在等待可见状态,则更新状态并从等待列表中移除
                if (prev.waitingVisible) {
                    prev.waitingVisible = false;
                    mStackSupervisor.mWaitingVisibleActivities.remove(prev);
                }
                // 如果需要销毁 Activity,则调用 destroyActivityLocked 方法
                if (prev.configDestroy) {
                    destroyActivityLocked(prev, true, "pause-config");
                } else if (!hasVisibleBehindActivity()) { // 如果没有可见的后置 Activity
                    // 将当前 Activity 添加到停止的 Activity 列表中
                    mStackSupervisor.mStoppingActivities.add(prev);
                    // 根据条件决定是否调度空闲状态
                    if (mStackSupervisor.mStoppingActivities.size() > 3 ||
                            prev.frontOfTask && mTaskHistory.size() <= 1) {
                        mStackSupervisor.scheduleIdleLocked();
                    } else {
                        mStackSupervisor.checkReadyForSleepLocked();
                    }
                }
            } else {
                prev = null;
            }
            // 清空正在暂停的 Activity
            mPausingActivity = null;
        }

        // 如果需要恢复下一个 Activity
        if (resumeNext) {
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();
            // 如果服务没有进入休眠或关闭状态,恢复顶层 Activity
            if (!mService.isSleepingOrShuttingDown()) {
                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
            } else {
                // 检查是否准备好进入休眠状态
                mStackSupervisor.checkReadyForSleepLocked();
                ActivityRecord top = topStack.topRunningActivityLocked(null);
                // 如果顶层 Activity 为空或与当前暂停的 Activity 不同,恢复顶层 Activity
                if (top == null || (prev != null && top != prev)) {
                    mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
                }
            }
        }

        // 如果 prev 不为空,恢复按键分发
        if (prev != null) {
            prev.resumeKeyDispatchingLocked();
            //电池信息统计
        }

        // 通知任务栈发生了变化
        mService.notifyTaskStackChangedLocked();
    }

completePauseLocked 方法用于完成 Activity 的pause操作。它首先更新 Activity 的状态并处理与应用相关的各种情况,包括销毁、停止和恢复下一个 Activity。方法还处理 CPU 使用情况的更新,并在 Activity 状态变化时通知系统。这个方法确保了 Activity 在暂停时能够正确地保存状态和资源,同时为下一个 Activity 的恢复做好准备。

但是注意,这里涉及老activity的pause和新activity的resume操作,相信第一次看的伙伴并不容易理解,因此这里使用一个案例来帮忙理解。

1.3 场景案例解读completePauseLocked

这里使用一个场景案例来解读所谓的completePauseLocked在逻辑上到底是干了啥?便于理解。当使用 am 命令从 Launcher 界面启动一个 Settings Activity 时,Android 系统会经历以下步骤。每个步骤详细解读如下。

1.3.1 启动 Settings Activity:

系统通过 ActivityManagerService 的 startActivity() 方法启动新的 Settings Activity。

ActivityManagerService 负责协调启动过程,包括创建新的 Activity 记录(ActivityRecord)和调度启动。

1.3.2 Launcher 的 onPause() 调用:

在新的 Settings Activity 变得可见之前,当前的 Launcher Activity 需要进入暂停(paused)状态。

ActivityManagerService 会通知 Launcher Activity 调用它的 onPause() 生命周期方法。

这是通过 completePauseLocked() 方法完成的,该方法会更新 Launcher Activity 的状态为 PAUSED 并执行相关的暂停操作。

1.3.3 Settings Activity 的 onCreate() 和 onStart() 调用:

随着新的 Settings Activity 被创建,它的 onCreate() 和 onStart() 生命周期方法会被调用。

这些方法负责初始化 Activity,设置 UI,以及准备显示内容。

1.3.4 Settings Activity 的 onResume() 调用:

一旦 Settings Activity 准备好显示,它的 onResume() 方法会被调用。

onResume() 方法标志着 Activity 变得可见并开始与用户交互。

1.3.5 completePauseLocked() 中的逻辑:

如果 completePauseLocked() 方法被调用,它会处理 Launcher Activity 的暂停逻辑。

这包括调用 Launcher Activity 的 onPause() 方法,更新系统状态,以及准备恢复下一个 Activity。

如果 resumeNext 参数为 true,completePauseLocked() 方法会请求 ActivityManagerService 恢复下一个 Activity,即 Settings Activity。

1.3.6 Settings Activity 的恢复:

在 Launcher Activity 暂停后,ActivityManagerService 会负责恢复 Settings Activity。

这涉及到调用 Settings Activity 的 onResume() 方法,使其成为前台 Activity。

总结来说,在这种场景下,completePauseLocked() 方法主要负责处理 Launcher Activity 的暂停逻辑,而 Settings Activity 的 onResume() 方法会在 Launcher Activity 暂停后被调用,以确保用户体验的连续性和响应性。这个过程是由 ActivityManagerService 协调。

2 stopActivityLocked方法(onStop处理)

2.1 找到stopActivityLocked调用的入口Idler

stopActivityLocked藏的比较深,接下来我们从handleResumeActivity开始。想更多了解可参考文

章:Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起),文中

2.2.2 对handleResumeActivity方法有详细的解读,本次我们关注点不同,handleResumeActivity

关键代码解读如下:

java 复制代码
//ActivityThread
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
        unscheduleGcIdler();  // 取消垃圾回收的定时器,准备恢复 Activity
        mSomeActivitiesChanged = true;  // 标记有 Activity 状态改变
 
        // 关键方法:resume Activity 的操作
        ActivityClientRecord r = performResumeActivity(token, clearHide);  
        if (r != null) {
            //...
            if (!r.onlyLocalRequest) {
                r.nextIdle = mNewActivities;  // 设置下一个空闲的 Activity
                mNewActivities = r;  // 设置新的 Activity
                Looper.myQueue().addIdleHandler(new Idler());  // 添加空闲处理器
            }
            r.onlyLocalRequest = false;  // 清除本地请求标志
 
            if (reallyResume) {
                try {
                    ActivityManagerNative.getDefault().activityResumed(token);  // 通知 AMS Activity 已resume
                } catch (RemoteException ex) {
                }
            }
        } else {
            //...
        }
    }

这里我们主要关注一句话:

java 复制代码
Looper.myQueue().addIdleHandler(new Idler());

接下来我们对这句话进行详细解读:

  • Looper.myQueue():获取当前线程的消息队列。在 Android 中,每个线程都有自己的消息队列,而主线程的消息队列是处理 UI 更新和生命周期回调的核心。Looper 对象与消息队列关联,负责循环处理队列中的消息。
  • addIdleHandler():向消息队列添加一个空闲处理器(IdleHandler)。空闲处理器是一种特殊的回调接口,它在消息队列中没有消息时被调用,即在消息队列空闲时触发。
  • new Idler():创建一个新的 Idler 实例。Idler 是 IdleHandler 接口的一个实现,它定义了在消息队列空闲时执行的操作。

这行代码的设计目的是为了在主线程空闲时进行垃圾回收和其他优化操作。通过这种方式,系统可以在不影响 UI 性能的情况下,做一些事情,比如:提高资源利用率,减少内存泄漏,优化电池使用,并提供更平滑的用户体验。这是 Android 系统中一个重要的性能优化机制。

当消息队列中没有消息时Idler 会被调用,更具体地说,IdleHandler 的 queueIdle 方法将会被调用。接下里我们看该方法的实现,代码如下:

java 复制代码
//ActivityThread
    //Idler
        @Override
        public final boolean queueIdle() {
            //activity列表含义,最近被启动但还没有报告为空闲(idle)的 Activity 实例
            ActivityClientRecord a = mNewActivities;
            boolean stopProfiling = false;
            //性能相关处理
            //...
            
            if (a != null) { // 如果存在新的 Activity 记录
                // 清空 mNewActivities 链表,准备处理这些 Activity
                mNewActivities = null;
                IActivityManager am = ActivityManagerNative.getDefault();
                ActivityClientRecord prev;
                do {
                    // 如果 Activity 存在且没有finish
                    if (a.activity != null && !a.activity.mFinished) {
                        try {
                            // 通知 AMS,Activity 已经空闲
                            am.activityIdle(a.token, a.createdConfig, stopProfiling);
                            // 清空创建配置,表示已经处理
                            a.createdConfig = null;
                        } catch (RemoteException ex) {
                            //...
                        }
                    }
                    // 记录当前 Activity 记录,然后移动到下一个
                    prev = a;
                    a = a.nextIdle;
                    // 断开当前记录的下一个引用,避免内存泄漏
                    prev.nextIdle = null;
                } while (a != null);
            }
            //...
            ensureJitEnabled();
            // 返回false 表示不再需要这个IdleHandler,将其从消息队列中移除
            return false;
        }

这个方法主要用于处理消息队列空闲时的一些操作,这组 ActivityClientRecord 列表代表了那些需要进一步处理或状态更新的 Activity 实例。它们在消息队列空闲时被处理,通知 AMS 某个 Activity 已经空闲。这些操作都是在 UI 线程没有其他工作时完成的,这样可以确保不会影响用户界面的响应性。activityIdle代码实现如下:

java 复制代码
//ActivityManagerService
    @Override
    public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
        final long origId = Binder.clearCallingIdentity();
        synchronized (this) {
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config);
                //性能相关处理
                //...
            }
        }
        Binder.restoreCallingIdentity(origId);
    }

继续分析ActivityStackSupervisor.activityIdleInternalLocked方法的实现,代码如下:

java 复制代码
//ActivityStackSupervisor
    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
            Configuration config) {
        ArrayList<ActivityRecord> stops = null;
        ArrayList<ActivityRecord> finishes = null;
        ArrayList<UserStartedState> startingUsers = null;
        int NS = 0; // 停止activity的计数
        int NF = 0; // 结束activity的计数
        boolean booting = false; // 标记系统是否正在启动
        boolean activityRemoved = false; // 标记是否有activity被移除

        // 根据 token 获取对应的 ActivityRecord 对象
        ActivityRecord r = ActivityRecord.forToken(token);
        if (r != null) {
            mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
            r.finishLaunchTickingLocked();
            // 如果是因为超时导致的空闲,报告activity已启动
            // 针对stop的分析,这里fromTimeout=false
            if (fromTimeout) {
                reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
            }

            if (config != null) {
                r.configuration = config;
            }
            
            r.idle = true;// 标记 Activity 为空闲状态

            // 如果 Activity 位于前台栈或者是因为超时,检查是否完成启动
            if (isFrontStack(r.task.stack) || fromTimeout) {
                booting = checkFinishBootingLocked();
            }
        }

        // 如果所有恢复的activity都处于空闲状态,调度应用程序的垃圾回收
        if (allResumedActivitiesIdle()) {
            if (r != null) {
                mService.scheduleAppGcsLocked();
            }

            // 如果有activity正在启动并且被暂停,移除相关的消息并释放
            if (mLaunchingActivity.isHeld()) {
                mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
                //...
                mLaunchingActivity.release();
            }
            // 确保activity可见
            ensureActivitiesVisibleLocked(null, 0);
        }

        // 处理所有标记为停止的activity
        stops = processStoppingActivitiesLocked(true);
        NS = stops != null ? stops.size() : 0;

        // 如果有等待完成的activity,将它们添加到列表中并清空原列表
        if ((NF=mFinishingActivities.size()) > 0) {
            finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
            mFinishingActivities.clear();
        }

        // 如果有正在启动的用户,将它们添加到列表中并清空原列表
        if (mStartingUsers.size() > 0) {
            startingUsers = new ArrayList<UserStartedState>(mStartingUsers);
            mStartingUsers.clear();
        }

        // 停止所有标记为停止的activity
        for (int i = 0; i < NS; i++) {
            r = stops.get(i);
            final ActivityStack stack = r.task.stack;
            if (r.finishing) {
                // 如果activity正在完成,立即结束它
                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
            } else {
                //关键方法:stop activity操作
                stack.stopActivityLocked(r);
            }
        }

        // 完成所有标记为结束的activity
        for (int i = 0; i < NF; i++) {
            r = finishes.get(i);
            // 如果activity被移除,标记 activityRemoved 为 true
            activityRemoved |= r.task.stack.destroyActivityLocked(r, true, "finish-idle");
        }

        // 如果系统不在启动过程中,完成用户启动
        if (!booting) {
            if (startingUsers != null) {
                for (int i = 0; i < startingUsers.size(); i++) {
                    mService.finishUserSwitch(startingUsers.get(i));
                }
            }
            if (mStartingBackgroundUsers.size() > 0) {
                startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
                mStartingBackgroundUsers.clear();
                for (int i = 0; i < startingUsers.size(); i++) {
                    mService.finishUserBoot(startingUsers.get(i));
                }
            }
        }
        // 修剪应用程序,释放无用资源
        mService.trimApplications();
        // 如果有activity被移除,恢复顶层activity
        if (activityRemoved) {
            resumeTopActivitiesLocked();
        }
        return r;
    }

至此,终于看到stopActivityLocked操作了。接下来我们以分析此方法为主。

2.2 stopActivityLocked方法解读(onStop处理)

stopActivityLocked方法的实现,代码如下:

java 复制代码
//ActivityStack
    final void stopActivityLocked(ActivityRecord r) {
        // 如果 Activity 在其 intent 或 activity info 中被标记为没有历史记录(即不在后退栈中出现)
        if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
            // 如果 Activity 还没有结束
            if (!r.finishing) {
                // 如果系统没有在睡眠状态
                if (!mService.isSleeping()) {
                    // 请求结束这个 Activity,并传递一个取消的结果码
                    requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "no-history", false);
                }
            }
        }

        // 如果 Activity 的应用和线程不为空
        if (r.app != null && r.app.thread != null) {
            // 调整焦点 Activity
            adjustFocusedActivityLocked(r, "stopActivity");
            // 恢复分派按键事件
            r.resumeKeyDispatchingLocked();
            try {
                // 重置 Activity 的 stopped 状态
                r.stopped = false;
                // 更新 Activity 的状态为 STOPPING
                r.state = ActivityState.STOPPING;
                // 如果 Activity 不可见,通知窗口管理器
                if (!r.visible) {
                    mWindowManager.setAppVisibility(r.appToken, false);
                }
                // 关键方法:通过应用线程请求停止 Activity
                r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                // 如果系统正在睡眠或关闭,设置 Activity 为睡眠状态
                if (mService.isSleepingOrShuttingDown()) {
                    r.setSleeping(true);
                }
                // 获取一个消息对象,并将其发送到消息队列,如果 Activity 停止操作超时,将处理该消息
                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
                mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
            } catch (Exception e) {
                // 异常处理(省略)
            }
        }
    }

stopActivityLocked 负责停止一个 Activity。它首先检查 Activity 是否被标记为没有历史记录,如果是,并且 Activity 还没有结束,且系统不在睡眠状态,它会请求结束这个 Activity。接下来,如果 Activity 的应用和线程不为空,它会调整焦点 Activity,恢复按键分派,更新 Activity 的状态为 STOPPING,并请求应用线程停止这个 Activity,这里较为关键。如果系统正在睡眠或关闭,它会设置 Activity 为睡眠状态。最后,它会发送一个延迟消息,用于处理停止操作的超时情况。

接下来我们关注关键方法ActivityThread.scheduleStopActivity的实现,代码如下:

java 复制代码
//ActivityThread
    //ApplicationThread
        public final void scheduleStopActivity(IBinder token, boolean showWindow,
                int configChanges) {
           sendMessage(
                showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
                token, 0, configChanges);
        }
        //...
        //Handler消息处理
        private class H extends Handler {
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    //...
                    case STOP_ACTIVITY_SHOW:
                        handleStopActivity((IBinder)msg.obj, true, msg.arg2);
                        break;
                    //...
                }
            }
            //...
        }
        //...
    private void handleStopActivity(IBinder token, boolean show, int configChanges) {
        ActivityClientRecord r = mActivities.get(token);
        r.activity.mConfigChangeFlags |= configChanges;

        StopInfo info = new StopInfo();
        // 执行停止 Activity 的内部操作
        performStopActivityInner(r, info, show, true);
        // 更新 Activity 的可见性状态
        updateVisibility(r, show);
        //...

        // 安排在 UI 线程上告诉 Activity Manager 我们已经停止了 Activity
        // 我们不是立即这样做,因为我们希望在通知 Activity Manager 之前,
        // 有机会完成任何其他挂起的工作(特别是内存修剪请求),然后才能让应用完全进入后台
        info.activity = r;
        info.state = r.state;
        info.persistentState = r.persistentState;
        mH.post(info);
        mSomeActivitiesChanged = true; // 标记有 Activity 状态改变
    }

这里继续分析performStopActivityInner方法的实现,代码如下:

java 复制代码
//ActivityThread
    private void performStopActivityInner(ActivityClientRecord r,
            StopInfo info, boolean keepShown, boolean saveState) {
        if (r != null) {
            //...
            // 如果 Activity 没有完成(即没有调用过 finish()),并且需要保存状态
            if (!r.activity.mFinished && saveState) {
                // 如果 Activity 的状态对象为空,调用 onSaveInstanceState() 方法来保存状态
                if (r.state == null) {
                    callCallActivityOnSaveInstanceState(r);
                }
            }

            // 如果 Activity 不需要保持显示状态
            if (!keepShown) {
                try {
                    // 调用 Activity 的 performStop() 方法来执行停止操作
                    r.activity.performStop();
                } catch (Exception e) {
                    // ...
                }
                r.stopped = true;// 标记 Activity 为已停止状态
            }
            r.paused = true;// 标记 Activity 为已暂停状态
        }
    }

performStopActivityInner 负责执行 Activity 的停止操作。它首先检查 Activity 是否需要保持显示状态。如果不需要,并且 Activity 之前没有被停止过,它会执行停止操作。如果需要保存状态,它会调用 onSaveInstanceState() 方法来保存 Activity 的状态。最后,它调用 Activity 的performStop() 方法来执行实际的停止操作,并更新 Activity 的状态为已停止和已暂停。performStop方法实现,代码如下:

java 复制代码
//Activity
    final void performStop() {
        // 标记不再需要报告完全绘制状态
        mDoReportFullyDrawn = false;
        // 如果加载器已经开始,现在需要停止它们
        if (mLoadersStarted) {
            mLoadersStarted = false; // 标记加载器已停止
            // 如果有加载器管理器,根据配置更改情况执行停止或保留操作
            if (mLoaderManager != null) {
                if (!mChangingConfigurations) {
                    mLoaderManager.doStop(); // 停止加载器
                } else {
                    mLoaderManager.doRetain(); // 保留加载器
                }
            }
        }

        // 如果 Activity 之前没有被停止过
        if (!mStopped) {
            // 如果有窗口对象,关闭所有面板
            if (mWindow != null) {
                mWindow.closeAllPanels();
            }

            // 如果 Activity 有 token 且没有父 Activity,通知窗口管理器该 Activity 已停止
            if (mToken != null && mParent == null) {
                WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
            }

            // 分发 Fragment 的停止事件
            mFragments.dispatchStop();

            // 标记未调用 onStop()
            mCalled = false;

            //关键方法:该方法间接调用 Activity 的 onStop() 方法
            mInstrumentation.callActivityOnStop(this);

            //光标处理相关
            //...
            mStopped = true;// 标记 Activity 为已停止状态
        }
        mResumed = false;// 标记 Activity 不再处于 resume 状态
    }

performStop() 方法执行了 onStop() 生命周期方法之后的操作,包括停止 Loader,关闭窗口面板,更新 Fragment 的状态,释放数据库和光标资源,以及更新 Activity 的状态。这个方法确保了在 Activity 停止时,所有资源都被正确管理和释放,以避免内存泄漏和其他资源问题。此外,它还确保了 onStop() 方法被正确调用,如果没有,会抛出异常。最后更新了 Activity 的状态,以反映它不再处于 resume 状态。

至此,调用到activity的onStop方法了(mInstrumentation.callActivityOnStop)。有了onPause和onStop的分析方法,感兴趣的伙伴可以自行分析下onDestroy的流程。这里不再编写该部分。

3 超时设计的解读

这里的超时的设计以Activity的onStop超时处理为例。即2.2 中stopActivityLocked方法为例,解读下onStop的超时处理流程,整理后相关代码如下:

java 复制代码
//ActivityStack
    final void stopActivityLocked(ActivityRecord r) {
        //...
        // 如果 Activity 的应用和线程不为空
        if (r.app != null && r.app.thread != null) {
            //...
            try {
                //...
                // 关键方法:通过应用线程请求停止 Activity
                r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                //...
                // 获取一个消息对象,并将其发送到消息队列,如果 Activity 停止操作超时,将处理该消息
                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
                mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
            } catch (Exception e) {
                // 异常处理(省略)
            }
        }
    }

可以看到执行scheduleStopActivity后开始用handler发送延迟消息。注意:这里是不管是否延迟都会发消息。那么消息是在哪里处理的呢?

我们以scheduleStopActivity为入口进行分析。这里scheduleStopActivity通过handler发送消息,最终由handleStopActivity来处理,我们就从handleStopActivity这个方法开始分析,代码整理后,关键代码如下:

java 复制代码
//ActivityThread
    private void handleStopActivity(IBinder token, boolean show, int configChanges) {
        ActivityClientRecord r = mActivities.get(token);
        r.activity.mConfigChangeFlags |= configChanges;

        StopInfo info = new StopInfo();
        performStopActivityInner(r, info, show, true);
        //...
        updateVisibility(r, show);
        //...
        //这里开始通过post执行info的run方法
        info.activity = r;
        info.state = r.state;
        info.persistentState = r.persistentState;
        mH.post(info);
        mSomeActivitiesChanged = true;
    }

这里主要关注StopInfo的实现及run方法,因为post会导致run的调用,StopInfo代码如下:

java 复制代码
    private static class StopInfo implements Runnable {
        ActivityClientRecord activity;
        Bundle state;
        PersistableBundle persistentState;
        CharSequence description;

        @Override public void run() {
            try {
                ActivityManagerNative.getDefault().activityStopped(
                    activity.token, state, persistentState, description);
            } catch (RemoteException ex) {
            }
        }
    }

继续分析AMS的关键方法activityStopped的实现,代码如下:

java 复制代码
//ActivityManagerService
    @Override
    public final void activityStopped(IBinder token, Bundle icicle,
            PersistableBundle persistentState, CharSequence description) {
        //...
        final long origId = Binder.clearCallingIdentity();
        synchronized (this) {
            ActivityRecord r = ActivityRecord.isInStackLocked(token);
            if (r != null) {
                r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
            }
        }
        trimApplications();
        Binder.restoreCallingIdentity(origId);
    }

继续分析这里的关键方法activityStoppedLocked的实现,整理关键代码内容分析,代码如下:

java 复制代码
//ActivityStack
    final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
            PersistableBundle persistentState, CharSequence description) {
        if (r.state != ActivityState.STOPPING) {
            Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
            mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
            return;
        }
        //...
    }

如果一切正常,那么最后会通过AMS,在ActivityStack的activityStoppedLocked中将这个超时消息移除。也就是正常情况下,只要不超过这个超时的时间,都会正常运行;出现超时的异常情况会导致延迟消息未取消而正常发送,导致异常处理的流程。

以上是以onStop的流程未基础进行分析,其他的onCreate、onStart、onResume、onPause等也是按照类似方式来处理超时的。

相关推荐
wrx繁星点点1 小时前
桥接模式:解耦抽象与实现的利器
android·java·开发语言·jvm·spring cloud·intellij-idea·桥接模式
镰刀出海1 小时前
RN开发环境配置与Android版本app运行
android·react native
Python大数据分析3 小时前
JetPack Compose安卓开发之底部导航Tabbar
android·vue.js·elementui
前期后期3 小时前
Android 在github网站下载项目:各种很慢怎么办?比如gradle下载慢;访问github慢;依赖下载慢
android·github
如果'\'真能转义说3 小时前
从网络到缓存:在Android中高效管理图片加载
android·网络·缓存
无休居士4 小时前
Java8中CompletableFuture.allOf的使用
android·java·开发语言·future·completable·allof
Asin²+cos²=112 小时前
关于Android Studio Koala Feature Drop | 2024.1.2下载不了插件的解决办法
android·ide·android studio
大耳猫13 小时前
Android gradle和maven国内镜像地址
android·gradle·maven
-seventy-15 小时前
Android 玩机知识储备
android
CYRUS STUDIO15 小时前
frida脚本,自动化寻址JNI方法
android·运维·自动化·逆向·移动安全·jni·frida