我是靠谱客的博主 彪壮芒果,最近开发中收集的这篇文章主要介绍ANR Broadcast TimeOut 超时判断Broadcast超时判断,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ANR Broadcast TimeOut 超时判断

  • Broadcast超时判断
    • 发送BROADCAST_INTENT_MSG处理广播
      • BroadcastHandler采用“ActivityManager”线程的Looper
      • BroadcastHandler处理BROADCAST_INTENT_MSG消息
    • processNextBroadcast 派发广播消息最为核心的函数
      • 处理并行广播消息
      • 处理阻塞的广播消息
      • 处理当前有序广播消息
      • 获取下条有序广播
    • Broadcast 超时判断
    • 超时响应执行broadcastTimeoutLocked
    • AppNotResponding输出Log
    • 何时清除超时消息BROADCAST_TIMEOUT_MSG
    • 感谢

android-9.0.0_r8

Broadcast超时判断

前台的“串行广播消息”必须在10秒内处理完毕,后台的“串行广播消息”必须在60秒内处理完毕,每派发串行广播消息到一个接收器,都抛出定时消息BROADCAST_TIMEOUT_MSG,如果定时消息响应了,则说明发生了ANR。

发送BROADCAST_INTENT_MSG处理广播

ContextImpl.broadcastIntent -> AMS.broadcastIntent -> AMS.broadcastIntentLocked -> BroadcastQueue.scheduleBroadcastsLocked
在这里插入图片描述

BroadcastHandler采用“ActivityManager”线程的Looper

BroadcastHandler使用的是AMS的Looper,真正派发广播的是AMS线程(system_server进程中的ActivityManager线程),往AMS线程的消息队列发送BROADCAST_INTENT_MSG消息

mHandlerThread = new ServiceThread(TAG,
                THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
        mHandlerThread.start();
        mHandler = new MainHandler(mHandlerThread.getLooper());
        //... ... ... ...
        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "foreground", BROADCAST_FG_TIMEOUT, false);
        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "background", BROADCAST_BG_TIMEOUT, true);
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;

在这里插入图片描述

BroadcastHandler处理BROADCAST_INTENT_MSG消息

在这里插入图片描述

processNextBroadcast 派发广播消息最为核心的函数

其实该版本这里转了一道,processNextBroadcast 跳到 processNextBroadcastLocked 方法
通过调用 processNextBroadcastLocked 来处理广播;其流程为先处理并行广播,再处理当前有序广播,最后获取并处理下条有序广播。

处理并行广播消息

在这里插入图片描述

  • deliverToRegisteredReceiverLocked 分发广播给已注册的 receiver

处理阻塞的广播消息

有时候会存在一个广播消息派发不出去的情况,这个广播消息会保存在mPendingBroadcast变量中。新一轮的派发启动时,会判断接收该消息的进程是否还活着, 如果接收进程还活着,那么就继续等待。否则,就放弃这个广播消息
在这里插入图片描述

处理当前有序广播消息

boolean looped = false;

do {
    //。。。。。。 。。。。。。
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    if (mService.mProcessesReady && r.dispatchTime > 0) {
        long now = SystemClock.uptimeMillis();
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
            Slog.w(TAG, "Hung broadcast ["
                    + mQueueName + "] discarded after timeout failure:"
                    + " now=" + now
                    + " dispatchTime=" + r.dispatchTime
                    + " startTime=" + r.receiverTime
                    + " intent=" + r.intent
                    + " numReceivers=" + numReceivers
                    + " nextReceiver=" + r.nextReceiver
                    + " state=" + r.state);
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }
    //。。。。。。 。。。。。。
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        // No more receivers for this broadcast!  Send the final
        // result if requested...
        if (r.resultTo != null) {
            try {
                if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                        "Finishing broadcast [" + mQueueName + "] "
                        + r.intent.getAction() + " app=" + r.callerApp);
                performReceiveLocked(r.callerApp, r.resultTo,
                    new Intent(r.intent), r.resultCode,
                    r.resultData, r.resultExtras, false, false, r.userId);
                // Set this to null so that the reference
                // (local and remote) isn't kept in the mBroadcastHistory.
                r.resultTo = null;
            } catch (RemoteException e) {
                r.resultTo = null;
                Slog.w(TAG, "Failure ["
                        + mQueueName + "] sending broadcast result of "
                        + r.intent, e);

            }
        }

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
        cancelBroadcastTimeoutLocked();
        // 。。。。。。 。。。。。。
  • numReceivers 获取所有该广播所有的接收者
  • 判断 broadcastTimeoutLocked 当广播处理时间超时,则强制结束这条广播,第一个ANR监测
  • performReceiveLocked 处理广播消息消息
  • cancelBroadcastTimeoutLocked() 串行广播消息处理完毕,移除 BROADCAST_TIMEOUT_MSG 消息

获取下条有序广播

  • 获取下条有序广播,Handler设置超时消息BROADCAST_TIMEOUT_MSG,串行广播消息的第二个ANR监测机制
    在这里插入图片描述

Broadcast 超时判断

1、(numReceivers > 0) && (now > r.dispatchTime + (2mTimeoutPeriodnumReceivers))
在这里插入图片描述

numReceivers 广播接收者不为空;
now = SystemClock.uptimeMillis() 获取当前时间;
r.dispatchTime 表示这一系列广播消息开始派发的时间;
mTimeoutPeriod 由当前BroadcastQueue的类型决定(forground为10秒,background为60秒)
在这里插入图片描述
2、获取下条有序广播,setBroadcastTimeoutLocked设置超时BROADCAST_TIMEOUT_MSG消息
在这里插入图片描述

  • timeoutTime = r.receiverTime + mTimeoutPeriod 设置超时时间
  • 响应 BroadcastHandler 消息 BROADCAST_TIMEOUT_MSG
  • 在这里插入图片描述

超时响应执行broadcastTimeoutLocked

1、fromMsg = true,设置mPendingBroadcastTimeoutMessage
在这里插入图片描述
2、fromMsg = true,当系统还没有准备就绪时,广播处理流程中不存在广播超时
在这里插入图片描述
3、fromMsg = true,如果当前正在执行的receiver没有超时,则重新设置广播超时
在这里插入图片描述
4、广播已经处理完成,但需要等待已启动service执行完成。当等待足够时间,则处理下一条广播。
在这里插入图片描述
5、r.anrCount++:当前BroadcastRecord的anr次数加1;app = mService.mPidsSelfLocked.get(bf.receiverList.pid):查询App进程;anrMessage:ANR Log信息;finishReceiverLocked、scheduleBroadcastsLocked:已经超时,则结束对当前接收器,开始新一轮调度;mHandler.post(new AppNotResponding(app, anrMessage)):使用AppNotResponding输出Log
在这里插入图片描述

AppNotResponding输出Log

在这里插入图片描述

和ANR service TimeOut 超时判断使用AppErrors.appNotResponding最终输出Log

何时清除超时消息BROADCAST_TIMEOUT_MSG

在这里插入图片描述

processNextBroadcastLocked中处理串行广播完成时,调用cancelBroadcastTimeoutLocked方法移除BROADCAST_TIMEOUT_MSG消息

感谢

ANR机制以及问题分析
理解Android ANR的触发原理
Android Broadcast广播机制分析
Android深入四大组件(四)广播的注册、发送和接收过程

最后

以上就是彪壮芒果为你收集整理的ANR Broadcast TimeOut 超时判断Broadcast超时判断的全部内容,希望文章能够帮你解决ANR Broadcast TimeOut 超时判断Broadcast超时判断所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部