您的位置:首页 > 移动开发 > Android开发

android ANR源码分析 --- 之四

2017-10-31 20:21 751 查看

5,小结

Timeout时长

对于前台服务,则超时为SERVICE_TIMEOUT = 20s;

对于后台服务,则超时为SERVICE_BACKGROUND_TIMEOUT = 200s

对于前台广播,则超时为BROADCAST_FG_TIMEOUT = 10s;

对于后台广播,则超时为BROADCAST_BG_TIMEOUT = 60s;

ContentProvider超时为CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s;

按键事件为5s;

超时检测

Service超时检测机制:

超过一定时间没有执行完相应操作来触发移除延时消息,则会触发anr;

BroadcastReceiver超时检测机制:

有序广播的总执行时间超过 2* receiver个数 * timeout时长,则会触发anr;

有序广播的某一个receiver执行过程超过 timeout时长,则会触发anr;

另外:

对于Service, Broadcast, Input发生ANR之后,最终都会调用AMS.appNotResponding;

对于provider,在其进程启动时publish过程可能会出现ANR, 则会直接杀进程以及清理相应信息,而不会弹出ANR的对话框.

 appNotRespondingViaProvider()过程会走appNotResponding(), 这个就不介绍了,很少使用,由用户自定义超时时间.

 

6,ANR处理

以下场景都会触发调用AMS.appNotResponding方法:

1,ServiceTimeout:比如前台服务在20s内未执行完成;

2,BroadcastQueueTimeout:比如前台广播在10s内未执行完成

3,InputDispatchingTimeout: 输入事件分发超时5s,包括按键和触摸事件。

 

AMS的appNotResponding方法主要逻辑如下,

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

updateCpuStatsNow(); //第一次 更新cpu统计信息
synchronized (this) {
//PowerManager.reboot() 会阻塞很长时间,因此忽略关机时的ANR
if (mShuttingDown) {
return;
} else if (app.notResponding) {
return;
} else if (app.crashing) {
return;
}
//记录ANR到EventLog
EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid, app.processName, app.info.flags, annotation);
•••

2,收集并输出重要进程列表中的各个线程的traces信息,该方法较耗时;

//创建CPU tracker对象
final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
//输出traces信息
File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST);

3, 输出当前各个进程的CPU使用情况以及CPU负载情况;

updateCpuStatsNow(); //第二次更新cpu统计信息
//记录当前各个进程的CPU使用情况
synchronized (mProcessCpuTracker) {
cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
}
//记录当前CPU负载情况
info.append(processCpuTracker.printCurrentLoad());
info.append(cpuInfo);
//记录从anr时间开始的Cpu使用情况
info.append(processCpuTracker.printCurrentState(anrTime));
//输出当前ANR的reason,以及CPU使用率、负载信息
Slog.e(TAG, info.toString());

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

//将traces文件 和 CPU使用率信息保存到dropbox,即data/system/dropbox目录
addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);

5, 根据进程类型,来决定直接后台杀掉,还是弹框告知用户.

synchronized (this) {
...
//后台ANR的情况, 则直接杀掉
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
app.kill("bg anr", true);
return;
}
•••
//弹出ANR对话框
Message msg = Message.obtain();
HashMap<String, Object> map = new HashMap<String, Object>();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
}
//向ui线程发送,内容为SHOW_NOT_RESPONDING_MSG的消息
mUiHandler.sendMessage(msg);
}

可以看出,最后终于向ui线程发送内容为SHOW_NOT_RESPONDING_MSG的消息。

这样就是发生ANR时的弹出框。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ANR 源码分析