学到的:
1. anr是什么
2. anr的时候会dump出一个log
3. log的结构,有哪几个部分组成
4. broadcastReceiver的onReceive方法的执行线程
5. 清晰理解bug报告(将bug重现一次)
[all;100%;yijun.xu]–[共同cell_REV01]–BT carkit
Pre: insert GSM card
,inport 2000 contacts and some MP3
Occur Process: connect Santa Fe Sport state/KIA MOTORS–>contact–>share namecard via
–>multiple contacts–>select all–>done–>Bluetooth–>Santa Fe Sport
–>it will receive a alert:BT send fail–>retry
Occur status: test phone lock up,and then screen become black,after a while,pop up ANR
理解问题
- 注意几个名词的意思:
Santa Fe Sport state/KIA MOTORS //两款车载蓝牙设备
it will receive a alert:BT send fail–>retry //出现失败通知,点击重试
ANR //程序没有相应 -
重新描述问题:
对某个车载蓝牙设备共享2000个联系人时,显示失败后,点击重试。然后手机没有响应,黑屏,过一会后显示ANR。
分析问题
-
查阅资料和经验得知,ANR出现一般是由于:
- 没有响应用户输入5s以上
- broadcast没有10s内处理完毕
bug描述中强调2000个联系人,猜测是由于耗时操作处理不当引起的anr。
根据个人经验,程序无法响应一般是由于主线程堵塞引起的,或者是线程的运行时间超过了某个上限。
-
阅读log:
打开dumpstate_app_anr-2014-05-20-14-47-00.txt, 搜索“anr”,有以下结果:
…
05-20 14:46:08.327 3312 3312 D CrashAnrDetector: Subject: Broadcast of Intent { act=android.bluetooth.devicepicker.action.DEVICE_SELECTED flg=0x10 cmp=com.android.bluetooth/.opp.BluetoothOppReceiver (has extras) }
…可得知anr的类型是“Broadcast timeout”。查阅代码得知DEVICE_SELECTED由BluetoothOppReceiver注册,查阅BluetoothOppReceiver代码后,没有发现涉及耗时操作的语句。
又由于BluetoothOppReceiver是在xml中声明的,所以它的onReceive会在主线程中运行。所以推断timeout的原因是由于主线程堵塞。于是查看一下当时系统的各个进程和线程的调用栈的情况。
打开dumpstate_app_anr-2014-05-20-14-47-00.txt,搜索“main”,有以下结果:"main" prio=5 tid=1 NATIVE | group="main" sCount=1 dsCount=0 obj=0x41720d08 self=0x41624680 | sysTid=32302 nice=0 sched=0/0 cgrp=apps handle=1073828180 | state=S schedstat=( 0 0 0 ) utm=73 stm=36 core=0 ... at android.os.BinderProxy.transact(Native Method) at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:680) at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1067) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:907) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:834) at com.android.bluetooth.opp.BluetoothOppSendFileInfo.generateFileInfo(BluetoothOppSendFileInfo.java:211) at com.android.bluetooth.opp.BluetoothOppManager.saveSendingFileInfo(BluetoothOppManager.java:262) at com.android.bluetooth.opp.BluetoothOppUtility.retryTransfer(BluetoothOppUtility.java:434) at com.android.bluetooth.opp.BluetoothOppTransferActivity.onClick(BluetoothOppTransferActivity.java:445) ...
得知当ANR发生时,主线程正在运行数据库相关操作:generateFileInfo。因此猜测ANR的出现是由于该函数在主线程上运行太久所导致的。
但是经过询问,该bug的出现需要多次重复Occur Process,说明generateFileInfo的运行时间不确定。
代码分析
继续进行分析,generateFileInfo中涉及ContentResolver的query操作。查阅资料得知,ContentProvider是线程安全的,但是某一时刻只能处理一种操作。于是推断是由于竞争ContentProvider的使用权导致generateFileInfo的运行时间不确定。
在前一次传输失败后,BluetoothOppTransfer会调用markBatchFailed方法,其中涉及ContentProvider的update方法。
于是推断bug是由于generateFileInfo和markBatchFailed竞争ContentProvider的使用权导致ANR。
但未能在log中找到上述推断的明显证据。
方案
bug是由于主线程堵塞引起的,所以将耗时操作放在新的线程上运行即可。
故将com.android.bluetooth.opp.BluetoothOppUtility.retryTransfer方法中的:
BluetoothOppUtility.retryTransfer(this, mTransInfo);
改成:
Thread t = new Thread(new Runnable() {
public void run() {
// retry the failed transfer
BluetoothOppUtility.retryTransfer(this, mTransInfo);
}
});
t.start();
- 总结
- 没有仔细研究bug报告导致误解retry一词。
- 经验不足,对anr不熟悉,不止从何下手。
- 阅读和分析log的技能很不足,很多信息一开始的时候没有挖掘出来,例如查看线程的调用栈、anr的log文件等等。