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

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui