ANR的理论_anr概念/类型/原理/机制

本文详细介绍了Android系统中的ANR(Application Not Responding)现象,包括ANR的定义、四种主要类型(KeyDispatchTimeout、BroadcastTimeout、ServiceTimeout、ContentProviderTimeout)及其触发机制。ANR是系统监控应用响应能力的机制,当主线程被阻塞过久时,系统会弹出提示或直接杀死进程。文章还分析了ANR产生的原因,如主线程的IO操作、线程死锁、Binder阻塞等,并提供了ANR实例分析及参数解读。最后,概述了ANR的分析步骤,包括定位时间点、查看trace信息、分析耗时操作等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:什么是anr

ANR(Application Not Responding) 应用程序无响应。如果你应用程序在UI线程被阻塞太长时间,就会出现ANR,通常出现ANR,系统会弹出一个提示提示框,让用户知道。

二:anr 类型

1.KeyDispatchTimeout: input事件在5S内没有处理完成发生了ANR。

logcat日志关键字:Input event dispatching timed out

2.BroadcastTimeout

前台Broadcast:onReceiver在10S内没有处理完成发生ANR。

后台Broadcast:onReceiver在60s内没有处理完成发生ANR。

logcat日志关键字:Timeout of broadcast BroadcastRecord

3. ServiceTimeout

前台Service:onCreate,onStart,onBind等生命周期在20s内没有处理完成发生ANR。

后台Service:onCreate,onStart,onBind等生命周期在200s内没有处理完成发生ANR

logcat日志关键字:Timeout executing service

4.ContentProviderTimeout ContentProvider 在10S内没有处理完成发生ANR。

logcat日志关键字:timeout publishing content providers

三:anr 触发机制

ANR是一套监控Android应用响应是否及时的机制,可以把发生ANR比作是引爆炸弹,那么整个流程包含三部分组成:
1. 启动定时炸弹:中控系统(system_server进程)启动倒计时,在规定时间内如果目标(应用进程)没有干完所有的活,则中控系统会定向炸毁(杀进程)目标。
2. 拆炸弹:在规定的时间内干完工地的所有活,并及时向中控系统报告完成,请求解除定时炸弹,则幸免于难。
3. 引爆炸弹:中控系统立即封装现场,抓取快照,搜集目标执行慢的罪证(traces),便于后续的案件侦破(调试分析),最后是炸毁目标。
举例:用户点击按钮,中控系统启动定时炸弹; 点击按钮后,执行的事务,在规定的5s内完成了,则解除了定时炸弹;如果点击按钮,发现点击按钮做的事务在执行了5s,后还没有结束,然后又有别的输入事件,这个时候,就会引爆炸弹。

service超时机制

1. 客户端(App进程)向中控系统(system_server进程)发起启动服务的请求
2. 中控系统派出一名空闲的通信员(binder_1线程)接收该请求,紧接着向组件管家(ActivityManager线程)发送消 息,埋下定时炸弹
3. 通讯员1(binder_1)通知工地(service所在进程)的通信员准备开始干活
4. 通讯员3(binder_3)收到任务后转交给包工头(main主线程),加入包工头的任务队列(MessageQueue)
5. 包工头经过一番努力干完活(完成service启动的生命周期),然后等待SharedPreferences(简称SP)的持久化;
6. 包工头在SP执行完成后,立刻向中控系统汇报工作已完成
7. 中控系统的通讯员2(binder_2)收到包工头的完工汇报后,立刻去拆除炸弹。如果在炸弹定时结束前拆除炸弹 则拆除炸弹,否则会引发爆炸(触发ANR)

broadcast超时机制

对于静态注册的广播在超时检测过程需要检测SP,如下图所示
1. 客户端(App进程)向中控系统(system_server进程)发起发送广播的请求
2. 中控系统派出一名空闲的通信员(binder_1)接收该请求转交给组件管家(ActivityManager线程)
3. 组件管家执行任务(processNextBroadcast方法)的过程埋下定时炸弹
4. 组件管家通知工地(receiver所在进程)的通信员准备开始干活
5. 通讯员3(binder_3)收到任务后转交给包工头(main主线程),加入包工头的任务队列(MessageQueue)
6. 包工头经过一番努力干完活(完成receiver启动的生命周期),发现当前进程还有SP正在执行写入文件的操作,便将向中控系统汇报的任务交给SP工人(queued-work-looper线程)
7. SP工人历经艰辛终于完成SP数据的持久化工作,便可以向中控系统汇报工作完成
8. 中控系统的通讯员2(binder_2)收到包工头的完工汇报后,立刻去拆除炸弹。如果在倒计时结束前拆除炸弹则炸弹拆除,否则会引发爆炸(触发ANR)。

