不论从事安卓应用开发,还是安卓系统研发,应该都遇到应用无响应(ANR,Application Not Responding)问题,当应用程序一段时间无法及时响应,则会弹出ANR对话框,让用户选择继续等待,还是强制关闭。
绝大多数人对ANR的了解仅停留在主线程耗时或CPU繁忙会导致ANR。面试过无数的候选人,几乎没有人能真正从系统级去梳理清晰ANR的来龙去脉,比如有哪些路径会引发ANR? 有没有可能主线程不耗时也出现ANR?如何更好的调试ANR?
如果没有深入研究过Android Framework的源代码,是难以形成对ANR有一个全面、正确的理解。研究系统源码以及工作实践后提炼而来,以图文并茂的方式跟大家讲解,相信定能帮忙大家加深对ANR的理解。
一、ANR触发机制
对于知识学习的过程,要知其然知其所以然,才能做到庖丁解牛般游刃有余。要深入理解ANR,就需要从根上去找寻答案,那就是ANR是如何触发的?
ANR是一套监控Android应用响应是否及时的机制,可以把发生ANR比作是引爆炸弹,那么整个流程包含三部分组成:
- 埋定时炸弹:中控系统(system_server进程)启动倒计时,在规定时间内如果目标(应用进程)没有干完所有的活,则中控系统会定向炸毁(杀进程)目标。
- 拆炸弹:在规定的时间内干完工地的所有活,并及时向中控系统报告完成,请求解除定时炸弹,则幸免于难。
- 引爆炸弹:中控系统立即封装现场,抓取快照,搜集目标执行慢的罪证(traces),便于后续的案件侦破(调试分析),最后是炸毁目标。
常见的ANR有service、broadcast、provider以及input,更多细节详见理解Android ANR的触发原理,深度解析Android ANR触发原理-CSDN博客,接下来本文以图文形式分别讲解。
service超时机制
下面来看看埋炸弹与拆炸弹在整个服务启动(startService)过程所处的环节。
图解1:
- 客户端(App进程)向中控系统(system_server进程)发起启动服务的请求
- 中控系统派出一名空闲的通信员(binder_1线程)接收该请求,紧接着向组件管家(ActivityManager线程)发送消息,埋下定时炸弹
- 通讯员1号(binder_1)通知工地(service所在进程)的通信员准备开始干活
- 通讯员3号(binder_3)收到任务后转交给包工头(main主线程),加入包工头的任务队列(MessageQueue)
- 包工头经过一番努力干完活(完成service启动的生命周期),然后等待SharedPreferences(简称SP)的持久化;
- 包工头在SP执行完成后,立刻向中控系统汇报工作已完成
- 中控系统的通讯员2号(binder_2)收到包工头的完工汇报后,立刻拆除炸弹。如果在炸弹倒计时结束前拆除炸弹则相安无事,否则会引发爆炸(触发ANR)
更多细节详见startService启动过程分析,http://gityuan.com/2016/03/06/start-service
broadcast超时机制
broadcast跟service超时机制大抵相同,对于静态注册的广播在超时检测过程需要检测SP,如下图所示。
图解2:
- 客户端(App进程)向中控系统(system_server进程)发起发送广播的请求
- 中控系统派出一名空闲的通信员(binder_1)接收该请求转交给组件管家(ActivityManager线程)
- 组件管家执行任务(processNextBroadcast方法)的过程埋下定时炸弹
- 组件管家通知工地(receiver所在进程)的通信员准备开始干活
- 通讯员3号(binder_3)收到任务后转交给包工头(main主线程),加入包工头的