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的情景。

相关推荐
Eastsea.Chen1 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年9 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿11 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神12 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛12 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法13 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter14 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快15 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl15 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
麦田里的守望者江16 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin