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

相关推荐
Monodye8 分钟前
【Java】网络编程:TCP_IP协议详解(IP协议数据报文及如何解决IPv4不够的状况)
java·网络·数据结构·算法·系统架构
一丝晨光15 分钟前
逻辑运算符
java·c++·python·kotlin·c#·c·逻辑运算符
元气代码鼠16 分钟前
C语言程序设计(进阶)
c语言·开发语言·算法
霍霍哈嗨28 分钟前
【QT基础】创建项目&项目代码解释
开发语言·qt
friklogff29 分钟前
【C#生态园】从图像到视觉:Emgu.CV、AForge.NET、OpenCvSharp 全面解析
开发语言·c#·.net
无名指的等待71239 分钟前
SpringBoot中使用ElasticSearch
java·spring boot·后端
Tatakai251 小时前
Mybatis Plus分页查询返回total为0问题
java·spring·bug·mybatis
武子康1 小时前
大数据-133 - ClickHouse 基础概述 全面了解
java·大数据·分布式·clickhouse·flink·spark
.生产的驴1 小时前
SpringBoot 消息队列RabbitMQ 消费者确认机制 失败重试机制
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
虚拟搬运工1 小时前
Python类及元类的创建流程
开发语言·chrome·python