赞
踩
Android系统中,system_server进程的组件ActivityManagerService(简称AMS)和InputManagerService(简称IMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现Application Not Responding ,即ANR。
ANR的机制是为了增强用户体验,避免设备长时间处在无法响应用户操作的状态。应用发生ANR后,系统对用户可感知的应用,创建弹框提示用户发生ANR,让用户选择继续运行或者强制关闭。系统对于用户不可感知的应用,直接杀掉其进程。
Android的ANR主要有两种方式触发:
1,通过handler的延迟机制触发ANR。
2,Input事件触发ANR。
Service、BroadcastReceiver、ContentProvider都是通过handler的延时机制触发ANR。
以下四个条件都可以造成ANR发生:
1,BroadcastQueue Timeout
在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。
2,Service Timeout
前台服务20秒内,后台服务在200秒内没有执行完毕。
3,ContentProvider Timeout
ContentProvider的publish在10s内没进行完。
4,Input Dispatching Timeout
5秒内无法响应屏幕触摸事件或键盘输入事件。
在startService过程根据发起方进程callerApp所属的进程调度组来决定被启动的服务是属于前台还是后台。当发起方进程不等于ProcessList.SCHED_GROUP_BACKGROUND(后台进程组)则认为是前台服务,否则为后台服务,并标记在ServiceRecord的成员变量createdFromFg。简单来说就是Adj>200的进程对用户来说基本是无感知,主要是做一些后台工作,故后台服务拥有更长的超时阈值,同时后台服务属于后台进程调度组,相比前台服务属于前台进程调度组,分配更少的CPU时间片。
1, APP与AMS之间的Binder通信
ApplicationThread 实现IBinder接口,注册为IApplicationThread的服务端。它是ActivityThread的一个内部类,都运行在UI thread,即main thread。ApplicationThread有自己的handler:mH,通过公用mainlooper消息队列与ActivityThread的mainHander通信。
xxxService.getService()获取xxx服务的一个客户端对象xxxServiceProxy,然后就可以跟AMS通信了。
2,Service ANR机制
3,Broadcast超时检测
如果是动态广播,或者静态广播没有正在执行持久化操作的SP任务,则不需要经过“queued-work-looper”线程中转。根据发送广播sendBroadcast(Intent intent)中的intent的flags是否包含FLAG_RECEIVER_FOREGROUND来决定把该广播是放入前台广播队列或者后台广播队列,前台广播队列的超时为10s,后台广播队列的超时为60s,默认情况下广播是放入后台广播队列,除非指明加上FLAG_RECEIVER_FOREGROUND标识。
4, ContentProvider 超时检测
provider的超时是在provider进程首次启动的时候才会检测,当provider进程已启动的场景,再次请求provider并不会触发provider超时。
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。
EventHub模块直接访问所有的设备节点/dev/input/event1、/dev/input/event2…/dev/input/eventN。InputReader运行于独立线程,负责管理输入设备的列表和配置,以及进行输入事件的加工处理。通过线程循环不断地通过getEvent()函数从EventHub中将事件取出并进行处理。对于设备节点的增删事件,他会更新输入设备列表于配置。对于原始输入事件,InputReader对其进行翻译,组装封装包含更多的信息,然后交给InputDispatcher进行派发。InputDispatcher对 Global 和 System 键默认是不会发给 App 的,Dispatcher 线程处理完后直接把它给丢掉。对于要发给 App 的事件也要放到目标 App 的队列中。传给 App 的时候向 WMS 查询当前窗口,得到目标 App 的 connection(WM 创建的),从 outBoundQueue 取出数据通过 connection 发给 App。
对于四大组件发生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则直接杀掉。
应用原因
1,主线程阻塞:如死循环、主线程处理IO时间太长、处理大数据 。
2,主线程锁住:主线程等待子线程的锁 。
3,服务端无法及时响应:服务的线程池有限,如果短时间内client过多可能导致ANR问题。
系统原因
1,CPU被抢占:比如前台在玩游戏,可能会导致你的后台广播出现ANR。
2,内存紧张:系统长期处于内存紧张,会导致频繁内存交换、回收,进而导致应用的一些操作超时。
3,CPU调度不合理:需要检查CPU调度。
4,IO紧张:系统整体IO紧张,造成平时可以很快完成的IO操作出现较长耗时。
以上归类只是初步判断,实际情况可能与初判结果大相径庭。应用Idle mode出现在支持电源模式Doze和App Standby的设备。
Other issue 可能是I/O,内存,CPU,GPU或启动其他模块的问题。
1,ANR LOG筛选
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关键字解析
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 | 这些是性能相关的关键字,也可能预示着资源紧张 |
1,GPU性能造成ANR
查看main log,发现在绘制的时候出现性能打印:
Line 180095: 09-01 10:44:46.254 2764 3064 I OpenGLRenderer: Davey! duration=32868ms; Flags=1, IntendedVsync=23678824135,
则考虑几种情况:
2,lock up导致ANR
以上是典型的abba锁导致的死锁问题。具体修复方案要根据实际场景一般来说,处理死锁问题有三种方法:
a.通过协议来预防或避免死锁,确保系统不会进入死锁状态。
b.可以允许系统进入死锁状态,然后检测它,并加以恢复。
c.可以忽视这个问题,认为死锁不可能在系统内发生。
3,binder对端返回结果慢
对于关键字:
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不足,I/O太高 IPC复杂导致对端返回慢
5,内存不足,kswapd很高
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。