当前位置: 首页 > java >正文

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/接收者类名等上下文)

0

源码分析

→ 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(); // 防止系统进程误用普通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弹窗

@Overridepublic void appNotResponding(@NonNull String processName, int uid,        @NonNull TimeoutRecord timeoutRecord) {    ActivityManagerService.this.appNotResponding(processName, uid, timeoutRecord);}

广播ANR中系统优化方案参考

0

http://www.xdnf.cn/news/16569.html

相关文章:

  • Linux系统Centos7 安装mysql5.7教程 和mysql的简单指令
  • rhel9.1配置本地源并设置开机自动挂载(适用于物理光驱的场景)
  • 在 Windows 系统 下直接使用了 Linux/macOS 的环境变量设置语法 PLATFORM=android
  • 图像处理第三篇:初级篇(续)—— 照明的理论知识
  • 问题大全【1】
  • Ansible提权sudo后执行报错
  • STM32——寄存器映射
  • Day22-二叉树的迭代遍历
  • NAS远程访问新解法:OMV与cpolar的技术协同价值
  • 浏览器安全演进:从裸指针到 raw_ptr 的实践与思考
  • QGIS基于规则的道路分级制图及Leaflet集成展示实例
  • 日志分析-windows日志分析base--笔记ing
  • 数论1.01
  • 【实时Linux实战系列】在实时应用中进行负载均衡
  • Python day27
  • 【硬件】LVGL
  • 时序数据基座升维:Apache IoTDB 以“端边云AI一体化”重构工业智能决策
  • Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式能源接入与电网稳定性保障中的应用(368)
  • 基于黑马教程——微服务架构解析(二)
  • OpenI x SCNet “智能超算”创新应用挑战赛:实践阶段1和阶段2 部署Deepseek推理模型
  • 图片格式转换
  • AR技术赋能工业设备维护:效率与智能的飞跃
  • 【数据结构初阶】--二叉树(三)
  • 使用signal信号机制 + backtrace函数打印出程序崩溃后的堆栈信息
  • Flutter在购物场景中BLoC的应用
  • MySQL面试题及详细答案 155道(001-020)
  • 无人机气动设计模块解析
  • 微信小程序点击输入框时,顶部导航栏被遮挡问题如何解决?
  • 秩为1的矩阵的特征和性质
  • 【数据库】时序数据库选型指南:从大数据视角看IoTDB的核心优势