背景:
有学员朋友近来有问到一些安卓系统开发过程中的一些核心小技能小技巧等,比如native crash在企业里面该如何准确定位具体代码函数,程序卡住,或者长时间没反应,想要看看卡在代码的哪里。针对以上的一些问题,我这边分享一些工作中常用积极该类问题的一些辅助工具命令技巧,帮助大家更好的在工作中定位这类问题。
Native Crash堆栈分析工具实战
先看看常见native日志中可以获取的堆栈情况
09-24 16:34:53.233 6918 6918 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-24 16:34:53.233 6918 6918 F DEBUG : LineageOS Version: '21.0-20240413-UNOFFICIAL-nx563j'
09-24 16:34:53.233 6918 6918 F DEBUG : Build fingerprint: 'nubia/NX563J/NX563J:7.1.1/NMF26X/eng.nubia.20171019.101529:user/release-keys'
09-24 16:34:53.233 6918 6918 F DEBUG : Revision: '0'
09-24 16:34:53.233 6918 6918 F DEBUG : ABI: 'arm64'
09-24 16:34:53.233 6918 6918 F DEBUG : Timestamp: 2024-09-24 16:34:53.213262674+0800
09-24 16:34:53.233 6918 6918 F DEBUG : Process uptime: 3s
09-24 16:34:53.233 6918 6918 F DEBUG : Cmdline: robert -rec:/data/event
09-24 16:34:53.234 6918 6918 F DEBUG : pid: 6914, tid: 6914, name: robert >>> robert <<<
09-24 16:34:53.234 6918 6918 F DEBUG : uid: 0
09-24 16:34:53.234 6918 6918 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
09-24 16:34:53.234 6918 6918 F DEBUG : Cause: null pointer dereference
09-24 16:34:53.234 6918 6918 F DEBUG : x0 0000006404f5c28c x1 0000006404f5cd12 x2 0000000000000000 x3 0045565f00000000
09-24 16:34:53.234 6918 6918 F DEBUG : x4 0000008000000000 x5 0000000000000000 x6 0000000080000000 x7 454b005342415f57
09-24 16:34:53.234 6918 6918 F DEBUG : x8 4acdd30573c30611 x9 0000000000000000 x10 0000000000000001 x11 0000006404f5dde8
09-24 16:34:53.234 6918 6918 F DEBUG : x12 0000006404f5dcde x13 0000000000000000 x14 0000000000000001 x15 0000000000000000
09-24 16:34:53.234 6918 6918 F DEBUG : x16 0000006404f64c08 x17 00000077aa0ce500 x18 00000077ab97c000 x19 0000000000000009
09-24 16:34:53.234 6918 6918 F DEBUG : x20 0000006404f5baad x21 0000006404f66000 x22 00000077aae3f000 x23 0000007ff03cad80
09-24 16:34:53.234 6918 6918 F DEBUG : x24 0000007ff03cad80 x25 0000000000000000 x26 0000000000000000 x27 0000006404f66000
09-24 16:34:53.234 6918 6918 F DEBUG : x28 0000006404f5cd12 x29 0000007ff03cad00
09-24 16:34:53.234 6918 6918 F DEBUG : lr 0000006404f60b58 sp 0000007ff03cacd0 pc 0000006404f5ff18 pst 0000000000000000
09-24 16:34:53.234 6918 6918 F DEBUG : 4 total frames
09-24 16:34:53.234 6918 6918 F DEBUG : backtrace:
09-24 16:34:53.234 6918 6918 F DEBUG : #00 pc 0000000000009f18 /system/bin/robert (print_all_event()+60) (BuildId: 52b288fb7098ea1a378db332a4c000bf)
09-24 16:34:53.234 6918 6918 F DEBUG : #01 pc 000000000000ab54 /system/bin/robert (startRecord()+2620) (BuildId: 52b288fb7098ea1a378db332a4c000bf)
09-24 16:34:53.234 6918 6918 F DEBUG : #02 pc 000000000000afd8 /system/bin/robert (recordEvent(char*)+228) (BuildId: 52b288fb7098ea1a378db332a4c000bf)
09-24 16:34:53.234 6918 6918 F DEBUG : #03 pc 0000000000052610 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+104) (BuildId: c74277f481a383c87215b672f6465e24)
上面堆栈都是一些地址码和大概的函数堆栈,所以一般没办法直接和java代码一样定位到具体的行数等。一般user版本也就只有上面的crash的堆栈信息,虽然没办法定位到具代码crash行数,但是可以得到一些线索:
1、根据堆栈可以得出这个其实是一个空指针的crash
2、crash的地方可以大概定位到是在 /system/bin/robert 的print_all_event()方法
但是具体函数user版本的话就看不出来,如果可以复现的话其实这个问题也好处理,因为可以考虑直接系统上复现,使用源码进行debug到具体函数,再不行还可一行行打log也可以缩小定位。
有源码+可以复现crash情况下,可以使用工具llvm-addr2line定位具体代码行数,方法如下:
~/test/aosp/out/target/product/xxx/symbols/system/lib64$ ~/test/aosp/prebuilts/clang/host/linux-x86/clang-r416183b/bin/llvm-addr2line -Cfe xxx.so(或者bin) xxxx(16进制地址)
xxxxx(方法全名)
上面来举例,堆栈获取最顶部的一行
#00 pc 0000000000009f18 /system/bin/robert (print_all_event()+60)
0000000000009f18就是16进制地址 robert就是bin print_all_event方法
就拿上面案例来测试:
test@test:~/disk2/nx563j_aosp14/out/target/product/nx563j/symbols/system/bin$ ~/disk2/nx563j_aosp14/prebuilts/clang/host/linux-x86/clang-r487747c/bin/llvm-addr2line -Cfe robert 0000000000009f18 print_all_event
testNull()
robert/getevent.cpp:270
print_all_event
去除路径核心就是 :
llvm-addr2line -Cfe robert 0000000000009f18 print_all_event
上面经过工具后既可以得到出错代码是在
robert/getevent.cpp:270
下面看看这个270行代码
确实有空指针
进程卡住,卡顿定位backtrace获取分析
经常调试偶尔发现app可能卡住,没反应的情况,这个时候就很希望知道卡住这时候的进程的一个运行情况,希望可以得到一个和anr trace一样的文件来方便分析定位线程状态,即想要获取进程的backtrace。
注意获取进程backtrace方法都需要root
apk打印出当前进程backtrace
使用命令:
kill -3 pid (只针对apk类型的生效)
执行后在/data/anr/目录生成backtrace文件
NX563J:/ # ps -A | grep anr
u0_a181 7449 22013 14655980 76492 futex_wait_queue_me 0 S com.example.anrdemo
NX563J:/ # kill -3 7449
pull出anr下面的文件及打开:
adb pull /data/anr ~/tmp/
可以看出卡顿时候其实是main主线程卡在onResume方法里面,线程处于sleep
native程序打印backtrace
使用debuggerd 命令
debuggerd -b pid (针对native bin)
案例如下:
robert进程的backtrace
NX563J:/ # ps -A | grep robert
root 7629 7622 10830444 1872 do_sys_poll 0 S robert
NX563J:/ # debuggerd -b 7629----- pid 7629 at 2024-09-24 17:14:02.315686219+0800 -----
Cmd line: robert -rec:/data/event
ABI: 'arm64'"robert" sysTid=7629#00 pc 00000000000ab758 /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+8) (BuildId: c74277f481a383c87215b672f6465e24)#01 pc 0000000000065ed0 /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: c74277f481a383c87215b672f6465e24)#02 pc 000000000000a2b4 /system/bin/robert (startRecord()+424) (BuildId: 7005ff744c2b0ed72a670bb8f0bd61e9)#03 pc 000000000000afcc /system/bin/robert (recordEvent(char*)+228) (BuildId: 7005ff744c2b0ed72a670bb8f0bd61e9)#04 pc 0000000000052610 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+104) (BuildId: c74277f481a383c87215b672f6465e24)----- end 7629 -----
更多framework详细代码和资料参考如下链接
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频试看:
https://www.bilibili.com/video/BV1wc41117L4/
参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615