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

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.lryc.cn/news/602351.html

相关文章:

  • ubuntu安装Anaconda及应用
  • 【运维】HuggingFace缓存目录结构详解
  • 首个智能存力调度平台启动!与算力网络共同加速AI创新
  • 【深度学习】SOFT Top-k:用最优传输解锁可微的 Top-k 操作
  • 应急响应案例处置(下)
  • 应急响应处置案例(上)
  • 【LeetCode 热题 100】(一)哈希
  • 绿算技术携手昇腾发布高性能全闪硬盘缓存设备,推动AI大模型降本增效
  • 零基础部署网站?使用天翼云服务搭建语音听写应用系统
  • Angular 依赖注入
  • 谷歌浏览器深入用法全解析:解锁高效网络之旅
  • 图像处理第三篇:初级篇(续)—— 照明的理论知识
  • C++算法之单调栈
  • 达梦数据库获取每个数据库表的总条数及业务实战
  • 提取excel中的年月日
  • window显示驱动开发—Direct3D 11 视频播放改进
  • 你的连接不是专用连接
  • NI Ettus USRP X440 软件无线电
  • 28天0基础前端工程师完成Flask接口编写
  • Go 语言-->指针
  • Java-数构排序
  • WAIC看点:可交付AI登场,场景智能、专属知识将兑现下一代AI价值
  • vue怎么实现导入excel表功能
  • 基于开源AI智能名片链动2+1模式与S2B2C商城小程序的微商品牌规范化运营研究
  • IDEA 手动下载安装数据库驱动,IDEA无法下载数据库驱动问题解决方案,IDEA无法连接数据库解决方案(通用,Oracle为例)
  • idea启动java应用报错
  • 设计模式十二:门面模式 (FaçadePattern)
  • 结合项目阐述 设计模式:单例、工厂、观察者、代理
  • 记一次IDEA启动微服务卡住导致内存溢出问题
  • Java设计模式之<建造者模式>