ANR系列(一)——ANR源码拆解之Broadcast的触发

前言

Broadcast触发ANR和Service触发ANR原理是一样的,都是通过延迟发送超时消息的形式

Broadcast简介

BroadcastReceiver广播接收分为2类

  • 静态广播:通过AndroidManifest.xml的标签来申明注册BroadcastReceiver
  • 动态广播:通过Context.registerReceiver来注册,动态注册更为灵活,可在不需要时通过unregisterReceiver()取消注册

广播发送方式可分为三类

  • 普通广播:通过Context.sendBroadcast()发送,可并行处理,我们最常用的是这种
  • 有序广播:通过Context.sendOrderedBroadcast()发送,串行处理
  • 粘性广播:通过Context.sendStickyBroadcast()发送(Android5.0已废弃),是一种特殊类型的广播,被发送的intent对象在广播完成后仍会保留在缓存中,系统可能会稍后向注册的接收器重新广播粘性intent

Broadcast的工作流程

在了解之前,要熟悉Broadcast的工作流程, Broadcast的工作流程主要分为注册广播流程和发送广播流程

  1. 注册广播

注册广播属于一个跨进程通讯的操作,通过AMS服务去保存广播对象,以便后续发送广播使用

ANR系列(一)——ANR源码拆解之Broadcast的触发_第1张图片

  1. 发送广播

发送广播同样是一个跨进程通讯的操作,在广播中存在一个广播队列BroadcastQueue,队列会一直遍历当前是否有广播可以处理,当发送广播过来的时候,会先加入到队列中,等待队列处理广播,当找到匹配的广播后,则执行onReceiver回调

ANR系列(一)——ANR源码拆解之Broadcast的触发_第2张图片

Broadcast的ANR机制就藏在发送广播的时候,通过发送延时消息埋炸弹,待消息执行完毕后拆除炸弹

Broadcast的ANR机制

发送广播的开始是从ContextImpl中调用sendBroadcast方法

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

发送广播最终会去遍历广播队列里的广播,最终调用到BroadcastQueueprocessNextBroadcastLocked去获取队列中的广播

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    //...
    //1、发送延时消息,设置超时时间
    setBroadcastTimeoutLocked(timeoutTime);
    //...
    //2、处理广播的onReceive方法
    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
    //...
    //3、取消超时消息
    cancelBroadcastTimeoutLocked();
}

在广播执行前发送延时消息,设置超时时间

final void setBroadcastTimeoutLocked(long timeoutTime) {
    if (! mPendingBroadcastTimeoutMessage) {
        Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
        mHandler.sendMessageAtTime(msg, timeoutTime);
        mPendingBroadcastTimeoutMessage = true;
    }
}

如果没有在规定时间完成,则会处理BROADCAST_TIMEOUT_MSG消息,触发ANR

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        //...
        case BROADCAST_TIMEOUT_MSG: {
            synchronized (mService) {
                broadcastTimeoutLocked(true);
            }
        } break;
    }
}

final void broadcastTimeoutLocked(boolean fromMsg) {
    //...

    if (!debugging && anrMessage != null) {
        // Post the ANR to the handler since we do not want to process ANRs while
        // potentially holding our lock.
        mHandler.post(new AppNotResponding(app, anrMessage));
    }
}

如果在指定时间内完成,则会取消超时消息

final void cancelBroadcastTimeoutLocked() {
    if (mPendingBroadcastTimeoutMessage) {
        mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
        mPendingBroadcastTimeoutMessage = false;
    }
}

你可能感兴趣的:(ANR合集,java,开发语言)