一、前言
上一篇我们对Service类型的ANR做了介绍,本篇我们将集合源码,对四种ANR类型中的Broadcast Timeout类型的触发机制做详尽的介绍。
二、Broadcast Timeout
在ActivityManagerService 中,构造了两种Broadcast timeout,分别是 前台FG 10s和
后台BG 60s.
mFgBroadcastQueue/mBgBroadcastQueue ⽤来表示foreground和background
⼴播队列.
⾸先看下如下⼏个数据的定义:
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground",
BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background",
BROADCAST_BG_TIMEOUT, true);
//frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
/**
* Lists of all active broadcasts that are to be executed
immediately
* (without waiting for another broadcast to finish).
Currently this only
* contains broadcasts to registered receivers, to avoid
spinning up
* a bunch of processes to execute IntentReceiver
components. Background-
* and foreground-priority broadcasts are queued
separately.
*/
/**
* 并⾏⼴播队列,可以⽴刻执⾏,⽽⽆需等待另⼀个⼴播运⾏完成,该队列只允
许动态已注册的⼴播,
* 从⽽避免发⽣同时拉起⼤量进程来执⾏⼴播,前台的和后台的⼴播分别位于独
⽴的队列。
*/
final ArrayList<BroadcastRecord> mParallelBroadcasts = new
ArrayList<>();
/**
* List of all active broadcasts that are to be executed
one at a time.
* The object at the top of the list is the currently
activity broadcasts;
* those after it are waiting for the top to finish. As
with parallel
* broadcasts, separate background- and foreground-priority
queues are
* maintained.
*/
/**
*有序⼴播队列,同⼀时间只允许执⾏⼀个⼴播,该队列顶部的⼴播便是活动⼴
播,
*其他⼴播必须等待该⼴播结束才能运⾏,和并⾏⼴播队列⼀样也是独⽴区别前
台的和后台的⼴播。
*/
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new
ArrayList<>();
三、Broadcast 设置 定时器
调⽤ processNextBroadcast来处理⼴播.其流程为先处理并⾏⼴播,再处理当前有序
⼴播,最后获取并处理下条有序⼴播.
//frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, long timeoutPeriod, boolean
allowDelayBehindServices) {
mService = service;
mHandler = new BroadcastHandler(handler.getLooper());
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
mDelayBehindServices = allowDelayBehindServices;
}
processNextBroadcast 最终会调⽤processNextBroadcastLocked (fromMsg
=false).
此处mService为ActivityManagerService,整个流程还是⽐较⻓的,全程持有AMS
锁,这个⽅法⽐较⻓,我省略的部分不在这⾥重点关注的部分.所以⼴播的队列很⻓的
话,直接会严重影响这个⼿机的性能与流畅度,这⾥可以做⼀个监控,看看系统处理⼴
播都需要hold 多久的ams lock.
整个processNextBroadcast的流程⼤致分为下⾯⼏个步骤:
- 设置⼴播超时延时消息,设置定时器: setBroadcastTimeoutLocked:
- 处理并⾏⼴播 mParallelBroadcasts 执⾏
deliverToRegisteredReceiverLocked - 处理有序⼴播mOrderedBroadcasts当⼴播接收者等待时间过⻓, now > now >
r.dispatchTime + (2mTimeoutPeriodnumReceivers) r.dispatchTime + (2mTimeoutPeriodnumReceivers) 则调⽤
broadcastTimeoutLocked(false) 则强制结束这条⼴播;
final void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
//...省略
//【1】处理并⾏⼴播 mParallelBroadcasts
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
//分发⼴播给已注册的receiver
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
//添加⼴播历史统计
addBroadcastToHistoryLocked(r);
}
// Now take care of the next serialized one...
// mPendingBroadcast正常情况下是空的,如果不是空,说明当前有需
要处理的⼴播,⼀般只有在
// 等待⽬标进程启动来处理对应的⼴播的情况下会出现,这个情况下就仅
仅检查进程是否存在.
if (mPendingBroadcast != null) {
boolean isDead;
if (mPendingBroadcast.curApp.pid > 0) {
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc =
mService.