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相关函数,代码如下所示:

//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,代码实现如下:

//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方法,过程中的代码实现如下:

//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方法,关键方法为:

//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方法,代码实现如下:

//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方法的实现,代码实现如下:

//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

关键代码解读如下:

//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 {
            //...
        }
    }

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

Looper.myQueue().addIdleHandler(new Idler());

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

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

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

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

//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代码实现如下:

//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方法的实现,代码如下:

//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方法的实现,代码如下:

//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的实现,代码如下:

//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方法的实现,代码如下:

//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方法实现,代码如下:

//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的超时处理流程,整理后相关代码如下:

//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这个方法开始分析,代码整理后,关键代码如下:

//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代码如下:

    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的实现,代码如下:


//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的实现,整理关键代码内容分析,代码如下:

//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等也是按照类似方式来处理超时的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/895278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IT监控平台可视化:3D机房与设备监控的革新实践

在信息化高速发展的今天&#xff0c;IT运维行业面临着前所未有的挑战。随着数据中心规模的不断扩大和设备复杂度的日益提升&#xff0c;如何高效、准确地监控和管理这些设备&#xff0c;成为了运维团队亟待解决的问题。IT监控平台的可视化功能&#xff0c;尤其是3D机房与设备监…

从零开始学PHP之输出语句变量常量

一、 输出方式 在 PHP 中输出方式&#xff1a; echo&#xff0c;print&#xff0c;print_r&#xff0c;var_dump 1、echo和print为php的输出语句 2、var_dump&#xff0c;print_r为php的输出函数 &#xff08;这里不做介绍&#xff09;echo 和 print 区别 1、echo - 可以输出…

CSS3 提示框带边角popover

CSS3 提示框带边角popover。因为需要绝对定位子元素&#xff08;这里就是伪元素&#xff09;&#xff0c;所以需要将其设置为相对对位 <!DOCTYPE html> <html> <head> <title>test1.html</title> <meta name"keywords" con…

uniapp_微信小程序_echarts_动态折线图

##uniapp_微信小程序_echarts_动态折线图 用来总结和学习&#xff0c;便于自己查找 文章目录 一、为什么使用echarts折线图?          1.1 动态折线图echarts效果&#xff1f; 二、怎么导入echarts折线图&#xff1f;          2.…

spring boot 3.3.4 网关(gateway) 集成knife4j 4.4.0

spring boot版本 3.3.4&#xff0c;jdk 22&#xff0c; springcloud 2023.0.3 官方参考链接 Spring Cloud Gateway网关聚合 | Knife4j (xiaominfo.com) springboot版本信息 <properties> <java.version>22</java.version> <spring-cloud.version>2023…

LSTM反向传播及公式推导

先回顾一下正向传播的公式: 化简一下: 反向传播从下到上逐步求偏导: 对zt求偏导(预测值和标签值相减): zt对未知数wt,ht,bt分别求偏导: ht对ot,Ct求偏导: ot对Net0求偏导: Net0对w0,b0求偏导: .... 总体的思路就是那个公式从下到上逐步对未知数求偏导: 下面是总体的流程…

在Openshift(K8S)上通过EMQX Operator部署Emqx集群

EMQX Operator 简介 EMQX Broker/Enterprise 是一个云原生的 MQTT 消息中间件。 我们提供了 EMQX Kubernetes Operator 来帮助您在 Kubernetes 的环境上快速创建和管理 EMQX Broker/Enterprise 集群。 它可以大大简化部署和管理 EMQX 集群的流程&#xff0c;对于管理和配置的知…

微服务架构 --- 使用RabbitMQ进行异步处理

目录 一.什么是RabbitMQ&#xff1f; 二.异步调用处理逻辑&#xff1a; 三.RabbitMQ的基本使用&#xff1a; 1.安装&#xff1a; 2.架构图&#xff1a; 3.RabbitMQ控制台的使用&#xff1a; &#xff08;1&#xff09;Exchanges 交换机&#xff1a; &#xff08;2&#…