SP8.0开始采用名叫“queued-work-looper”handler线程,在老版本采用newSingleThreadExecutor创 建的单线程的线程池)
如果是动态广播,或者静态广播没有正在执行持久化操作的SP任务,则不需要经过“queued-work-looper”线程中 转,而是直接向中控系统汇报,流程更为简单,如下图所示:

 provider超时机制

provider的超时是在provider进程首次启动的时候才会检测,当provider进程已启动的场景,再次请求provider并不会触发provider超时。
1. 客户端(App进程)向中控系统(system_server进程)发起获取内容提供者的请求
2. 中控系统派出一名空闲的通信员(binder_1)接收该请求,检测到内容提供者尚未启动,则先通过zygote孵化新进程
3. 新孵化的provider进程向中控系统注册自己的存在
4. 中控系统的通信员2号接收到该信息后,向组件管家(ActivityManager线程)发送消息,埋下炸弹
5. 通信员2号通知工地(provider进程)的通信员准备开始干活
6. 通讯员4(binder_4)收到任务后转交给包工头(main主线程),加入包工头的任务队列(MessageQueue)
7. 包工头经过一番努力干完活(完成provider的安装工作)后向中控系统汇报工作已完成
8. 中控系统的通讯员3(binder_3)收到包工头的完工汇报后,立刻去拆除炸弹。如果在倒计时结束前拆除炸弹则拆除炸弹,否则会引发爆炸(触发ANR).

input超时机制

input的超时检测机制跟servicebroadcastprovider截然不同,为了更好的理解input过程先来介绍两个重要线程的相关工作:
1.InputReader线程: 负责通过EventHub(监听目录/dev/input)读取输入事件,一旦监听到输入事件则放入到InputDispatcher的mInBoundQueue队列,并通知其处理该事件;
2.InputDispatcher线程: 负责将接收到的输入事件分发给目标应用窗口,分发过程使用到3个事件队列:
   a. mInBoundQueue用于记录InputReader发送过来的输入事件;
   b. outBoundQueue用于记录即将分发给目标应用窗口的输入事件;
   c. waitQueue用于记录已分发给目标应用,且应用尚未处理完成的输入事件;
input的超时机制并非时间到了一定就会爆炸,而是处理再次有上报输入事件的过程才会去检测是否该爆炸,具体如下图所示。

四:为什么会出现ANR

1:主线程频繁进行耗时的IO操作:如数据库读写

2:多线程操作的死锁,主线程被block;(搜索关键字 held by)

3:主线程被Binder 对端block;

4:System Server中WatchDog出现ANR;

5:service binder的连接达到上线无法和和System Server通信

6:系统资源已耗尽(管道、CPU、IO)

五:ANR 实例分析

主要分析:通过logcat日志或者traces文件确认anr发生时间点; CPU使用率 ;主线程状态;其他线程状态

1,看anr日志,主要了解发生anr的进程等信息

2. 看主线程(下面是一个线程死锁的例子)

 主线程执行了耗时操作

六,参数分析

main:main标识是主线程,如果是线程,那么命名成“Thread-X”的格式,x表示线程id,逐步递增。 prio:线程优先级,默认是5

tid:tid不是线程的id,是线程唯一标识ID

group:是线程组名称

sCount:该线程被挂起的次数

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

obj:对象地址

self:该线程Native的地址

sysTid:是线程号(主线程的线程号和进程号相同)

nice:是线程的调度优先级

sched:分别标志了线程的调度策略和优先级

cgrp:调度归属组

handle:线程处理函数的地址。

state:是调度状态

schedstat:从 /proc/[pid]/task/[tid]/schedstat读出,三个值分别表示线程在cpu上执行的时间、线程的等待时间和线程执行的时间片长度,不支持这项信息的三个值都是0; utm:是线程用户态下使用的时间值(单位是jiffies)

stm:是内核态下的调度时间值

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

七:分析步骤

1).收集的信息如下

前台ANR发生后,系统会马上去抓取现场的信息,用于调试分析,收集的信息如下:

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

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

b1. 当前发生ANR的进程,system_server进程以及所有persistent进程
b2. audioserver, cameraserver, mediaserver, surfaceflflinger等重要的native进程
b3. CPU使用率排名前5的进程

c. 将发生ANRreason以及CPU使用情况信息输出到main log

c1. 将traces文件和CPU使用情况信息保存到dropbox,即data/system/dropbox目录
c2. 对用户可感知的进程则弹出ANR对话框告知用户,对用户不可感知的进程发生ANR则直接杀掉

2). 分析步骤

1. 定位发生ANR时间点
2. 查看trace信息
3. 分析是否有耗时的message,binder调用,锁的竞争,CPU资源的抢占
4. 结合具体的业务场景的上下文来分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值