android中有3种crash情况:未捕获的异常、ANR和闪退。未捕获的异常一般用crash文件就可以记录异常信息,而ANR无响应表现就是界面卡着无法响应用户操作,而闪退则是整个app瞬间退出,个人感觉对用户造成的体验最差。闪退一般是由于调用so库出错导致,像类似非法地址访问等。
闪退发生时在logcat中将日志过滤条件选为“No Filters”就可以看到完整的闪退日志,或者叫tombstone(墓碑)文件。
tombstone(墓碑)是当系统 crash 的时候,会保存一个 tombstone 文件到/data/tombstones目录下(Logcat中也会有相应的信息),文件就像墓碑一样记录了死亡了的进程的基本信息(例如进程的进程 号,线程号),死亡的地址(在哪个地址上发生了 Crash),死亡时的现场是什么样的(记录了一系列的堆栈调用信息)等等。
闪退(tombstone)主要日志如下,中间太长部分用省略号省略。
--------- beginning of crash
2020-01-19 15:22:07.194 14414-14414/com.android.dj.crash.test A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xfffffffd in tid 14414 (dj.crashtest), pid 14414 (dj.crashtest)
2020-01-19 15:22:07.249 14414-18253/com.android.dj.crash.test V/IOTCAPIS: [io_recv_proc][297]:
2020-01-19 15:22:07.249 14414-18253/com.android.dj.crash.test V/IOTCAPIS: get remote packet ICE_SES_MSG_HIT
2020-01-19 15:22:07.303 18260-18260/? I/crash_dump32: obtaining output fd from tombstoned, type: kDebuggerdTombstone
2020-01-19 15:22:07.309 883-883/? I//system/bin/tombstoned: received crash request for pid 14414
2020-01-19 15:22:07.311 18260-18260/? I/crash_dump32: performing dump of process 14414 (target tid = 14414)
2020-01-19 15:22:07.313 1313-1416/system_process W/ActivityTaskManager: Activity pause timeout for ActivityRecord{567b991 u0 com.android.dj.crash.test/com.android.dj.crash.view.CrashTestActivity t2302 f}
···
2020-01-19 15:22:07.330 18260-18260/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2020-01-19 15:22:07.330 18260-18260/? A/DEBUG: Build fingerprint: 'HUAWEI/VOG-AL00/HWVOG:10/HUAWEIVOG-AL00/10.0.0.185C00:user/release-keys'
2020-01-19 15:22:07.330 18260-18260/? A/DEBUG: Revision: '0'
2020-01-19 15:22:07.330 18260-18260/? A/DEBUG: ABI: 'arm'
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: SYSVMTYPE: Maple
APPVMTYPE: Art
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: Timestamp: 2020-01-19 15:22:07+0800
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: pid: 14414, tid: 14414, name: dj.crashtest >>> com.android.dj.crash.test <<<
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: uid: 10218
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xfffffffd
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: r0 fffffffd r1 ff99f161 r2 80000000 r3 00660e9d
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: r4 ffffffff r5 b9f33000 r6 867cb252 r7 ff99f108
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: r8 00000000 r9 eb283e00 r10 ff99f7a0 r11 eb283e00
2020-01-19 15:22:07.331 18260-18260/? A/DEBUG: ip 20000000 sp ff99f0c8 lr 00000002 pc e9097000
2020-01-19 15:22:07.419 2378-10947/? D/HwRecentsTaskUtils: refreshToCache
2020-01-19 15:22:07.419 2378-10947/? D/HwRecentsTaskUtils: searchFromDate
2020-01-19 15:22:07.427 2302-10215/? E/HsmCoreServiceImpl: onTransact in code is: 103
2020-01-19 15:22:07.427 2302-10215/? I/MediaProcessHandler: playingUids:
···
2020-01-19 15:22:07.581 14414-18186/com.android.dj.crash.test I/IPCSDK: 1
2020-01-19 15:22:07.582 14414-18186/com.android.dj.crash.test V/IOTCAPIS: [p2p_global_thread][94]:
2020-01-19 15:22:07.582 14414-18186/com.android.dj.crash.test V/IOTCAPIS: p2p_global_thread GLOBAL_EVENT_MSG_CB_EVENT_SESSION_CONNECT_SUCCESS_P2P end
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: backtrace:
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #00 pc 0004f000 /apex/com.android.runtime/lib/bionic/libc.so (__memcpy_a15+200) (BuildId: f2470da1a22265f8104ce6bb9bcaf63e)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #01 pc 00023d6f /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (LoopBuffWrite+138) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #02 pc 00031f75 /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (CP2PSessionData::p2p_session_data_write(char*, int, unsigned char)+264) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #03 pc 0002a561 /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (IOTC_Session_WriteData+66) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
···
2020-01-19 15:22:07.693 18260-18260/? A/DEBUG: #134 pc 0000202f /system/bin/app_process32 (_start_main+38) (BuildId: 9979c215af59ed821fac6ea4f956225d)
2020-01-19 15:22:07.693 18260-18260/? A/DEBUG: #135 pc 00004456
可以看到
tombstone文件如何分析
主要看backtrace下面的函数调用,backtrace下的函数调用是从下往上的顺序执行的,所以在最上面的函数是最后执行的。
最后几行的函数调用如下:
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: backtrace:
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #00 pc 0004f000 /apex/com.android.runtime/lib/bionic/libc.so (__memcpy_a15+200) (BuildId: f2470da1a22265f8104ce6bb9bcaf63e)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #01 pc 00023d6f /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (LoopBuffWrite+138) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #02 pc 00031f75 /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (CP2PSessionData::p2p_session_data_write(char*, int, unsigned char)+264) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
2020-01-19 15:22:07.691 18260-18260/? A/DEBUG: #03 pc 0002a561 /data/app/com.android.dj.crash.test-dA-LA_OmHFay2acWJnDeJA==/lib/arm/libipcsdk.so (IOTC_Session_WriteData+66) (BuildId: cf6a63bc513797ba7582c510f377f11c44a12970)
我们需要记住最后几个函数调用的地址00023d6f、00031f75、0002a561,后面用到的工具分析以及反汇编后的文件分析都会用到这几个偏移地址。
分析工具
android的ndk中提供了多个工具可以进行so库导致的crash的分析。
1)addr2line
addr2line 是 用来获得指定动态链接库文件或者可执行文件中指定地址对应的源代码信息的工具
D:\DJ_Software\Android\Ndk_Download\android-ndk-r10e-windows-x86_64\android-ndk-r10e\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin>arm-linux-androideabi-addr2line -f -e D:\flash_anr_pc\libipcsdk.so 00023d6f
LoopBuffWrite
??:?
D:\DJ_Software\Android\Ndk_Download\android-ndk-r10e-windows-x86_64\android-ndk-r10e\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin>arm-linux-androideabi-addr2line -f -e D:\flash_anr_pc\libipcsdk.so 00031f75
_ZN15CP2PSessionData22p2p_session_data_writeEPcih
??:?
addr2line 命令及执行结果如上所示,-e参数指定文件名,-f参数显示函数名。只是得到了函数入口,详细运行信息没有。再使用objdump工具看下。
2)objdump
objdump可以将so库进行反汇编,反汇编后得到重定向文件,然后根据偏移地址得到更详细的函数调用上下文信息。
我实际使用ndk 20版本发现addr2line 运行可以,objdump总有一些错误,所以最后使用ndk 10命令执行成功。
D:\DJ_Software\Android\Ndk_Download\android-ndk-r10e-windows-x86_64\android-ndk-r10e\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin>objdump -S -D D:\flash_anr_pc\libipcsdk.so > D:\flash_anr_pc\deassmble_libipc.log
命令执行结果就是将反汇编后的结果写入到D盘对应目录的deassmble_libipc.log文件里。
反汇编后结果分析
仍是重点分析前面提到的那3个函数。实际发现反汇编后不知为何得到的函数偏移地址总是比crash日志中的偏移地址小1。
IOTC_Session_WriteData函数
打开deassmble_libipc.log文件,搜索偏移地址“2a560”。
0002a51e :
2a51e: b5b0 push {r4, r5, r7, lr}
2a520: af02 add r7, sp, #8
2a522: b08a sub sp, #40 ; 0x28
2a524: 469c mov ip, r3
2a526: 4696 mov lr, r2
2a528: 460c mov r4, r1
···
2a560: f7ea ef62 blx 15428 <_ZN15CP2PSessionData22p2p_session_data_writeEPcih@plt>
2a564: 9009 str r0, [sp, #36] ; 0x24
2a566: e7ff b.n 2a568
2a568: 9809 ldr r0, [sp, #36] ; 0x24
2a56a: b00a add sp, #40 ; 0x28
2a56c: bdb0 pop {r4, r5, r7, pc}
可以看到IOTC_Session_WriteData函数在2a560行(crash日志中是0002a561)调用了p2p_session_data_write函数,p2p_session_data_write函数是C++类中的成员函数,所以在汇编中的函数名与纯C函数的函数名有所区别。
p2p_session_data_write函数
00031e6c <_ZN15CP2PSessionData22p2p_session_data_writeEPcih>:
31e6c: b5f0 push {r4, r5, r6, r7, lr}
31e6e: af03 add r7, sp, #12
31e70: f84d bd04 str.w fp, [sp, #-4]!
31e74: b098 sub sp, #96 ; 0x60
31e76: 469c mov ip, r3
31e78: 4696 mov lr, r2
···
31f66: d923 bls.n 31fb0 <_ZN15CP2PSessionData22p2p_session_data_writeEPcih+0x144>
31f68: e7ff b.n 31f6a <_ZN15CP2PSessionData22p2p_session_data_writeEPcih+0xfe>
31f6a: 9808 ldr r0, [sp, #32]
31f6c: f500 7067 add.w r0, r0, #924 ; 0x39c
31f70: a914 add r1, sp, #80 ; 0x50
31f72: 2209 movs r2, #9
31f74: f7e2 ea0c blx 14390
31f78: 9910 ldr r1, [sp, #64] ; 0x40
31f7a: 2901 cmp r1, #1
31f7c: 9005 str r0, [sp, #20]
31f7e: db09 blt.n 31f94 <_ZN15CP2PSessionData22p2p_session_data_writeEPcih+0x128>
可以看到实际的LoopBuffWrite函数调用在31f74行(crash日志中的00031f75)。
LoopBuffWrite函数
00023ce4 :
23ce4: b5d0 push {r4, r6, r7, lr}
23ce6: af02 add r7, sp, #8
23ce8: b08c sub sp, #48 ; 0x30
23cea: 4613 mov r3, r2
23cec: 468c mov ip, r1
23cee: 4686 mov lr, r0
···
23d64: 3a01 subs r2, #1
23d66: 4010 ands r0, r2
23d68: 4408 add r0, r1
23d6a: 990a ldr r1, [sp, #40] ; 0x28
23d6c: 9a08 ldr r2, [sp, #32]
23d6e: f7f0 ecde blx 1472c <__aeabi_memcpy@plt>
23d72: 990b ldr r1, [sp, #44] ; 0x2c
23d74: 6809 ldr r1, [r1, #0]
23d76: 9a0a ldr r2, [sp, #40] ; 0x28
23d78: f8dd e020 ldr.w lr, [sp, #32]
中间部分代码省略,可以看到在23d6e行(crash日志中为00023d6f),也是差一行。LoopBuffWrite在此处执行了__aeabi_memcpy,估计是执行数据拷贝时发生了错误,再继续深入就需要对汇编语言有所了解。
最后,还有一个工具ndk-stack可以简化分析过程。使用参见
https://blog.csdn.net/u010144805/article/details/80763956