【双指针算法】快乐数

1.题目解析 2.算法分析 由图可知&#xff0c;不管是最后可以变成1的还是不可以变成1的都相当于形成环了&#xff0c;只是成环处值不一样 问题转变成&#xff0c;判断链表是否有环 采用双指针&#xff0c;快慢指针算法 1.定义快慢指针2.慢指针每次向后移动一步&#xff0c;快…

初识适配器模式

适配器模式 引入 生活中的例子&#xff1a;当我们使用手机充电时&#xff0c;充电器起到了转换器的作用&#xff0c;它将家用的220伏特电压转换成适合手机充电的5伏特电压。 适配器模式的三种类型 命名原则&#xff1a;适配器的命名应基于资源如何传递给适配器来进行。 类适配…

AnaTraf | 利用多点关联数据分析和网络关键KPI监控提升IT运维效率

目录 什么是多点关联数据分析&#xff1f; 多点关联数据分析的运用场景 监控网络关键KPI的重要性 典型的网络关键KPI 案例分析&#xff1a;利用多点关联数据分析和KPI监控解决网络性能问题 结语 AnaTraf 网络性能监控系统NPM | 全流量回溯分析 | 网络故障排除工具AnaTraf…

01 设计模式-创造型模式-工厂模式

工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;它提供了一种创建对象的方式&#xff0c;使得创建对象的过程与使用对象的过程分离。 工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。 通过使用工厂模式…

SpringBoot框架下的汽车票在线预订系统

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

基于单片机的家用无线火灾报警系统的设计

1 总体设计 本设计家用无线火灾报警系统利用单片机控制技术、传感器检测技术、GSM通信技术展开设计&#xff0c;如图2.1所示为本次系统设计的主体框图&#xff0c;系统包括单片机主控模块、温度检测模块、烟雾检测模块、按键模块、GSM通信模块、液晶显示模块、蜂鸣器报警模块。…

汽车票预订系统:SpringBoot框架的优势

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…

UE5 使用Animation Budget Allocator优化角色动画性能

Animation Budget Allocator是UE内置插件&#xff0c;通过锁定动画系统所占CPU的预算&#xff0c;在到达预算计算量时对动画进行限制与优化。 开启Animation Budget Allocator需要让蒙皮Mesh使用特定的组件&#xff0c;并进行一些编辑器设置即可开启。 1.开启Animation Budget…

地球链EACO怎么和房车旅游等行业结合起来加速全球发展?

地球链EACO怎么和房车旅游等行业结合起来加速全球发展&#xff1f; 将地球链&#xff08;EACO&#xff09;与房车,旅游&#xff0c;汽车等行业结合以加速全球发展&#xff0c;可以通过以下策略&#xff1a; 智能合约与租赁平台 去中心化租赁市场&#xff1a;建立一个基于EACO的…

PCL 点云配准 基于目标对称的ICP算法(精配准)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1计算点云的法线 2.1.2基于对称误差估计的ICP配准 2.1.3可视化 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总…

【火山引擎】调用火山大模型的方法 | SDK安装 | 配置 | 客户端初始化 | 设置

豆包 (Doubao) 是字节跳动研发的大规模预训练语言模型。 目录 1 安装 2 配置访问凭证 3 客户端初始化 4 设置地域和访问域名 5 设置超时/重试次数 1 安装 通过pip安装PYTHON SDK。 pip install volcengine-python-sdk[ark] 2 配置访问凭证 获取 API Key 访问凭证具体步…

理工科考研想考计算机,湖南大学、重大、哈工大威海、山东大学,该如何选择?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 计算机对理工科同学来说&#xff0c;还是性价比很高的&#xff0c;具有很大的优势&#xff01; 一、就业前景广阔 高需求行业 在当今数字化时代&#xff0c;计算机技术几乎渗透到了各个领域&#xff0c;无论是互联网…