Android系统是如何检测到ANR- 应用无响应的?

起言

最近debug应用时,发现只要看debug的变量内容太久了,app也会爆出anr问题,遂想对ANR做一个系统的整理。

正文

导致ANR

导致ANR的直观原因在Android官网已经说的很清楚了

---- 引用自ANR | App quality | Android Developers

出现以下任何情况时,系统都会针对您的应用触发 ANR:

  • 输入调度超时:如果您的应用在 5 秒内未响应输入事件(例如按键或屏幕触摸)。
  • 执行服务 :如果应用声明的服务无法在几秒内完成 Service.onCreate()Service.onStartCommand()/Service.onBind() 执行。
  • 未调用 Service.startForeground() :如果您的应用使用 Context.startForegroundService() 在前台启动新服务,但该服务在 5 秒内未调用 startForeground()
  • intent 广播 :如果 BroadcastReceiver 在设定的一段时间内没有执行完毕。如果应用有任何前台 activity,此超时期限为 5 秒。
  • JobScheduler 互动 :如果 JobService 未在几秒钟内从 JobService.onStartJob()JobService.onStopJob() 返回,或者如果用户发起的作业启动,而您的应用在调用 JobService.onStartJob() 后的几秒内未调用 JobService.setNotification()。对于以 Android 13 及更低版本为目标平台的应用,ANR 会保持静默状态,且不会报告给应用。对于以 Android 14 及更高版本为目标平台的应用,ANR 会保持活动状态,并会报告给应用。

甚至连如何查找ANR的考量因素Google大大都为我们考虑到了,干,此文结束

治理ANR

诊断 ANR 时需要考虑以下几种常见模式:

  • 应用在主线程上非常缓慢地执行涉及 I/O 的操作。
  • 应用在主线程上进行长时间的计算。
  • 主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
  • 主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。
  • 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。如需了解详情,请参阅维基百科上的死锁

但是,比起这些,我更好奇的是Android官方是如何检测到ANR的发生的?要知道,ANR发生如上文所述涉及到多个组件,Google有一套通用的实现吗

监测ANR

答案就是Handler,实际上Android系统内部很多地方都用到了handler,要写出优秀的设计,很多时候都可以考虑使用handler。

推荐阅读:Android ANR?谁控制了触发时间?

可以发现,通用套路就是向Handler发送了一个延迟消息,内容为执行ANR逻辑,如果事件被消费了,就把这个延迟消息取消掉,如果没有被消费,则消息不被取消,执行ANR产生逻辑。

示例代码如下:

java 复制代码
private Runnable anrRunnable = new Runnable() {
     @Override
     public void run() {
         Log.e(TAG, "ANR detected!");
     }
};

public void startDoSomething() {
    // 启动服务、、处理事件、、
    handler.postDelayed(anrRunnable, ANR_TIMEOUT);
}

public void finishDoSomething() {
    // 做完了,可以取消了
    handler.removeCallbacks(anrRunnable);
    // handler.removeMessages(TAG);
}

文中没有的内容补充:

对于输入事件,第一个输入事件产生后,又产生了第二个输入事件,此时若过0.5s了第一个输入事件还没有处理完毕,则设置5s的计时器,5s后第一个输入还未处理完毕,则产生ANR。

ANR后发生了什么
  1. 发送 SIGQUIT 信号:system_server 进程检测到ANR后,向应用程序进程发送 SIGQUIT 信号。
  2. 接收 SIGQUIT 信号:应用程序进程中的 libart.so 处理该信号。
  3. 调用 dump 方法:libart.so 调用Java虚拟机的 dump 方法生成线程转储。
  4. 生成 traces.txt 文件:线程转储信息被写入 traces.txt 文件,用于分析和调试ANR问题。

结语

Android官方的很多设计都值得学习,不知道大家了解到安卓检测ANR的方式后有咩有感到惊讶呢。

相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说11 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json