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

news2024/10/22 8:50:36

该系列文章总纲链接:专题总纲目录 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等也是按照类似方式来处理超时的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Springboot在线视频网站的设计与实现

基于Springboot视频网站的设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;idea 源码获取&#xff1a;https://do…

15.JVM垃圾收集算法

一、垃圾收集算法 1.分代收集理论 分代收集理论是JAVA虚拟机进行垃圾回收的一种思想&#xff0c;根据对象存活周期的不同将内存分成不同的几个区域&#xff1b;一般将JAVA堆内存分为新生代和老年代&#xff1b;根据每个分代特点选择不同的垃圾收集器&#xff1b; 在新生代中&am…

UE4 材质学习笔记12(水体反射和折射)

一.水体反射和折射 首先就是要断开所有连接到根节点的线&#xff0c;因为水有很多不同的节点成分&#xff0c;当所有其他节点都在用时 要分辨出其中一个是何效果是很难的。 虚幻有五种不同的方法可以创建反射&#xff0c;虚幻中的大多数场景使用多种这些方法 它们会同时运作。…

开源vGPU方案 HAMi实现细粒度GPU切分——筑梦之路

前言 为什么需要 GPU 共享、切分等方案&#xff1f; 在使用GPU的过程中我们会发现&#xff0c;直接在裸机环境使用&#xff0c;都可以多个进程共享 GPU&#xff0c;怎么到 k8s 环境就不行了&#xff1f; 1. 资源感知 在 k8s 中资源是和节点绑定的&#xff0c;对于 GPU 资源…

【Linux】僵尸进程和孤儿进程

一、僵尸进程 何为僵尸进程&#xff1f; 在 Unix/Linux 系统中&#xff0c;正常情况下&#xff0c;子进程是通过父进程创建的&#xff0c;且两者的运行是相互独立的&#xff0c;父进程永远无法预测子进程到底什么时候结束。当一个进程调用 exit 命令结束自己的生命时&#xff…

《编程入门与提高:开启数字世界的大门》

《编程入门与提高&#xff1a;开启数字世界的大门》 一、引言二、编程入门的基础知识&#xff08;一&#xff09;编程语言的选择&#xff08;二&#xff09;编程环境的搭建&#xff08;三&#xff09;编程的基本概念&#xff08;四&#xff09;编程的基本语法 三、编程入门的方…

哪些方法可以缓解面试紧张?

面试紧张是许多人在面对重要职业机会时的一种常见情绪。虽然一定程度的紧张可能激发人的潜能&#xff0c;但过度的紧张则可能影响到面试表现。为了缓解面试紧张&#xff0c;以下是一些有效的方法&#xff1a; 1.充分准备&#xff1a; 深入了解公司背景、职位要求以及公司文化…

地方门户分类信息网站源码系统 用户可以自由发帖 PHP+MySQL组合开发 带完整的安装代码包以及搭建部署教程

系统概述 地方门户分类信息网站源码系统是一个基于PHP和MySQL开发的强大平台&#xff0c;旨在帮助用户轻松搭建地方性的分类信息网站。该系统集成了众多实用功能&#xff0c;支持用户自由发帖、浏览和搜索各类信息&#xff0c;如二手交易、求职招聘、房屋租售、生活服务、商家…

Python网络请求库requests的10个基本用法

大家好&#xff01;今天我们要聊聊Python中非常实用的一个库——requests。这个库让发送HTTP请求变得超级简单。无论你是想抓取网页数据还是测试API接口&#xff0c;requests都能派上大用场。下面我们就一起来看看如何使用requests完成一些常见的任务。 引言 随着互联网技术的…

空洞卷积:Atrous/Dilated convolution - 语义分割中多用到

没办法&#xff0c;我还是很多基础的、底层的模块不通透&#xff0c;读论文难免会受到阻碍&#xff0c;而且这现在科研任务很急了&#xff0c;必须要马上动手实验&#xff0c;全给我弄明白、特别是算法&#xff01; 空洞卷积-可变形卷积-这一个个我都要。 空洞卷积据说在语义分…

