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的方式后有咩有感到惊讶呢。

相关推荐
csbysj20201 天前
Vue3 表单
开发语言
Sylvia-girl1 天前
Java之构造方法
java·开发语言
予枫的编程笔记1 天前
深度解析Kibana:从基础到进阶的全维度数据可视化指南
java·人工智能·elasticsearch·kibana
Thera7771 天前
C++ 中如何安全地共享全局对象:避免“multiple definition”错误的三种主流方案
开发语言·c++
C_心欲无痕1 天前
js - generator 和 async 函数讲解
开发语言·javascript·ecmascript
MindCareers1 天前
Beta Sprint Day 1-2: Alpha Issue Fixes Initiated + Mobile Project Setup
android·c语言·数据库·c++·qt·sprint·issue
galaxyffang1 天前
漏桶、令牌桶与滑动窗口业务场景选型
java
龚礼鹏1 天前
Android应用程序 c/c++ 崩溃排查流程三——ndk-stack工具使用
android
七夜zippoe1 天前
依赖注入:构建可测试的Python应用架构
开发语言·python·架构·fastapi·依赖注入·反转
zhengfei6111 天前
CVE-2025-13156 - Vitepos WooCommerce 的销售(POS) 系统漏洞
android