2ANRMonitor_CollectInfo

应用层如何判定 ANR

Android M(6.0) 版本之后,应用侧无法直接通过监听 data/anr/trace 文件,监控是否发生 ANR,那么大家又有什么其它手段去判定 ANR 呢?下面我们简单介绍一下

站在应用侧角度来看,因为系统没有提供太友好的机制,去主动通知应用是否发生 ANR,而且很多信息更是对应用屏蔽了访问权限,但是对于三方 App 来说,也需要关注基本的用户体验,因此很多公司也进行了大量的探索,并给出了不同的解决思路,目前了解到的方案(思路)主要有下面 2 种:

  1. 主线程 watchdog 机制

核心思想是在应用层定期向主线程设置探测消息,并在异步设置超时监测,如在规定的时间内没有收到发送的探测消息状态更新,则判定可能发生 ANR,为什么是可能发生 ANR?因为还需要进一步从系统服务获取相关数据(下面会讲到如何获取),进一步判定是否真的发生 ANR。

  1. 监听 SIGNALQUIT 信号

该方案在很多公司有应用,网上也有相关介绍,这里主要介绍一下思路。我们在上面提到了虚拟机是通过注册和监听 SIGNALQUIT 信号的方式执行请求的,而对于信号机制有了解的同学马上就可以猜到,我们也可以在应用层参考此方式注册相同信号去监听。不过要注意的是注册之后虚拟机之前注册的就会被覆盖,需要在适当的时候进行恢复,否则小心系统(厂商)找上门。

当接收到该信号时,过滤场景,确定是发生用户可感知的 ANR 之后,从 Java 层获取各线程堆栈,或通过反射方式获取到虚拟机内部 Dump 线程堆栈的接口,在内存映射的函数地址,强制调用该接口,并将数据重定向输出到本地。

该方案从思路上来说优于第一种方案,并且遵循系统信息获取方式,获取的线程信息及虚拟机信息更加全面,但缺点是对性能影响比较大,对于复杂的 App 来说,统计其耗时,部分场景一次 Dump 耗时可能要超过 10S。

应用层如何获取 ANR Info

上面提到无论是 Watchdog 还是监听信号的方式,都需要结论进一步过滤,以确保收集我们想要的 ANR 场景,因此需要利用系统提供的接口,进一步判定当前应用是否发生问题(ANR,Crash);

与此同时,除了需要获取进程中各线程状态之外,我们也需要知道系统乃至其他进程的一些状态,如系统 CPU,Mem,IO 负载,关键进程的 CPU 使用率等等,便于推测发生问题时系统环境是否正常;

获取信息相关接口类如下:

通过该接口获取的相关信息,示意如下,其中下图红框选中的关键字,我们在后续 ANR 分析思路一章,会对其进行详细释义:

xcrashanr