推动AI技术研发与应用,景联文科技提供专业高效图像采集服务

景联文科技提供专业图像采集服务&#xff0c;涵盖多个领域的应用需求。 包含人体图像、人脸图像、手指指纹、手势识别、交通道路、车辆监控等图像数据集&#xff0c;计算机视觉图像数据集超400TB&#xff0c;支持免费试采试标。 高质量人像采集服务&#xff1a;支持不同光线条件…

Netty入门基础:Netty架构设计模型介绍(主从Reactor多线程模型,Futrue-Listener模型)

文章目录 &#x1f3b5;单Reactor单线程✏单Reactor多线程&#x1f6d2;主从Reactor多线程&#x1f390;Netty模型&#x1f6b4;‍♀️Future-listener模型 &#x1f3b5;单Reactor单线程 Reactor通过select监控客户端的事件&#xff0c;通过dispatch分发。 如果是建立连接事件…

Unity-RetargetPro3-动画插件试用

一个名气大于实战的插件 目录 初见这个插件, 打开文档看看 下载并打开Demo项目 直接看Editor代码吧 这个插件,可以放弃了 初见这个插件, 觉得,1.都已经是3.0版本,不错哦 看上去,2.目录也 不错,有分Core,plugin等 (应该感觉,怎么也是大公司的代码分拆出来吧,感…

计算机的错误计算(一百三十)

摘要 用手持式计算器计算 则输出为0 . 计算机的错误计算&#xff08;四十&#xff09;探讨了计算器的计算精度问题。为了回应一位计算器收藏家来信中的疑问&#xff0c;既&#xff08;四十&#xff09;后再续若干节&#xff0c;以便更为广泛地讨论计算器的上述问题。 例1. …

【思维导图】C语言—数据类型和变量

今天我们来回顾——C语言【数据类型和变量】 我们先梳理一下思路&#xff1a;首先学习数据的类型&#xff0c;然后学会用类型去创建变量&#xff0c;接着学习操作符进行变量之间的运算&#xff0c;最后学习 scanf 输入数据&#xff0c; printf 进行数据的打印。回顾的时候最好…

【K8S系列】Kubernetes Pod 状态详细介绍及异常状态解决方案

在 Kubernetes 中&#xff0c;Pod 是最小的可调度单元&#xff0c;负责运行一个或多个容器。Pod 的状态能够反映其生命周期中的不同阶段&#xff0c;帮助用户了解当前的运行状况。本文将详细介绍 Kubernetes Pod 的各种状态及其可能的异常状态解决方案。 一、Pod 状态概览 Po…

【Git】远程操作-标签管理-多人协作

远程操作 分布式版本控制系统 概念理解 Git就像正在看的一本书。每当看完一章&#xff0c;可以将其保存起来&#xff0c;如果后面想修改或者查看以前自己看到哪里&#xff0c;随时可以翻看。Git就是帮助记录这些修改的工具&#xff0c;主要负责记录每次改动&#xff0c;就类似…

git命令笔记(速查速查)

git命令功能总结 1.创建git的本地仓库2. 配置本地仓库(name和email地址)3. 工作区、版本库、暂存区、对象区3.1 add, commit3.2 打印提交日志3.2 修改文件 4.版本回退&#xff08;git reset&#xff09;5. 撤销修改&#xff08;在push之前撤销&#xff09;6.删除版本库中的文件…

Github + 自定义域名搭建个人静态站点

Github 自定义域名搭建个人静态站点 使用 Github 部署一个自己的免费站点给你的站点添加上自定义域名 本文基于腾讯云基于二级域名, 作用于 Github 实现自定义域名站点 使用 Github 部署一个自己的免费站点 首先你得有一个 Github 账号, 没有就去注册一个,网上有教程,本文跳…

字典学习算法

分为固定基字典和学习型字典 学习型字典 是指通过训练大量与目标数据相似的数据&#xff0c;学习其特征获得的字典。字典学习主要包括两个阶段&#xff0c;一个是字典构建阶段&#xff0c;一个是利用字典进行样本表示阶段。 首次提出&#xff1a;最优方向法&#xff08;Method …