ANR问题原理介绍与DEBUG分析

一、ANR简介

Android系统中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。

Android的ANR主要有两种方式触发:

1,通过handler的延迟机制触发ANR。

2,Input事件触发ANR。

Service、BroadcastReceiver、ContentProvider都是通过handler的延时机制触发ANR。

二、ANR发生场景

以下四个条件都可以造成ANR发生:

1,BroadcastQueue Timeout 

    执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。

2,Service Timeout 

    前台服务20秒内,后台服务在200秒内没有执行完毕。

3,ContentProvider Timeout 

    ContentProviderpublish10s内没进行完。

4,Input Dispatching Timeout

    5秒内无法响应屏幕触摸事件或键盘输入事件。

startService过程根据发起方进程callerApp所属的进程调度组来决定被启动的服务是属于前台还是后台。当发起方进程不等于ProcessList.SCHED_GROUP_BACKGROUND(后台进程组)则认为是前台服务,否则为后台服务,并标记在ServiceRecord的成员变量createdFromFg。简单来说就是Adj>200的进程对用户来说基本是无感知,主要是做一些后台工作,故后台服务拥有更长的超时阈值,同时后台服务属于后台进程调度组,相比前台服务属于前台进程调度组,分配更少的CPU时间片。

三、ANR触发原理

1, APP与AMS之间的Binder通信

ANR问题原理介绍与DEBUG分析_第1张图片

2,Service ANR机制

ANR问题原理介绍与DEBUG分析_第2张图片

3,Broadcast超时检测

ANR问题原理介绍与DEBUG分析_第3张图片

如果是动态广播,或者静态广播没有正在执行持久化操作的SP任务,则不需要经过“queued-work-looper线程中转。根据发送广播sendBroadcast(Intent intent)中的intentflags是否包含FLAG_RECEIVER_FOREGROUND来决定把该广播是放入前台广播队列或者后台广播队列,前台广播队列的超时为10s,后台广播队列的超时为60s,默认情况下广播是放入后台广播队列,除非指明加上FLAG_RECEIVER_FOREGROUND标识。

4, ContentProvider 超时检测

provider的超时是在provider进程首次启动的时候才会检测,当provider进程已启动的场景,再次请求provider并不会触发provider超时。

ANR问题原理介绍与DEBUG分析_第4张图片

5, Input超时机制

input的超时检测机制跟service、broadcast、provider截然不同,为了更好的理解input过程先来介绍两个重要线程的相关工作:

InputReader线程负责通过EventHub(监听目录/dev/input)读取输入事件,一旦监听到输入事件则放入到InputDispatcher的mInBoundQueue队列,并通知其处理该事件;

InputDispatcher线程负责将接收到的输入事件分发给目标应用窗口,分发过程使用到3个事件队列:

a. mInBoundQueue用于记录InputReader发送过来的输入事件;

b. outBoundQueue用于记录即将分发给目标应用窗口的输入事件;

c. waitQueue用于记录已分发给目标应用,且应用尚未处理完成的输入事件;

input的超时机制并非时间到了一定就会爆炸,而是处理后续上报事件的过程才会去检测是否该爆炸。表现就是我们在UI界面操作即使某个时间超过阈值也不会提示,而是要到下次事件才会提示ANR。

ANR问题原理介绍与DEBUG分析_第5张图片

四,ANR信息搜集

对于四大组件发生ANR后,AMS会马上去抓取现场的信息,用于调试分析。收集的信息包括如下:

1,将am_anr信息输出到EventLog,也就是说ANR触发的时间点最接近的就是EventLog中输出的am_anr信息。

2,收集以下重要进程的各个线程调用栈trace信息,保存在data/anr/traces.txt文件:

      a, 当前发生ANR的进程,system_server进程以及所有persistent进程

      b, audioserver, cameraserver, mediaserver, surfaceflinger等重要的native进程

      c, CPU使用率排名前5的进程

3,将发生ANR的reason以及CPU使用情况信息输出到main log,/data/anr/目录。

4,将traces文件和CPU使用情况信息保存到dropbox,即data/system/dropbox目录。

5,对用户可感知的进程则弹出ANR对话框告知用户,对用户不可感知的进程发生ANR则直接杀掉。

五,导致ANR的原因

应用原因

