Broadcast ANR 设计原理
- 只在有序广播中才会有ANR的监控
- AMS负责分发有序广播,并在分发的时候设置超时监控报警,如果广播接收者在超时时间范围内处理掉消息并和AMS通信取消本次超时监控则不会发生ANR,反之未取消则判定ANR。
- AMS是用过Binder机制和APP进程通信,当接受到广播数据,会封装数据再sendMessage到主线程消息队列,主线程处理Msg,最终调用receiver.onReceive方法。(当主线程消息队列前面有耗时任务,或者其他进程有耗时任务,影响了当前事件的调度,而不是本身事件耗时过长,也会引发ANR)
Service ANR 设计原理
Input ANR 设计原理
ANR Dump流程
- 过滤掉特殊场景(正在dump,正在关机,正在crash,正在被系统kill)
- 查找需要Dump的进程,主要包括ANR进程的父进程,SystemServer进程,高CPU的(最多5个)进程
- 发送SIGQUIT信号给需要Dump的进程
- 各进程SignalCatcher线程收集当前虚拟机信息,内存信息,class信息,GC信息,再挂起所有线程,获取线程的堆栈信息
- 最后通过管道发送给SystemServer,追加写入到Trace文件中
应用检测ANR
- watchdog
- 监听SIGNALQUIT信号,确定自己进程ANR时候,Java端获取堆栈信息,或者反射调用虚拟机内部Dump线程的堆栈接口,获取数据输出到自己的目录下。
实现参考Xcrash:https://github.com/iqiyi/xCrash/blob/master/README.zh-CN.md
获取ANR Info
- 通过ActivityManagerService.getProcessesInErrorState,遍历mLruProcesses,并根据进程目前的异常状态如crash或者anr类型,返回具体的ProcessErrorStateInfo
ANR出现前消息队列中耗时情况
- 当前 Trace 堆栈所在业务耗时严重;
- 当前 Trace 堆栈所在业务耗时并不严重,但是历史调度有一个严重耗时;
- 当前 Trace 堆栈所在业务耗时并不严重,但是历史调度有多个消息耗时;
- 当前 Trace 堆栈所在业务耗时并不严重,但是历史调度存在巨量重复消息(业务频繁发送消息);
- 当前 Trace 堆栈业务逻辑并不耗时,但是其他线程存在严重资源抢占,如 IO,Mem,CPU;
- 当前 Trace 堆栈业务逻辑并不耗时,但是其他进程存在严重资源抢占,如 IO,Mem,CPU;
ANR日志语义分析
Load: 2.62 / 2.55 / 2.25
表示:1、5、15 分钟内正在使用和等待使用CPU 的活动进程的平均数CPU usage from 0ms to 1987ms later (2020-03-10 08:31:55.169 to 2020-03-10 08:32:17.156)
表明:负载信息抓取在ANR发生之后的0~1987ms。同时也指明了ANR的时间点:2020-03-10 08:31:55.169
如果是 CPU usage xxx awake 表示是ANR之前的系统负载信息41% 2080/system_server: 28% user + 12% kernel / faults: 76445 minor 180 major 26% 9378/com.xiaomi.store: 20% user + 6.8% kernel / faults: 68408 minor 68 major
表示:各个进程占用的CPU的详细情况66% TOTAL: 20% user + 15% kernel + 28% iowait + 0.7% irq + 0.7% softirq
表示:各进程合计占用CPU的信息
ANR 关键字
a. user:用户态,kernel:内核态
b. faults:内存缺页,minor——轻微的,major——重度,需要从磁盘拿数据
c. iowait:IO使用(等待)占比
d. irq:硬中断,softirq:软中断
e. utm: user space time,stm: kernel space time
参考: