Android中Crash Debug技巧

工作中经常会遇到Android中Crash的情况,之前没有一个很清晰的思路,现在总结一下:

一般情况下,Android中发生了Crash,会以"beginning of crash"为开头,记录crash发生的相关信息,比如是哪个进程(pid)发生的crash,如下所示

--------- beginning of crash
08-02 17:11:45.761 10549 10655 F libc    : Fatal signal -1447396355 (?), code -1862269955 (? from pid -1459396616, uid -145) in tid 10655 (Runner: gl_5_hi), pid 10549 (50005.corporate)
08-02 17:11:45.761   938   983 I libPowerHal: [perfLockRel] hdl:60244, idx:4
08-02 17:11:45.761   938   983 I libPowerHal: [PD] fpsgo update cmd:1408300 param:0

因此,从adb logcat的角度判断是否发生了crash,在log中搜索"beginning of crash"则可以,如果搜索到了,就证明该进程发生了crash。

那么如何debug呢?需要看log中的crash这部分的log有没有记录下backtrace

1.crash记录了backtrace

直接搜"backtrace",会看到类似下面的log片段:

07-08 08:33:43.062  2091  2091 F DEBUG   : Cmdline: /vendor/bin/hw/rild -l /vendor/lib64/libquectel-ril.so
07-08 08:33:43.062  2091  2091 F DEBUG   : pid: 2087, tid: 2087, name: rild  >>> /vendor/bin/hw/rild <<<
07-08 08:33:43.062  2091  2091 F DEBUG   : uid: 0
07-08 08:33:43.062  2091  2091 F DEBUG   : tagged_addr_ctrl: 0000000000000001
07-08 08:33:43.062  2091  2091 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
07-08 08:33:43.062  2091  2091 F DEBUG   : Cause: null pointer dereference
07-08 08:33:43.062  2091  2091 F DEBUG   :     x0  0000007038a8afa8  x1  0000007fd7cd33d8  x2  0000000000000000  x3  0000007fd7cd343a
07-08 08:33:43.062  2091  2091 F DEBUG   :     x4  0000000000000000  x5  0000000000000000  x6  726b68737473646d  x7  7f7f7f7f7f7f7f7f
07-08 08:33:43.062  2091  2091 F DEBUG   :     x8  3a07c997d0de8c07  x9  3a07c997d0de8c07  x10 0000007fd7cd2c08  x11 fffffffffffffffd
07-08 08:33:43.062  2091  2091 F DEBUG   :     x12 0000007fd7cd2d20  x13 00000000000000cb  x14 0000007fd7cd2ea8  x15 000000008aac1451
07-08 08:33:43.062  2091  2091 F DEBUG   :     x16 00000072ca56a530  x17 00000072ca6d3610  x18 00000072ce3e4000  x19 0000007fd7cd3438
07-08 08:33:43.062  2091  2091 F DEBUG   :     x20 0000007038aae000  x21 0000007038aaf010  x22 0000007038a86000  x23 0000007038aaf000
07-08 08:33:43.062  2091  2091 F DEBUG   :     x24 0000007fd7cd33d8  x25 0000000000000003  x26 0000005a616d9368  x27 0000000000000000
07-08 08:33:43.062  2091  2091 F DEBUG   :     x28 0000007038a8af40  x29 0000007fd7cd38a0
07-08 08:33:43.062  2091  2091 F DEBUG   :     lr  0000007038a5c76c  sp  0000007fd7cd3300  pc  0000000000000000  pst 0000000060001000
07-08 08:33:43.062  2091  2091 F DEBUG   : backtrace:
07-08 08:33:43.062  2091  2091 F DEBUG   :       #00 pc 0000000000000000  <unknown>
07-08 08:33:43.062  2091  2091 F DEBUG   :       #01 pc 000000000001b768  /vendor/lib64/libquectel-ril.so (RIL_Init+720)
07-08 08:33:43.062  2091  2091 F DEBUG   :       #02 pc 0000000000002378  /vendor/bin/hw/rild (main+804) (BuildId: e9dcddf3d5bf74361d31231eafbe6a08)
07-08 08:33:43.062  2091  2091 F DEBUG   :       #03 pc 00000000000488c8  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+96) (BuildId: ba489d4985c0cf173209da67405662f9)