1,主线程阻塞:如死循环、主线程处理IO时间太长、处理大数据 。

2,主线程锁住:主线程等待子线程的锁 。

3,服务端无法及时响应:服务的线程池有限,如果短时间内client过多可能导致ANR问题。

系统原因

1,CPU被抢占:比如前台在玩游戏,可能会导致你的后台广播出现ANR。

2,内存紧张:系统长期处于内存紧张,会导致频繁内存交换、回收,进而导致应用的一些操作超时。

3,CPU调度不合理:需要检查CPU调度。

4,IO紧张:系统整体IO紧张,造成平时可以很快完成的IO操作出现较长耗时。

六,ANR问题分析步骤

ANR问题原理介绍与DEBUG分析_第6张图片

七,应用问题分析步骤

ANR问题原理介绍与DEBUG分析_第7张图片

Other issue 可能是I/O,内存,CPU,或启动其他模块的问题。

八,ANR LOG分析

1,ANR LOG筛选

ANR问题原理介绍与DEBUG分析_第8张图片

KeyDispatch Timeout : “dispatching timed out”

Broadcast Timeout: “Timeout of broadcast BroadcastRecord”

Service Timeout: “Timeout executing service”

Content Provider Timeout: “timeout publishing content providers”

2,ANR trace关键字解析

ANR问题原理介绍与DEBUG分析_第9张图片

sCount 此线程被挂起的次数

dsCount 线程被调试器挂起的次数

prio=5 priority 优先级

nice 线程调度的优先级

utm 线程用户态下使用的时间值(单位是jiffies)

stm 内核态下的调度时间值

core  最后执行这个线程 cpu核的序号

cgrp=default 线程调度组

sched=0/0 线程调度策略和优先级

线程处理函数地址:handle=0x7f85742548

3,其他日志关键字

关键字

说明

CPU usage from

筛选CPU信息确认CPU是否被占用

 Free RAM:

cached pss 与  cached kernel 任一较低预示内存不足

am_meminfo: [1175105536,。。。]

四个值分别是:Cached, Free, Zram, Kernel, Native

lowmemorykiller:

内存不足时触发Low Memory Killer

FAILED BINDER TRANSACTION

可能是资源不足导致binder通信出错

IPCThreadState: binder thread pool

(4 threads) starved for 10018 ms

可能是资源不足导致binder通信缓慢

 Davey Displayed Choreographer

这些是性能相关的关键字,也可能预示着CPU紧张

九,示例

1,主线程处于等待状态

ANR问题原理介绍与DEBUG分析_第10张图片

上述主线程堆栈是一个很正常的空闲堆栈,主线程正在等待新的消息。如果ANR日志里主线程是这样一个状态,那可能有两个原因:

    a.该ANR是CPU抢占或内存紧张等其他因素引起。

    b.这份ANR日志抓取的时候,主线程已经恢复正常。

    c.系统处于关机、休眠等特殊场景。

遇到这种空闲堆栈,可以先确认设备场景,然后去分析CPU、内存的情况。

2,lock up导致ANR

ANR问题原理介绍与DEBUG分析_第11张图片

以上是典型的abba锁导致的死锁问题。具体修复方案要根据实际场景一般来说,处理死锁问题有三种方法:

    a.通过协议来预防或避免死锁,确保系统不会进入死锁状态。

    b.可以允许系统进入死锁状态,然后检测它,并加以恢复。

    c.可以忽视这个问题,认为死锁不可能在系统内发生。

3,binder对端返回结果慢

ANR问题原理介绍与DEBUG分析_第12张图片

对于关键字:

libbinder.so (android::IPCThreadState::talkWithDriver(bool)

通常是由于binder对端返回超时,需要对端检查原因。也有可能是对端binder线程池耗尽。

如果对端不能保证结果返回时限,本应用最好把该消息处理函数的binder调用改为异步模式。

如果要确认对端是谁,则可以通过如下命令打开binder的transaction调试后重新复现:

echo 512 > /sys/module/binder/parameters/debug_mask

也可在现场打印:

cat /d/binder/transaction_log

4,CPU不足,IPC复杂导致对端返回慢

ANR问题原理介绍与DEBUG分析_第13张图片

5,内存不足,kswapd很高

ANR问题原理介绍与DEBUG分析_第14张图片

你可能感兴趣的:(android)