如何在 Flutter 中符号化 libapp.so 堆栈跟踪?

How to symbolicate libapp.so stack trace in Flutter?

在 Google Play 控制台中,有时我会看到这样的崩溃报告:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.blackoutage.game <<<

backtrace:
  #00  pc 00000000003080f0  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 0000000000306ad4  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 000000000065ebc4  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 000000000051e4a8  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libapp.so (offset 0x1000)
  #00  pc 0000000000565c9c  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libapp.so (offset 0x1000)
  #00  pc 000000000063925c  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc b4000071fdfd5200  <unknown>

libflutter.so (https://github.com/flutter/flutter/wiki/Crashes) 符号化堆栈跟踪非常容易。根据上面的日志,我可以说 flutter 中的某些东西崩溃了,但要修复这些错误,我还需要符号化来自 libapp.so 的痕迹,我该怎么做?

首先,如果可以的话,尽量使用集成的解决方案,比如Sentry(https://pub.dev/packages/sentry_flutter)。它会自动捕获堆栈跟踪并尝试将它们符号化。如果你的应用被剥离,你也可以将符号文件上传到他们的服务器,他们会对其进行符号化。

其次,如果您想手动完成,这里有一些见解。之前我也纠结过这样的符号化,网上好像没有足够的信息(所以让我在网上补充一点信息;))。

有趣的是,libapp.so是一个普通的.so文件(动态链接库)。它不是一种特殊的自制特定于 Flutter 的格式。相反,即使你写下一个C/C++程序并编译它也是一样的ELF格式。有了这些知识,您会立即意识到,符号化 Flutter 堆栈跟踪与符号化普通 C/C++/... 代码没有区别。

因此,您可能需要了解一下 C/C++ 的传统世界。例如,我建议阅读经典 CSAPP 教科书的“链接器”一章,它解释得很好。然后你就会完全理解什么是.so文件,如何符号化C/C++.so文件的堆栈跟踪等

那你做Flutter的符号化应该没问题。但在这里我也写下了一步一步要做的事情:首先,当你构建不包含调试信息的 apk 时,你使用 split-debug-info 标志并单独获取调试信息文件。在符号化中将需要此调试信息文件。然后,使用传统工具操作传统 .so 文件,例如 addr2line,以获取给定 pc 的源代码行号。当然,ndk-stack 等高级工具也有帮助。或者你可以写下你自己的脚本调用addr2line等等。