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
@Overridepublic void sendBroadcast(Intent intent) {warnIfCallingFromSystemProcess(); // 防止系统进程误用普通APIString 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.Stubimplements 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 parametersfinal 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()) { // 非调试进程才触发ANRfinal 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弹窗
@Overridepublic void appNotResponding(@NonNull String processName, int uid,@NonNull TimeoutRecord timeoutRecord) {ActivityManagerService.this.appNotResponding(processName, uid, timeoutRecord);}
广播ANR中系统优化方案参考
