本文为 Android App ANR 系列的第一篇,主要是从系统的角度来剖析 Android ANR 的设计思想,系列文章目录如下
- Android App ANR 系列 1 :理解 Android ANR 设计思想
- Android App ANR 系列 2 :ANR 分析套路和关键 Log 介绍
- Android App ANR 系列 3 :ANR 案例分享
技术核查:2026-10-14。 本文保留原有讨论顺序,机制说明以 AOSP
android-15.0.0_r1为源码基线,并补充 Android 11/14/15 的公开 API 与行为边界。超时值是对应版本的默认设置,不是所有 OEM 设备的固定合同;本次未新增真机 ANR 复现结果。
分析 ANR,先确认是哪一种操作没有按时完成,再找阻塞在哪里。线上可从 Android vitals 或监控平台取得问题类型与影响面;测试机结合 bugreport、ANR 堆栈、EventLog 和 system/main log 还原现场。旧版本常见 traces.txt,较新版本多为 /data/anr/anr_*,但普通量产设备不一定允许直接读取这些目录。Perfetto 能补充时间线,前提是采集窗口覆盖了超时之前的过程。
一、ANR 的普遍性与复杂性
ANR(Application Not Responding)表示应用没有及时履行某项响应要求。主线程执行耗时操作是常见原因,但不是唯一原因:它可能在等锁、等同步 Binder 回复,也可能已经 Runnable 却长期得不到 CPU。广播通过 goAsync() 交给工作线程后,该工作线程迟迟不完成,同样可能触发 ANR。
ANR 报告归属于某个应用进程,不等于根因一定在这个应用。系统服务迟迟不返回、设备资源紧张等也可能导致应用超时。反过来,看到 system_server 或 Binder 就把问题归给系统,也缺少依据。应沿等待关系继续检查。
- 应用 ANR:围绕组件完成、输入确认等具体条件检测超时。
- 系统无响应:工程排查中有时称为 SNR;AOSP 的
system_serverWatchdog 会检查指定 Handler 线程和 Monitor 的进展。它不是与所有 ANR 类型一一对应的统一分类,也不是只看进程是否存活。Watchdog 源码
这些检测大多由应用外的系统组件负责,避免只依赖已经阻塞的应用主线程。但检测线程仍会受调度延迟和系统锁影响,没有“系统负载再高也能精确裁决”的保证。
检测到超时、采集诊断、显示对话框、结束进程是不同步骤。系统不遵循“先杀死应用,再冻结其完整现场,最后让用户决定”的固定顺序。部分后台 ANR 可以静默处理;前台 ANR 也要结合恢复、调试状态和系统策略决定是否显示对话框。ANR trace 通常以线程堆栈为主,不是完整内存快照,也不保证所有线程在同一时刻被冻结。处理流程
二、ANR 的核心设计哲学
ANR 的本质:系统级监控与强制干预
可以把许多 ANR 检测理解为三件事:记录开始条件、等待完成确认、到期后重新检查状态。这里的“等待”通常是系统保存状态并安排定时检查,不是让 AMS 的主线程同步阻塞直到应用完成。
完成条件因类型而异。Service 关注生命周期回调是否执行完,广播关注接收处理是否结束,输入系统关注事件是否收到完成响应。并不是应用每发起一次 Binder 调用,系统就为它设置一个统一的 ANR 倒计时。
以服务派发为例,Android 15 的 IApplicationThread 是 oneway 接口。系统提交任务后,应用还要调度到对应线程执行,不能用“同步 Binder 调用保证业务原子性”来解释这条路径。超时控制和事务同步/异步,是两个需要分别核对的问题。
组件类 ANR:异步任务的全局防护逻辑
在 Android 15 的 ActiveServices 中,创建服务的路径先调用 bumpServiceExecutingLocked() 记录执行状态,再调用 scheduleCreateService()。应用侧 ActivityThread.handleCreateService() 执行 Service.onCreate(),随后通过 serviceDoneExecuting() 报告完成。创建、启动、绑定等路径各有处理,不能只看一个 onCreate() 的耗时。
主线程还没轮到服务消息、正在做应用初始化,或被其他组件堵住,都可能消耗执行预算。把服务的长期业务工作放到子线程,并不意味着 onCreate() 或 onStartCommand() 可以在主线程等待子线程完成。框架对生命周期回调的完成确认,与业务任务何时结束也不是同一件事。
常见类型可以这样区分:
| 类型 | 关注的完成条件 | 默认时间与版本边界 |
|---|---|---|
| Execute service | 服务生命周期回调完成,并由框架回报 | Android 15 AOSP 的短/长执行超时通常为 20/200 秒,由服务执行状态选择;不要与提升为前台服务的期限混淆 |
| 广播接收 | onReceive() 返回;使用 goAsync() 时为 PendingResult.finish() |
Android 13 及以前,前台优先级广播通常 10 秒、其他通常 60 秒;Android 14+ 在 CPU 饥饿情况下可延至 20/120 秒 |
| JobService 回调 | onStartJob() / onStopJob() 及时返回 |
Android 14+ 上,对 targetSdk 34+ 应用,回调响应超时会显式触发 ANR;返回期限不是后台任务全部完成期限 |
| ContentProvider | 受监控的远端请求及时响应 | 可能涉及进程启动、Binder 线程或查询本身,需看实际检测设置,不能统一套用输入的 5 秒 |
广播的“前台优先级”由 FLAG_RECEIVER_FOREGROUND 等条件区分,不能只看应用是否有前台 Activity。goAsync() 不会消除原有完成期限。详见分类诊断文档和 Android 14 JobScheduler 变更。
ProcessStateRecord 用于记录进程状态、OOM 调整等信息,Android 13 源码中已经存在。不能把它描述为 Android 14 新增的主线程消息实时监控器。类似地,调整进程优先级也不能保证 ANR 检测或诊断在高负载下准时完成。
前台服务还需要单独区分三种期限:
- 及时提升为前台服务:调用
startForegroundService()后需尽快调用startForeground()。公开排障文档将未及时提升单列为ForegroundServiceDidNotStartInTimeException;不能写成“Android 15 统一 3 秒后 ANR”,也不要依赖未证实的persist.sys.fgs_timeout属性。 - shortService 的运行期限:Android 14 引入的该类型约有 3 分钟运行时间,超时通知后仍不停止可能导致 ANR。这是分钟级的服务运行期限,不是初始化的 3 秒。服务类型说明
- Android 15 的限时服务:对 targetSdk 35+ 应用,
dataSync、mediaProcessing在后台各自按类型共享 24 小时内累计 6 小时的预算,用户把应用带到前台会重置相应计时。收到onTimeout()后仍不停止,公开排障文档描述为内部异常导致崩溃;该源码基线的崩溃路径还受功能开关控制,不能仅凭源码分支推断每台设备均已启用。不要与 shortService 的 ANR 混为一谈。超时规则
诊断资料也有边界。Android 11(API 30)起,可以通过历史退出记录取得 ApplicationExitInfo。它不是所有活跃 ANR 的实时数据库:getTimestamp() 是进程退出时间;getTraceInputStream() 可能因保留空间被覆盖而返回 null。进程发生 ANR 后恢复、稍后因其他原因退出,记录仍可能带有先前的 ANR trace。因此应同时看退出原因、时间和 trace 内容。
Input 类 ANR:输入事件分发的动态熔断体系
输入链路中,EventHub 读取设备数据,InputReader 完成设备相关解释,InputDispatcher 再根据窗口与事件类型分发。这里的“熔断”是对超时处理的概括,不代表每次超时都会立即杀进程。
- EventHub:使用
epoll_wait()等待设备文件描述符上的活动,再用read()读取 Linuxinput_event。inotify主要用于设备节点创建、删除等变化,不负责传输触摸原始数据。阻塞等待能减少忙轮询开销,但不能承诺零 CPU 消耗。源码 - InputReader:通过 InputMapper 处理触摸、按键等设备数据,生成后续分发使用的通知参数。它与 Dispatcher 分线程工作,并不意味着所有队列无锁;Android 15 的代码会在锁内交换待发送数据,再在锁外通知后续 listener。源码
- InputDispatcher:通过 InputChannel 与应用通信。按键等事件依赖焦点窗口,触摸通常还要做命中测试,不能把所有输入都简化为“发给焦点窗口”。
InputDispatcher 维护待分发事件队列,以及每个连接的 outboundQueue、waitQueue。前者等待发送,后者保存已经发送、等待应用确认完成的事件。
发送时会记录该次派发的时间与期限;等待确认的事件通过 mAnrTracker 参与到期检查。调度循环根据下一次到期时间安排唤醒,完成响应则推进队列和相关记录。这里不是原文所称的通用 MonitoredTimeout 或固定周期心跳模型。普通输入响应默认常见 5 秒,但窗口、应用和系统配置可影响实际期限。
应用主线程卡住,并不会自动让 InputReader 的读取线程也停下;不过系统线程自身的锁、调度和 Binder 延迟仍可能成为问题。定位时要分别检查应用是否收到事件、何时开始处理、何时完成,以及系统在等待哪个确认。
No Focused Window 类 ANR
No Focused Window 属于输入派发 ANR。Android 15 的对应路径在需要派发给焦点窗口的事件到来时,如果已有焦点应用、却没有焦点窗口,会启动等待期限。若焦点应用和窗口都不存在,则可能直接丢弃该类事件,而不是无条件报告 ANR。
它的默认等待时间同样常见为 5 秒,不是“连续几次找不到窗口就更快触发”。与窗口存在但不确认事件的超时相比,这里缺的是可接收该事件的窗口。
窗口焦点要结合可见性、焦点属性、显示与窗口管理状态判断。新 Activity、Dialog 或 PopupWindow 出现,不保证它一定获得焦点;也没有适用于所有切换的“旧窗口 relayout 后新窗口 addWindow”固定流程。
常见应用侧原因包括启动路径过重、首帧迟迟未准备好,以及主窗口带有 FLAG_NOT_FOCUSABLE。因此应先核对 Application/Activity 初始化、窗口配置和首帧时间,再检查 WMS、system_server 负载及系统服务延迟。官方诊断说明
不能仅凭 ANR 类型就认定责任在系统或应用:用窗口状态和时间线证明哪一环没有及时完成。
系统设计的统一性原则
从这些实现中,可以归纳出四点:
- 完成条件明确:不同操作用不同的确认与状态,不能只设一个全局“主线程卡住多久”的计时器。
- 检测与执行分离:应用阻塞后仍可能由系统检测,但系统自身也受资源和锁约束。
- 判定与处置分离:诊断、静默处理、提示用户和进程终止按场景执行,不保证每次都有弹窗或自动重启。
- 异步仍有合同:换工作线程可以减轻主线程负担,却不能消除广播完成期限、组件回调要求或资源竞争。
这些原则能帮助我们判断该查哪个完成条件,而不是先把所有 ANR 都归为某一种阻塞。
ANR 问题的全局解析与主动防御
分析范围可以从应用扩展到系统,但每扩展一层都要有证据。主线程的一张堆栈,是调查起点,不是整个超时区间的录像。
从现象到根源:逐层解剖 ANR 问题
- 确认现象:记录 ANR 类型、Subject、进程与线程、系统版本和发生时间。没有弹窗不等于没有 ANR;也不要把普通崩溃自动算成 ANR。
- 确认检测条件:组件侧检查派发、回调和完成上报;输入侧检查窗口、连接与确认事件。两者都可以采用异步检测,不存在“AMS 同步阻塞检测、InputDispatcher 才异步”的二分。
- 沿等待关系追踪:主线程等同步 Binder,就检查对端线程与回复;等锁,就找持有者;长期 Runnable,就检查 CPU 可用性、调度与系统负载。Binder 线程池容量和忙闲情况按实际进程核对,不套用一个通用线程数常量。
- 验证资源因素:CPU、I/O、内存回收和 GPU 等只有在相关时间段出现对应证据时,才支持根因推断。不能从 CPU 乱序执行直接推导锁竞争,也不能从内存带宽紧张直接推导 Binder 拷贝风暴。
如果证据只证明“某线程在等”,就继续查它等什么、对端何时有进展;暂时没有记录的部分明确保留为未知。
从被动应对到主动防御:ANR 治理的三步走
- 堆栈分析:先对齐检测时间与采样时间。
nativePollOnce可能是采样时线程已经恢复、当时确实空闲或消息调度异常,需要结合 ANR 类型解读。没有提前采样,就不能凭现有日志还原“前后 5 秒的所有堆栈”。 - 动态追踪:对可复现问题预先录制 Perfetto,围绕目标时间窗分析调度、Binder、锁和 I/O。确认启用的数据源、覆盖窗口及丢失情况,再把堆栈快照放回时间线;时间相邻不等于因果。
- 架构预防:缩短主线程关键路径,避免持锁做长同步 IPC;给工作队列设置并发与积压预算,并保证组件及时完成。采用 Executor、HandlerThread 或协程时仍要防止线程池饱和、主线程反向等待和漏报完成。广播或事件总线不是所有同步调用的通用替代方案。
Android vitals 的聚类和 ANR Insights 可以辅助发现常见模式。若团队建立规则或机器学习分类器,应验证标注质量、误报和漏报,并把输出当排查线索;不能仅凭平台提供聚类功能,就推断其使用了某套未公开的“20 多项指标预测模型”。
ANR 相关资料分享
以下保留历史案例与研究文章,阅读时结合各自讨论的系统版本。
- 反思|Android 输入系统 & ANR机制的设计与实现
- 西瓜视频稳定性治理体系建设一:Tailor 原理及实践
- 西瓜视频稳定性治理体系建设二:Raphael 原理及实践
- 西瓜视频稳定性治理体系建设三:Sliver 原理及实践
- 西瓜卡顿 & ANR 优化治理及监控体系建设
- 今日头条 ANR 优化实践系列 - 设计原理及影响因素
- 今日头条 ANR 优化实践系列 - 监控工具与分析思路
- 今日头条 ANR 优化实践系列分享 - 实例剖析集锦
- 今日头条 ANR 优化实践系列 - Barrier 导致主线程假死
- 今日头条 ANR 优化实践系列 - 告别 SharedPreference 等待
- Android ANR|原理解析及常见案例
参考资料
- https://duanqz.github.io/2015-10-12-ANR-Analysis#1-%E6%A6%82%E8%A7%88
- https://duanqz.github.io/2015-10-12-ANR-Analysis
- http://gityuan.com/2016/12/02/app-not-response/
- http://gityuan.com/2017/01/01/input-anr/
- https://xiaozhuanlan.com/topic/5097486132
关于我 && 博客
下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!
- 博主个人介绍 :里面有个人的微信和微信群链接。
- 本博客内容导航 :个人博客内容的一个导航。
- 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
- Android性能优化知识星球 :2026 年已关闭,保留历史介绍。
一个人可以走的更快 , 一群人可以走的更远