Broadcast触发ANR和Service触发ANR原理是一样的,都是通过延迟发送超时消息的形式
BroadcastReceiver广播接收分为2类
AndroidManifest.xml
的标签来申明注册BroadcastReceiver
Context.registerReceiver
来注册,动态注册更为灵活,可在不需要时通过unregisterReceiver()
取消注册广播发送方式可分为三类
Context.sendBroadcast()
发送,可并行处理,我们最常用的是这种Context.sendOrderedBroadcast()
发送,串行处理Context.sendStickyBroadcast()
发送(Android5.0已废弃),是一种特殊类型的广播,被发送的intent对象在广播完成后仍会保留在缓存中,系统可能会稍后向注册的接收器重新广播粘性intent在了解之前,要熟悉Broadcast的工作流程, Broadcast的工作流程主要分为注册广播流程和发送广播流程
注册广播属于一个跨进程通讯的操作,通过AMS服务去保存广播对象,以便后续发送广播使用
发送广播同样是一个跨进程通讯的操作,在广播中存在一个广播队列BroadcastQueue
,队列会一直遍历当前是否有广播可以处理,当发送广播过来的时候,会先加入到队列中,等待队列处理广播,当找到匹配的广播后,则执行onReceiver
回调
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();
}
}
发送广播最终会去遍历广播队列里的广播,最终调用到BroadcastQueue
的processNextBroadcastLocked
去获取队列中的广播
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;
}
}