Unity排查定位libunity.so崩溃问题(自动+手动)

线上崩溃统计日志中经常出现一个空指针崩溃问题,关键词为 signal 11(SIGSEGV),code 1(SEGV_MAPERR),fault addr 00000000,调用链指向 libunity.so。

问题

虽然崩溃时调用链指向了 libunity.so,但具体执行了啥,调用的是哪个方法,根本无从下手,例如下面的日志,你根本不知道 libunity.00966c68 是啥:

E AndroidRuntime:   at libunity.00966c68(Native Method)
E AndroidRuntime:   at libunity.00965318(Native Method)
E AndroidRuntime:   at libunity.005b7d18(Native Method)
E AndroidRuntime:   at libunity.005b7d50(Native Method)
E AndroidRuntime:   at libunity.005b7f28(Native Method)
E AndroidRuntime:   at libunity.006a43d0(Native Method)
E AndroidRuntime:   at libunity.006b2a70(Native Method)

因此需要找个方法将 libunity.so 调用报错转换成具体的方法名。本文以我遇到的报错为例,简要记录下 Debug 方法。

注意:新版 Unity 以 IL2CPP 方式编译,默认开启引擎裁剪。裁剪后,对应的符号表参考下文:
IL2CPP打包libunity.so等符号表(Symbols)对不上问题

方法1:上传 so 库符号表(仅针对未混淆的 App,自动翻译)

此种方法仅作用于 Bugly 这种支持符号表上传的平台,且要求你的程序是未做过安卓代码混淆的。

Unity libunity.so 的符号表在如下目录可以找到:

注意,此处的符号表对应的是未勾选引擎裁剪的完整库

Debug版:
Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Symbols
发行版:
Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Symbols

根据平台不同,可找到不同的文件夹,里面的 libunity.sym.so 即为 so 库符号表。

使用 Bugly 官方工具将 libunity.sym.so 符号表传至线上统计平台,之后平台自动将 crash report 中的 so 库报错替换为调用链符号(即方法名)。

java -jar buglyqq-upload-symbol.jar
    -appid [AppId]
    -appkey [Appkey]
    -bundleid com.test.azimiao
    -version 1.0.0
    -platform Android
    -inputSymbol libunity.sym.so

成功上传后,bugly 后台应该有 so 符号表:

我传了,发现不行,后来问过安卓同学才知道,Unity 导出项目给他们后,他们又加了一层代码混淆。

我猜测代码混淆导致 crash 日志的字符发生变化,本应该是 libunity.so + 调用栈的报错变成了 libunity.调用栈,因此无法被 bugly 等平台自动识别。

方法2.根据符号表手动翻译

既然上传符号表行不通,则选择手动翻译。

当然这里的手动翻译不是手动去分析二进制,而是利用现有工具自己一行一行翻译。

首先在你的 ndk 文件夹里找到 *-addr2line 这玩意,他是一个把调用栈内存地址转为行号的工具。

  • 32 位 APK so 库使用 arm-linux-androideabi-addr2line

  • 64 位 APK so 库使用 aarch64-linux-android-addr2line

使用如下命令将调用栈内存地址转化为符号表对应内容并输出:

./*-addr2line.exe -f -C -e libunity.sym.so 00966c68

如果得法,将会输出对应的方法名:

将上文中报错调用链日志一行行翻译,最终报错翻译如下:

VideoClipPlayback::DetectEndReached()
VideoPlaybackMgr::Update()
ExecutePlayerLoop(NativePlayerLoopSystem*)
PlayerLoop()
UnityPlayerLoop()
nativeRender(_JNIEnv*, _jobject*)

可以看出这是一个使用自带 VideoPlayer 时导致的崩溃。

这个例子中的报错究竟是啥

上文中用某个 libunity 报错日志举了个例子,那么这个报错的原因是什么呢?而空引用又代表了什么呢?

这其实是 Unity 自带 VideoPlayer 一个久远的 Bug:当 VideoPlayer 开始播放后又马上被销毁时,某些内部逻辑会直接使用已经被销毁的对象,导致该问题。

Unity 自称这个问题在 2018.4.35f1 及 2020.2 版本中被修复,具体内容见 Unity Issue Tracker #1241848。

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/8591.html
欢迎加入梓喵出没博客交流群:313732000

发表评论

*

*