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

相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡3 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi003 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你5 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk13 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin