1.概念
首先,ANR(Application Not responding)是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。ANR由消息处理机制保证,Android在系统层实现了一套精密的机制来发现ANR,核心原理是消息调度和超时处理。
2.表现
当发生ANR时,会收集一些系统状态,譬如CPU/IO使用情况、进程函数调用栈,并且报告用户有进程无响应了(ANR对话框)。
发生ANR时会调用AppNotRespondingDialog.show()方法弹出对话框提示用户,该对话框的依次调用关系如下图所示:
AppErrors.appNotResponding(),该方法是最终弹出ANR对话框的唯一入口,调用该方法的场景才会有ANR提示,也可以认为在主线程中执行无论再耗时的任务,只要最终不调用该方法,都不会有ANR提示,也不会有ANR相关日志及报告;通过调用关系可以看出哪些场景会导致ANR,有以下四种场景:
(1)Service Timeout:Service在特定的时间内无法处理完成
(2)BroadcastQueue Timeout:BroadcastReceiver在特定时间内无法处理完成
(3)ContentProvider Timeout:内容提供者执行超时
(4)inputDispatching Timeout: 按键或触摸事件在特定时间内无响应。
ANR机制
ANR机制可以分为两部分:
ANR监测机制:Android对于不同的ANR类型(Broadcast, Service, InputEvent)都有一套监测机制。
ANR报告机制:在监测到ANR以后,需要显示ANR对话框、输出日志(发生ANR时的进程函数调用栈、CPU使用情况等)。
举例Service超时监测机制
Service运行在应用程序的主线程,如果Service的执行时间超过20秒,则会引发ANR。
当发生Service ANR时,一般可以先排查一下在Service的生命周期函数中(onCreate(), onStartCommand()等)有没有做耗时的操作,譬如复杂的运算、IO操作等。 如果应用程序的代码逻辑查不出问题,就需要深入检查当前系统的状态:CPU的使用情况、系统服务的状态等,判断当时发生ANR进程是否受到系统运行异常的影响。
如何检测Service超时呢?Android是通过设置定时消息实现的。
Service超时监测机制可以从Service启动流程中找到。
(1)ActiveServices.realStartServiceLocked()主要工作有
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
// 主要是为了设置ANR超时,可以看出在正式启动Service之前开始ANR监测;
bumpServiceExecutingLocked(r, execInFg, "create");
// 启动过程调用scheduleCreateService方法,最终会调用Service.onCreate方法;
app.thread.scheduleCreateService(r, r.serviceInfo,
// 绑定过程中,这个方法中会调用app.thread.scheduleBindService方法
requestServiceBindingsLocked(r, execInFg);
// 调动Service的其他方法,如onStartCommand,也是IPC通讯
sendServiceArgsLocked(r, execInFg, true);
}
2)bumpServiceExecutingLocked()会调scheduleServiceTimeoutLocked()方法
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
// 在serviceDoneExecutingLocked中会remove该SERVICE_TIMEOUT_MSG消息,