其中有三个地方需要注意:

  • Cmdline:指示代码是运行什么样的命令/应用时发生crash的,该处是运行"/vendor/bin/hw/rild -l /vendor/lib64/libquectel-ril.so"
  • Cause:指示发生Crash的原因是什么,该处是"Cause: null pointer dereference",即发生了空指针的解引用。
  • backtrace:指示调用的顺序

1.1如何debug:

1.1.1找到发生Crash的函数,然后手动在源代码中加log,一步步debug

backtrace中,对应的log中会提示是跑在哪个函数中。比如:

07-08 08:33:43.062  2091  2091 F DEBUG   :       #01 pc 000000000001b768  /vendor/lib64/libquectel-ril.so (RIL_Init+720)

指示跑在libquectel-ril.so中的RIL_Init函数中。则我们可以检查这个RIL_Init这个函数中的代码并加log进行debug。

1.1.2利用addr2line这个工具,精准定位到哪个文件的哪一行

比如我们想定位发生crash的RIL_Init函数在哪个文件的哪一行,则可以先找到上述信息中的偏移地址"01 pc 000000000001b768"

$ cd <Android_Source_Code>/out/target/product/<specific_product_name>/symbols/
$ find . -name libquectel-ril.so
$ cd <path_libquectel-ril.so>
$ addr2line -C -f -e libquectel-ril.so 000000000001b768

//上述命令找到symbol的位置,利用addr2line命令把偏移量转换为函数所在的文件与代码行,可以让我们知道crash在代码中的具体位置

可能会遇到"addr2line: DWARF error: invalid or unhandled FORM value"的错误,无法成功拿到正确的输出,则应该用Android Source Code中自带的addr2line工具就可以解决:

prebuilts/clang/host/linux-x86/clang-r487747c/bin/llvm-addr2line

补充:我们发布xxxx.so文件的时候,可以连同xxxx.so.symbols一起发布,这样即使我们的编译环境更改了,也可以通过 xxxx.so.symbols 文件定位错误发生在哪一行,用法跟xxxx.so一样,以上面的命令为例,即:

$ addr2line -C -f -e libquectel-ril.so.symbols 000000000001b768

脚本:

exelist=(exe1 exe2)
addrlist=(addr1 addr2)

exe1=out/target/product/xxxx/symbols/vendor/lib64/egl/libGLES_mali.so
addr1=(
0000000001aa1990
0000000001926ab4
0000000001996188
0000000001ab2e1c
0000000001ab0fa0
0000000001ab1030
0000000001aaefd0

 )
exe2=out/target/product/mahakala/symbols/data/nativetest64/vendor/mali_tests64/mali_vulkan_integration_suite
addr2=(
 )

echo ${addr[*]}

for i in ${addr1[*]}; do
    llvm-addr2line -e ${exe1} 0x${i}
done



for i in ${addr2[*]}; do
    llvm-addr2line -e ${exe2} 0x${i}
done

2. crash未记录backtrace

没有backtrace意味着不知道是哪里发生了crash,这一般是由于对空指针进行解引用,导致不能记录backtrace。也就是说你只能在log里搜到"beginning of crash",而搜不到"backtrace"。这种情况需要去查找tombstone。Android的tombstone会帮助记录这些信息。

$ adb shell
$ cd /data/tombstone/

tombstone中会记录的信息跟前面的情况一样,包含:Cmdline, Cause和backtrace。Debug方法同crash记录了backtrace的情景。

相关推荐
zhangphil12 分钟前
Android简洁缩放Matrix实现图像马赛克,Kotlin
android·kotlin
m0_5127446412 分钟前
极客大挑战2024-web-wp(详细)
android·前端
lw向北.29 分钟前
Qt For Android之环境搭建(Qt 5.12.11 Qt下载SDK的处理方案)
android·开发语言·qt
不爱学习的啊Biao37 分钟前
【13】MySQL如何选择合适的索引?
android·数据库·mysql
Clockwiseee1 小时前
PHP伪协议总结
android·开发语言·php
mmsx8 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
众拾达人11 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
吃着火锅x唱着歌11 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
_Shirley13 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
hedalei14 小时前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576