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

相关推荐
shuair29 分钟前
idea 2023.3.7常用插件
java·ide·intellij-idea
paterWang1 小时前
基于 Python 和 OpenCV 的酒店客房入侵检测系统设计与实现
开发语言·python·opencv
小安同学iter1 小时前
使用Maven将Web应用打包并部署到Tomcat服务器运行
java·tomcat·maven
Yvonne9781 小时前
创建三个节点
java·大数据
东方佑1 小时前
使用Python和OpenCV实现图像像素压缩与解压
开发语言·python·opencv
太空漫步112 小时前
android社畜模拟器
android
我真不会起名字啊2 小时前
“深入浅出”系列之杂谈篇:(3)Qt5和Qt6该学哪个?
开发语言·qt
laimaxgg2 小时前
Qt常用控件之单选按钮QRadioButton
开发语言·c++·qt·ui·qt5
水瓶丫头站住2 小时前
Qt的QStackedWidget样式设置
开发语言·qt
不会飞的小龙人2 小时前
Kafka消息服务之Java工具类
java·kafka·消息队列·mq