【 Android 性能优化】ANR 问题如何监控?

前言

ANR 即 Applicatipon No Response,程序无响应。Android 系统设计了 ANR 机制,其目的是监控与其交互的组件(Activity 等)和用户交互(InputEvent)的超时情况。这样能够判断应用进程(主线程)是否存在卡死或响应过慢的问题

相比 Crash,ANR 问题存在原因复杂,不易定位的特点,本文主要包括以下内容

  1. ANR 工作流程
  2. 如何监控 ANR?
  3. 如何定位 ANR 原因?

ANR 工作流程

ANR 可能触发的时机有多种,通常可以分为以下几方面:

在这里插入图片描述

其基本原理其实 WatchDog 的思想,如果发出的事件,在一定时间内没有消费,则触发 ANR。

这里说一下总体流程,如下图所示:

在这里插入图片描述

  1. 发生 ANR 后,系统会采集许多进程数据,进行堆栈转储,以生成 ANR Trace文件。其中,第一个被采集的进程必定是发生 ANR 的进程。
  2. 系统会向这些应用进程发送 SIGQUIT 信号,这些应用进程收到信号后开始进行堆栈转储
  3. 应用进程 Dump 堆栈成功后通过 Socket 与系统进程通信写 Trace 文件
  4. 在 Trace 文件写入完成后,如果发生 ANR 的进程是前台进程则弹出 Dialog,否则则直接杀死进程

如何监控 ANR?

在了解了 ANR 的工作流程之后,我们该如何监控 ANR 的发生呢?

ANR WatchDog 检测思路

既然 ANR 的原因是输入在定时间内没有响应,那么我们很自然地想到,向主线程发送一个任务,如果一段时间内没有被执行的话,就认为发生了 ANR

这个思路主要有以下几个问题

  1. 不准确,超时条件不一定会导致 ANR,例如,5 秒超时只是在 TouchEvent 未被消耗时发生 ANR 的条件之一,而其他条件则不一定是 5 秒。
  2. 漏检测:如果超时时间定为 5 秒,去检测 TouchEvent 的 ANR 存在一定的漏检测的概率(周期不同步)。

ANR 信号监听思路

在上面介绍 ANR 总体流程时,我们注意到当 ANR 发生时会发送 SIGQUIT 信号,那么我们通过监听这一信号不就可以实现 ANR 监控了吗?事实上 XCrash与 Matrix 都是通过这种方式实现 ANR 监控的

在这里需要注意,默认情况下进程通过SignalCatcher监听SIGQUIT信号,进行堆栈转储生成 ANR Trace 文件。因此当我们监听SIGQUIT信号后,需要重新向SignalCatcher发送SIGQUIT

如果缺少重新向 SignalCatcher 发送 SIGQUIT 信号的步骤,Android System 管理服务(AMS)将一直等待 ANR 进程写入堆栈信息。直到超过20秒的超时时间,AMS 才会被迫中断,并继续后续流程。这将导致 ANR 弹窗的显示非常缓慢(因为超时时间为20秒),同时在 /data/anr 目录下也无法生成完整的 ANR Trace 文件。

误报情况处理

当监听到 SIGQUIT 信号时,不一定是发生了 ANR。

Matrix 的文档中提到了两种误报的情况:

  1. 比如可能是其它进程 ANR 了,发生 ANR 的进程不是唯一需要进行堆栈转储的进程。系统会收集许多其他进程进行堆栈转储,用于生成 ANR Trace 文件
  2. 厂商或者是开发者自己发送的SIGQUIT信号,发送SIGQUIT信号其实是很容易的一件事情

因此我们需要在监听到信号时再进行一次检查:在 ANR 弹窗前,会给发生 ANR 的进程标记一个 NOT_RESPONDING 的 flag,而这个 flag 我们可以通过 ActivityManager 来获取

private static boolean checkErrorState() {
   
    
    
    try {
   
    
    
        Application application = sApplication == null ? Matrix.with().getApplication() : sApplication;
        ActivityManager am = (ActivityManager) application.getSystemService(Context.ACTIVITY_SERVICE);

猜你喜欢

转载自blog.csdn.net/m0_70748458/article/details/130506156