Android15广播ANR的源码流程分析
Android15的广播ANR源码流程
跟了下实际代码的流程,大概如下哈:
App.sendBroadcast() // 应用发起广播
→ AMS.broadcastIntentWithFeature() // 通过Binder IPC进入system_server进程
→ AMS.broadcastIntentLocked() // 权限校验+广播分类(前台/后台)
→ BroadcastQueueModernImpl.enqueueBroadcastLocked() // 按进程隔离的队列管理
→ BroadcastQueueModernImpl.updateRunningListLocked() // 检查进程活跃状态
→ BroadcastQueueModernImpl.scheduleReceiverWarmLocked() // 预热进程(若未启动)
→ BroadcastQueueModernImpl.dispatchReceivers() // 关键:启动超时检测(前台10s/后台60s)
├─ 通过Handler发送MSG_DELIVERY_TIMEOUT延迟消息
└─ 豁免条件:系统未就绪或广播标记为timeoutExempt
→ IApplicationThread.scheduleRegisteredReceiver() // Binder投递到目标进程
→ ActivityThread.post(Args.run()) // 主线程消息队列调度
→ Args.run() // 封装广播处理逻辑
→ BroadcastReceiver.onReceive() // 开发者代码执行点(耗时操作直接触发ANR)
→ AMS.finishReceiver() // 正常完成通知
→ BroadcastQueueModernImpl.finishReceiverLocked() // 移除超时检测(Handler取消MSG_DELIVERY_TIMEOUT)
└─ 若超时未完成→ AMS.appNotResponding() // 触发ANR弹窗(含Intent/接收者类名等上下文)
源码分析
→ App.sendBroadcast()
→ → AMS.broadcastIntentWithFeature()
→ → → AMS.broadcastIntentLocked() /broadcastIntentLockedTraced()
→ → → → BroadcastQueueModernImpl.enqueueBroadcastLocked()
→ → → → → BroadcastQueueModernImpl.updateRunningListLocked()
→ → → → → →BroadcastQueueModernImpl.scheduleReceiverWarmLocked()
→ → → → → → BroadcastQueueModernImpl.dispatchReceivers()
→ → → → → → → IApplicationThread.scheduleRegisteredReceiver()
→→ → → → → → → → ActivityThread.post()
→→ → → → → → → → → Args.run()
→ → → → → → → → → → BroadcastReceiver.onReceive()
→ → → → → → → → → → → AMS.finishReceiver()
→ → → → → → → → → → → →BroadcastQueueModernImpl.finishReceiverLocked()
→ → → → → → → → → → → →→AMS.appNotResponding(queue.app, tr)
0. 广播产生并发送给AMS
应用或系统广播产生并发送给AMS
源码路径:frameworks/base/core/java/android/app/ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess(); // 防止系统进程误用普通API
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this); // 清理不可序列化对象,确保跨进程传输
// 通过Binder调用AMS的广播接口
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), // 调用方线程标识
getAttributionTag(), // 权限追踪标签
intent, resolvedType, null, Activity.RESULT_OK,
null, null, null, null, null, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
1. AMS投递广播到队列并启动超时检测
源码路径:frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@GuardedBy("mService")
private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
@NonNull BroadcastRecord r, int index) throws BroadcastRetryException {
final ProcessRecord app = queue.app;
// 仅在满足条件时启动超时检测
if (mService.mProcessesReady && !r.timeoutExempt && !r.isAssumedDelivered(index)) {
queue.setTimeoutScheduled(true);
// 区分前台/后台广播超时阈值
final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
: mBgConstants.TIMEOUT);
startDeliveryTimeoutLocked(queue, softTimeoutMillis); // 启动动态超时检测
} else {
queue.setTimeoutScheduled(false); // 豁免超时检测
}
// 处理后台Activity启动权限的超时(新增特性)
if (r.mBackgroundStartPrivileges.allowsAny()) {
final long bgStartTimeout = r.isForeground() ? mFgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT
: mBgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT;
// 通过Handler延迟发送超时消息
mLocalHandler.sendMessageDelayed(
Message.obtain(mLocalHandler, MSG_BG_ACTIVITY_START_TIMEOUT, args), bgStartTimeout);
}
}
ActivityManagerService定义了广播ANR的双阈值动态控制:
前台广播(mFgConstants.TIMEOUT):默认10秒,保障用户体验。
后台广播(mBgConstants.TIMEOUT):默认60秒,放宽限制以节省资源
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
static final int BROADCAST_FG_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // 前台广播默认10秒
static final int BROADCAST_BG_TIMEOUT = 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // 后台广播默认60秒
public BroadcastQueue getBroadcastQueue(ActivityManagerService service) {
// Broadcast policy parameters
final BroadcastConstants foreConstants = new BroadcastConstants(
Settings.Global.BROADCAST_FG_CONSTANTS);
foreConstants.TIMEOUT = BROADCAST_FG_TIMEOUT;
final BroadcastConstants backConstants = new BroadcastConstants(
Settings.Global.BROADCAST_BG_CONSTANTS);
backConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
return new BroadcastQueueModernImpl(service, service.mHandler,
foreConstants, backConstants);
}
}
2. 目标进程接收并处理广播
源码路径:frameworks/base/core/java/android/app/LoadedApk.ReceiverDispatcher.java
public void performReceive(Intent intent) {
// 封装为Runnable投递到主线程消息队列
Args args = new Args(intent, ...);
mActivityThread.post(args); // 使用主线程Handler
}
3. 超时检测取消入口(finishReceiverLocked)
源码路径:frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
BroadcastQueueModernImpl.finishReceiverLocked
/**
* 处理广播接收完成或超时的核心逻辑,更新状态并触发后续操作
*
* @param queue 目标进程的广播队列(包含当前活跃的广播记录)
* @param deliveryState 广播投递状态(如超时/DELIVERY_TIMEOUT、正常完成等)
* @param reason 状态变更原因(用于日志和调试)
*/
@GuardedBy("mService")
private void finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
@DeliveryState int deliveryState, @NonNull String reason) {
// 1. 校验队列有效性:若当前无活跃广播,直接返回
if (!queue.isActive()) {
logw("Ignoring finishReceiverActiveLocked; no active broadcast for " + queue);
return;
}
// 2. 获取当前广播上下文
final int cookie = traceBegin("finishReceiver"); // 性能追踪标记
final ProcessRecord app = queue.app; // 目标进程记录
final BroadcastRecord r = queue.getActive(); // 当前处理的广播记录
final int index = queue.getActiveIndex(); // 接收者索引
final Object receiver = r.receivers.get(index); // 具体的接收者对象
// 3. 更新投递状态(如标记超时或完成)
setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
// 4. 处理超时场景
if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
r.anrCount++; // 记录ANR次数
if (app != null && !app.isDebugging()) { // 非调试进程才触发ANR
final AutoCloseable timer = mAnrTimer.accept(queue);
final String packageName = getReceiverPackageName(receiver);
final String className = getReceiverClassName(receiver);
// 构造ANR报告记录
TimeoutRecord tr = TimeoutRecord.forBroadcastReceiver(r.intent, packageName,
className).setExpiredTimer(timer);
mService.appNotResponding(queue.app, tr); // 触发ANR弹窗
} else {
mAnrTimer.discard(queue); // 调试进程忽略ANR
}
}
// 5. 正常完成时取消超时检测
else if (queue.timeoutScheduled()) {
cancelDeliveryTimeoutLocked(queue); // 关键:移除超时消息
}
// 6. 检查是否有等待条件被满足(如有序广播的链式触发)
checkAndRemoveWaitingFor();
traceEnd(cookie); // 结束性能追踪
}
1.广播处理完成 → finishReceiverActiveLocked(DELIVERY_DONE, "正常完成")
→ cancelDeliveryTimeoutLocked()
├─ mAnrTimer.cancel()
└─ (旧版) Handler.removeMessages()
2.广播超时 → finishReceiverActiveLocked(DELIVERY_TIMEOUT, "超时")
→ mService.appNotResponding()
→ 触发ANR弹窗或日志记录
4.触发AMS的ANR弹窗
@Override
public void appNotResponding(@NonNull String processName, int uid,
@NonNull TimeoutRecord timeoutRecord) {
ActivityManagerService.this.appNotResponding(processName, uid, timeoutRecord);
}
广播ANR中系统优化方案参考