traces文件
android出现anr后会在手机中生成如下文件/data/anr/traces.txt。
利用adb pull取出后,就可以分析啦。
addr2line
addr2line是用来解析符号表的工具,是个python3的脚本,可以根据自己的需求修改。命令如下:python3 addr2line.py -dump traces.txt -sym 源码/out/target/product/xxx/symbols/ -cpp -force 然后可以重定向新的文件方便查看。
例子
场景
手机otg连接u盘,里面有很多音频/视频/图片,然后用文件管理器查看,加载的过程中,拔掉otg线,手机卡顿,然后systemUI出现anr
log文件
05-25 15:42:56.936 2654 2719 E ActivityManager: ANR in com.android.systemui
05-25 15:42:56.936 2654 2719 E ActivityManager: PID: 3111
05-25 15:42:56.936 2654 2719 E ActivityManager: Reason: Broadcast of Intent
{ act=android.intent.action.TIME_TICK flg=0x50000014 (has extras) }
05-25 15:42:56.936 2654 2719 E ActivityManager: Load: 13.84 / 9.53 / 7.99
05-25 15:42:56.936 2654 2719 E ActivityManager: CPU usage from 0ms to 29604ms later (2017-05-25 15:42:27.293 to 2017-05-25 15:42:56.896):
05-25 15:42:56.936 2654 2719 E ActivityManager: 94% 25870/sdcard: 5.3% user + 88% kernel / faults: 8 minor
05-25 15:42:56.936 2654 2719 E ActivityManager: 11% 25375/kworker/u8:0: 0% user + 11% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 7.9% 25397/kworker/u8:4: 0% user + 7.9% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 7.6% 25885/kworker/u8:5: 0% user + 7.6% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 7.3% 2654/system_server: 4.4% user + 2.9% kernel / faults: 2445 minor 37 major
05-25 15:42:56.936 2654 2719 E ActivityManager: 6.3% 20769/kworker/u8:8: 0% user + 6.3% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 3.2% 23494/com.cloudminds.filemanager: 1.6% user + 1.5% kernel / faults: 1995 minor
05-25 15:42:56.936 2654 2719 E ActivityManager: 2.7% 24528/com.baidu.searchbox: 1.9% user + 0.7% kernel / faults: 757 minor 42 major
05-25 15:42:56.936 2654 2719 E ActivityManager: 1.9% 390/irq/431-fsc_int: 0% user + 1.9% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 1.5% 8/rcu_sched: 0% user + 1.5% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 1.5% 7/rcu_preempt: 0% user + 1.5% kernel
05-25 15:42:56.936 2654 2719 E ActivityManager: 1% 4149/com.android.phone: 0.4% user + 0.6% kernel / faults: 1469 minor 14 major
05-25 15:42:56.936 2654 2719 E ActivityManager: 0.8% 11/migration/1: 0% user + 0.8% kernel
发现sdcard中的kernel调用占用大量cpu导致systemUI出现anr。
trace文件
25870/sdcard: 5.3% user + 88% kernel
直接查看trace文件中的pid是25870的sdard相关内容
----- pid 25870 at 2017-05-25 15:42:53 -----
Cmd line: /system/bin/sdcard
ABI: 'arm64'
"sdcard" sysTid=25870
#00 pc 000000000006b4f0 /system/lib64/libc.so (read+4)
#01 pc 000000000000290c /system/bin/sdcard
#02 pc 000000000001a7d8 /system/lib64/libc.so (__libc_init+88)
#03 pc 0000000000001ca0 /system/bin/sdcard
"sdcard" sysTid=25871
#00 pc 000000000006aa44 /system/lib64/libc.so (__getdents64+8)
#01 pc 000000000001e36c /system/lib64/libc.so (readdir+100)
#02 pc 0000000000004d80 /system/bin/sdcard
#03 pc 00000000000037f8 /system/bin/sdcard
#04 pc 0000000000068618 /system/lib64/libc.so (_ZL15__pthread_startPv+196)
#05 pc 000000000001df68 /system/lib64/libc.so (__start_thread+16)
"sdcard" sysTid=25872
#00 pc 000000000006b4f0 /system/lib64/libc.so (read+4)
#01 pc 0000000000002fd8 /system/bin/sdcard
#02 pc 0000000000068618 /system/lib64/libc.so (_ZL15__pthread_startPv+196)
#03 pc 000000000001df68 /system/lib64/libc.so (__start_thread+16)
"sdcard" sysTid=25873
#00 pc 000000000006b4f0 /system/lib64/libc.so (read+4)
#01 pc 0000000000002fd8 /system/bin/sdcard
#02 pc 0000000000068618 /system/lib64/libc.so (_ZL15__pthread_startPv+196)
#03 pc 000000000001df68 /system/lib64/libc.so (__start_thread+16)
----- end 25870 -----
发现都是libc和sdcard的相关堆栈,不知道是具体哪个函数,所以要用addr2line通过符号表解析出来。
addr2line解析结果
用最开始的例子的命令格式解析后,找到sdcard相关内容如下
"sdcard" sysTid=25870
#00 pc 000000000006b4f0 /system/lib64/libc.so read 于 read.S:7
#01 pc 000000000000290c /system/bin/sdcard read 于 unistd.h:465
(已内连入) watch_package_list 于 sdcard.c:1944
(已内连入) run 于 sdcard.c:2123
(已内连入) main 于 sdcard.c:2325
#02 pc 000000000001a7d8 /system/lib64/libc.so __libc_init 于 libc_init_dynamic.cpp:119
#03 pc 0000000000001ca0 /system/bin/sdcard do_arm64_start 于 sdcard.c:?
"sdcard" sysTid=25871
#00 pc 000000000006aa44 /system/lib64/libc.so __getdents64 于 __getdents64.S:9
#01 pc 000000000001e36c /system/lib64/libc.so __fill_DIR(DIR*) 于 dirent.cpp:96 (discriminator 1)
(已内连入) __readdir_locked(DIR*) 于 dirent.cpp:106 (discriminator 1)
(已内连入) readdir 于 dirent.cpp:121 (discriminator 1)
#02 pc 0000000000004d80 /system/bin/sdcard find_file_within 于 sdcard.c:391
#03 pc 00000000000037f8 /system/bin/sdcard handle_lookup 于 sdcard.c:811 (discriminator 1)
(已内连入) handle_fuse_request 于 sdcard.c:1703 (discriminator 1)
(已内连入) handle_fuse_requests 于 sdcard.c:1854 (discriminator 1)
(已内连入) start_handler 于 sdcard.c:1871 (discriminator 1)
#04 pc 0000000000068618 /system/lib64/libc.so __pthread_start(void*) 于 pthread_create.cpp:198 (discriminator 1)
#05 pc 000000000001df68 /system/lib64/libc.so __start_thread 于 clone.cpp:41 (discriminator 1)
"sdcard" sysTid=25872
#00 pc 000000000006b4f0 /system/lib64/libc.so read 于 read.S:7
#01 pc 0000000000002fd8 /system/bin/sdcard read 于 unistd.h:465
(已内连入) handle_fuse_requests 于 sdcard.c:1828
(已内连入) start_handler 于 sdcard.c:1871
#02 pc 0000000000068618 /system/lib64/libc.so __pthread_start(void*) 于 pthread_create.cpp:198 (discriminator 1)
#03 pc 000000000001df68 /system/lib64/libc.so __start_thread 于 clone.cpp:41 (discriminator 1)
"sdcard" sysTid=25873
#00 pc 000000000006b4f0 /system/lib64/libc.so read 于 read.S:7
#01 pc 0000000000002fd8 /system/bin/sdcard read 于 unistd.h:465
(已内连入) handle_fuse_requests 于 sdcard.c:1828
(已内连入) start_handler 于 sdcard.c:1871
#02 pc 0000000000068618 /system/lib64/libc.so __pthread_start(void*) 于 pthread_create.cpp:198 (discriminator 1)
#03 pc 000000000001df68 /system/lib64/libc.so __start_thread 于 clone.cpp:41 (discriminator 1)
----- end 25870 -----
查看sdcard源码
路径system/core/sdcard/sdcard.c
对应于解析后的文件,找到find_file_within的函数
while ((entry = readdir(dir))) {
if (!strcasecmp(entry->d_name, name)) {
/* we have a match - replace the name, don't need to copy the null again */
memcpy(actual, entry->d_name, namelen);
break;
}
}
closedir(dir);
发现最后是在readdir文件中,这个需要看kernel中的情况啦。
分析kernel文件
后面就是根据这个trace文件继续看代码啦,和sdcard的情况类似,这里就不详说啦。
后记
本文就是记录利用addr2line分析anr的一种思路。 anr的出现有各种情况,基本上要case by case的看。但是思路都差不多,就是利用android log和trace文件结合着看。如果是必现的情况则也可以通过增加log复现然后解决问题,如果是偶现的则只能通过log和代码的蛛丝马迹来推测啦。