Flutter engine 异常捕获

475 阅读4分钟

Flutter的崩溃日志收集主要有两个方面:

  1. flutter dart 代码的异常(包含app和framework代码两种情况,这个比较简单,在这里我们不讨论)
  2. flutter engine 的崩溃日志(一般会闪退),我们着重讨论这个场景。。。。。。

堆栈还原

收集到异常之后,需要查符号表(symbols)还原堆栈。下面以Android 端 bugly 收集到堆栈为一例:

1 #00 pc 00016998 /system/lib/libc.so (__memcpy_base+104) [armeabi-v7a::2b2dac1c583b68da2f7c58e7ed352851] 2 #01 pc 00158aed /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 3 #02 pc 00138041 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 4 #03 pc 00139461 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 5 #04 pc 00013057 /system/lib/libutils.so (_ZN7android6Looper9pollInnerEi+530) [armeabi-v7a::ac423f49f579c99cfababb65014363e9] 6 #05 pc 00013127 /system/lib/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv+130) [armeabi-v7a::ac423f49f579c99cfababb65014363e9] 7 #06 pc 00007889 /system/lib/libandroid.so (ALooper_pollOnce+64) [armeabi-v7a::954c216fdf1faa9aa08f41bc27503a87] 8 #07 pc 001394fb /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 9 #08 pc 001371eb /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 10 #09 pc 00138441 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] 11 #10 pc 0004185b /system/lib/libc.so (_ZL15__pthread_startPv+30) [armeabi-v7a::2b2dac1c583b68da2f7c58e7ed352851] 12 #11 pc 000192a5 /system/lib/libc.so (__start_thread+6) [armeabi-v7a::2b2dac1c583b68da2f7c58e7ed352851] 13 java: 14 [Failed to get Java stack]

| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

首先需要确认该 flutter engine 所属版本号,在命令行执行:

