bug练习1 车载蓝牙设备共享2000个联系人

学到的:
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

antibiotika-online.com

,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

理解问题

  1. 注意几个名词的意思:
    Santa Fe Sport state/KIA MOTORS //两款车载蓝牙设备
    it will receive a alert:BT send fail–>retry //出现失败通知,点击重试
    ANR //程序没有相应

  2. 重新描述问题:
    对某个车载蓝牙设备共享2000个联系人时,显示失败后,点击重试。然后手机没有响应,黑屏,过一会后显示ANR。

分析问题

  1. 查阅资料和经验得知,ANR出现一般是由于:

    • 没有响应用户输入5s以上
    • broadcast没有10s内处理完毕

    bug描述中强调2000个联系人,猜测是由于耗时操作处理不当引起的anr。

    根据个人经验,程序无法响应一般是由于主线程堵塞引起的,或者是线程的运行时间超过了某个上限。

  2. 阅读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();
  1. 总结
    • 没有仔细研究bug报告导致误解retry一词。
    • 经验不足,对anr不熟悉,不止从何下手。
    • 阅读和分析log的技能很不足,很多信息一开始的时候没有挖掘出来,例如查看线程的调用栈、anr的log文件等等。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据