| ```
``
flutter --version 

输出如下:

Flutter 3.0.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision cd41fdd495 (5 周前) • 2022-06-08 09:52:13 -0700
Engine • revision f15f824b57
Tools • Dart 2.17.3 • DevTools 2.12.2 

可以看到 Engine 的 revision 为 f15f824b57

其次,在 flutter infra 上找到对应cpu abi 的 symbols.zip 并下载 :console.cloud.google.com/storage/bro…

解压后,可以得到带有符号信息的 debug so 文件—— libflutter.so,并将其放到文件夹 armeabi-v7a 下。如需要x86等的符号信息,类似操作。

mkdir -p ~/Downloads/flutter-52c7a1e849/armeabi-v7a unzip symbols.zip -d ~/Downloads/flutter-52c7a1e849/armeabi-v7a 

使用 ndk-stack

Android 上手动还原 libflutter.so 堆栈,可以使用 NDK 提供的工具 ndk-stack

  1. 将原始堆栈保存到 stack.txt 中,注意第一行要以 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 开头
   *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 
   1 #00 pc 00016998 /system/lib/libc.so (__memcpy_base+104) [armeabi-   v7a::2b2dac1c583b68da2f7c58e7ed352851] 2 #01 pc 00158aed /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-   v7a::2c9d8634bdb07ea641970181b0b00b84] 3 #02 pc 00138041 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-   v7a::2c9d8634bdb07ea641970181b0b00b84] 4 #03 pc 00139461 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-   v7a::2c9d8634bdb07ea641970181b0b00b84] 5 #04 pc 00013057 /system/lib/libutils.so 
   (_ZN7android6Looper9pollInnerEi+530) [armeabi-   v7a::ac423f49f579c99cfababb65014363e9] ... 
  1. 执行ndk-stack命令

    $ANDROID_NDK/ndk-stack -sym ~/Downloads/flutter-52c7a1e849/armeabi-v7a -dump stack.txt > re-stack.txt

打开文件 re-stack.txt 即可看到还原后的堆栈:

********** Crash dump: ********** #00 0x00016998 /system/lib/libc.so (__memcpy_base+104) [armeabi-v7a::2b2dac1c583b68da2f7c58e7ed352851] #01 0x00158aed 
/data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] fml::WriteAtomically(fml::UniqueObject<int, 
fml::internal::os_unix::UniqueFDTraits> const&, char const*, fml::Mapping const&) /b/s/w/ir/k/src/out/android_release/../../flutter/fml/platform/posix/file_posix.cc:203:
3 flutter::PersistentCacheStore(fml::RefPtr<fml::TaskRunner>, std::__1::shared_ptr<fml::UniqueObject<int, fml::internal::os_unix::UniqueFDTraits> >, 
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::unique_ptr<fml::Mapping, std::__1::default_delete<fml::Mapping> 
>)::$_0::operator()() /b/s/w/ir/k/src/out/android_release/../../flutter/shell/common/persistent_cache.cc:114:
0 auto fml::internal::CopyableLambda<flutter::PersistentCacheStore(fml::RefPtr<fml::TaskRunner
>, std::__1::shared_ptr<fml::UniqueObject<int, fml::internal::os_unix::UniqueFDTraits> 
>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::unique_ptr<fml::Mapping, std::__1::default_delete<fml::Mapping> 
>)::$_0>::operator()<>() const /b/s/w/ir/k/src/out/android_release/../../flutter/fml/make_copyable.h:24:0 #02 
0x00138041 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-v7a::2c9d8634bdb07ea641970181b0b00b84] fml::MessageLoopImpl::FlushTasks(fml::MessageLoopImpl::FlushType) /b/s/w/ir/k/src/out/android_release/../../flutter/fml/message_loop_impl.cc:140:5 
fml::MessageLoopImpl::RunExpiredTasksNow() /b/s/w/ir/k/src/out/android_release/../../flutter/fml/message_loop_impl.cc:148:0 #03 
0x00139461 /data/app/com.netease.cartoonreader-1/lib/arm/libflutter.so [armeabi-
v7a::2c9d8634bdb07ea641970181b0b00b84] fml::MessageLoopAndroid::OnEventFired() /b/s/w/ir/k/src/out/android_release/../../flutter/fml/platform/android/message_loop_and
roid.cc:92:5 fml::MessageLoopAndroid::MessageLoopAndroid()::$_0::operator()(int, int, 
void*) const /b/s/w/ir/k/src/out/android_release/../../flutter/fml/platform/android/message_loop_and
roid.cc:42:0 fml::MessageLoopAndroid::MessageLoopAndroid()::$_0::__invoke(int, int, 
void*) /b/s/w/ir/k/src/out/android_release/../../flutter/fml/platform/android/message_loop_and
roid.cc:40:0 #04 0x00013057 /system/lib/libutils.so 
(_ZN7android6Looper9pollInnerEi+530) [armeabi-v7a::ac423f49f579c99cfababb65014363e9]  ... 

bugly 自动还原堆栈

一个个崩溃堆栈手动还原多麻烦(噫 你怎么这么多崩溃),下载好 debug so 之后你也可以使用 bugly给的符号表上传工具上传到bugly上,文档见:bugly.qq.com/docs/user-g…

输出符号表:

java -jar buglySymbolAndroid.jar -i ~/Downloads/flutter-52c7a1e849/armeabi-v7a 

将符号表上传之后,bugly 会自动将堆栈还原,如下图所示

使用 atos

iOS上的 Flutter 引擎崩溃堆栈还原步骤和 Android 类似,先下载对应的符号表(Flutter.dSYM.zip),然后通过 atos 还原,如:

atos -arch arm64 -o ~/Downloads/flutter_e1e6ced81d029258d449bdec2ba3cddca9c2ca0c_ios-
release_Flutter.dSYM/Flutter.dSYM/Contents/Resources/DWARF/Flutter -l 
0x000000010277c000 0x00000001027b91dc 

输出:
fml::MessageLoopDarwin::OnTimerFire(__CFRunLoopTimer*, fml::MessageLoopDarwin*) (in 
Flutter) (message_loop_darwin.mm:76) 

福利 <(▰˘◡˘▰)>

如果你不想使用第三方的错误收集平台,可以用 github.com/flutter/sen… 和 sentry.io开源版 配合使用搭建自己的后台.