ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flutter Engine 崩溃堆栈符号化完全指南:Android / iOS / macOS 平台实操与源码原理

Flutter Engine 崩溃堆栈符号化完全指南:Android / iOS / macOS 平台实操与源码原理 跨平台图形学前端【免费下载链接】engineThe Flutter engine项目地址https://gitcode.com/gh_mirrors/eng/engine点击查看免费下载导读当 Flutter 应用发生原生崩溃时Android tombstone 与 iOS 崩溃日志中的十六进制地址往往无法直接看出是引擎哪一行代码出了问题。本文以 Flutter Engine 仓库的 docs/Crashes.md 为骨架系统讲解如何将引擎崩溃堆栈符号化Symbolicate覆盖 Android 下ndk-stack、addr2line与libflutter.so构建 ID 校验的完整链路iOS / macOS 上 dSYM 符号的获取方式以及 Dart AOT 代码崩溃的调试流程。读完本文你将掌握从一份崩溃报告反查到引擎源码具体行号如dart_api_impl.cc:1366的完整方法也能为自己的本地引擎构建开启带符号的产物。一、何时需要手动符号化在 Flutter 3.24 及之后版本产生的 iOS 应用归档包archive中已经内嵌了引擎调试符号因此这类崩溃默认即可自动符号化。但对于Android以及3.24 之前的旧版 iOS应用崩溃堆栈默认是十六进制地址需要额外处理。最省力的方式是运行dart_ci symbolizer工具在本地进行符号化。如果该方案不可用则按本文后面的步骤手动完成。手动符号化的核心思路是从崩溃报告拿到Flutter Framework 或 Flutter Engine 的 revision提交哈希以该哈希为索引从 Flutter 官方产物存储中下载与崩溃应用构建模式debug / release / profile严格匹配的符号文件使用 NDK 自带的ndk-stack/addr2lineAndroid或 Xcode 的atosiOS/macOS等工具把地址翻译为源文件:行号。二、Android 平台符号化2.1 获取符号文件第一步确定 Engine revision。如果崩溃报告中直接给出了 Engine revision可直接跳到第三步否则需要先从 Framework revision 反查 Engine revision。Flutter 仓库中的bin/internal/engine.version文件记录了与某个 Framework 版本对应的 Engine 提交哈希——把该文件 URL 中的main替换为你报告的 Framework 哈希即可看到对应内容。第二步确认完整哈希。报告中的提交哈希可能是短哈希需要先按本文「2.5 扩展 Git Revisions」一节补齐为完整的 40 位哈希例如cea5ed2b9be42a981eac762af3664e4a17d0a53f。第三步下载符号压缩包。有了完整 engine revision可以打开产物浏览页面把其中的 engine 哈希替换为你的哈希产物浏览页面https://console.cloud.google.com/storage/browser/flutter_infra_release/flutter/ENGINE_HASH下载符号文件则使用另一个主机名storage而非 console的 URL且必须使用浏览器访问因为它需要登录认证https://storage.cloud.google.com/flutter_infra_release/flutter/ENGINE_HASH/android-arm/symbols.zip⚠️关键符号类型必须与应用的发布类型匹配。上例对应的是 android-arm 的debug构建。如果应用是release或profile构建URL 中对应目录名分别是android-arm-release与android-arm-profilehttps://storage.cloud.google.com/flutter_infra_release/flutter/ENGINE_HASH/android-arm-release/symbols.ziphttps://storage.cloud.google.com/flutter_infra_release/flutter/ENGINE_HASH/android-arm-profile/symbols.zip选错模式会导致地址无法正确解析——因为不同构建模式下 Dart 运行时与引擎的代码布局完全不同。解压symbols.zip后即可得到带调试信息的libflutter.so等符号文件。2.2 使用 ndk-stack 符号化ndk-stack随 Android NDK 一起分发。假设stack.txt中保存了完整的崩溃堆栈必须包含开头的*** *** ***标记行它是 tombstone 的起始标志# Linux .../ndk/prebuilt/linux-x86_64/bin/ndk-stack -sym .../path/to/downloaded/symbols stack.txt# macOS .../ndk/prebuilt/darwin-x86_64/bin/ndk-stack -sym .../path/to/downloaded/symbols stack.txtndk-stack会解析 stdin 中的日志把每一帧的地址与-sym指定的符号目录进行匹配并输出对应源文件与行号。注意日志完整性某些调试工具如pidcat可能不会展示完整的 tombstone 日志这种情况下请直接使用adb logcat抓取并复制完整输出否则符号化结果会缺失帧。2.3 使用 addr2line 符号化另一种方式是使用同样打包在 NDK 中的addr2line工具把上文下载的.so文件路径传给-e参数然后手动把堆栈中的地址逐一喂给它。例如在 macOS 上% $ANDROID_HOME/ndk/20.0.5594570/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line -e ~/Downloads/libflutter.so此时工具进入等待输入状态把崩溃地址粘贴进去注意地址中的前导0x需保留0x00000000006a26ec /b/s/w/ir/cache/builder/src/out/android_release_arm64/../../third_party/dart/runtime/vm/dart_api_impl.cc:1366这个例子清晰地展示了成果地址0x00000000006a26ec对应的是 Dart VM 源码dart_api_impl.cc的第 1366 行。addr2line的优势是不依赖完整 tombstone可以逐帧灵活处理但需要手动复制每个地址。2.4 确认拿到的是正确的 libflutter.so符号化失败的最常见原因是下载的.so与崩溃设备上实际运行的libflutter.so不是同一个构建产物。构建系统会为每个libflutter.so打上一个唯一的Build ID在 tombstone 中可以看到#00 pc 000000000062d6e0 /data/app/com.app-tARy3eLH2Y-QN8J0d0WFog/lib/arm64/libflutter.so!libflutter.so (offset 0x270000) (BuildId: 34ad5bdf0830d77a)上例中该.so的 Build ID 为34ad5bdf0830d77a。用file命令可以验证下载到的符号文件% file ~/Downloads/libflutter.so /Users/user/Downloads/libflutter.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[xxHash]34ad5bdf0830d77a, with debug_info, not stripped务必确认两者的 Build ID 完全一致否则无法完成符号化。顺带说明输出中的not stripped表示该文件保留了调试信息这也是它能被符号化的前提引擎的 release 构建符号包正因如此才能解析出源码行号。2.5 扩展 Git Revisions崩溃报告中出现的往往是短提交哈希如2a13567。要去掉这个前缀只需在浏览器中打开对应仓库的 commit 页面并把短哈希作为 URL 最后一段例如 Flutter 仓库的.../commit/9cb914df1或 Engine 仓库的.../commit/2a13567页面中会展示完整的 40 位 revision直接复制即可用于构造符号下载 URL。2.6 符号化本地构建的引擎如果你使用的是自己编译的引擎则无需下载符号——构建产物本身就带符号直接用ndk-stack指向构建输出目录即可# dev/engine 是你的引擎源码目录包含 .gclient 文件的位置 # android_debug_unopt 是你正在使用的引擎构建变体 adb logcat | ~/dev/engine/src/third_party/android_tools/ndk/prebuilt/linux-x86_64/bin/ndk-stack -sym ~/dev/engine/src/out/android_debug_unopt这条命令把adb logcat的实时输出通过管道直接交给ndk-stack崩溃发生时即可即时得到符号化结果非常适合本地调试循环。三、iOS 平台符号化3.1 Flutter 3.24 及之后从 artifact cache 获取自 Flutter 3.24 起iOS 引擎符号已经包含在 Flutter framework 的artifact cache中即 xcframework 包内bin/cache/artifacts/engine/ios-release/Flutter.xcframework其中真机device构建的符号位于ios-arm64/dSYMs/Flutter.framework.dSYM包内模拟器simulator构建的符号位于ios-arm64_x86_64-simulator/dSYMs/Flutter.framework.dSYM包内。对于 3.24 及之后的 release这些符号不再作为独立压缩包单独上传必须从上述 artifact cache 获取。artifact cache 本身也可以通过 URL 直接下载把 engine 哈希替换为你的哈希https://storage.googleapis.com/flutter_infra_release/flutter/ENGINE_HASH/ios-release/artifacts.zip3.2 3.24 之前从 Google Cloud Storage 下载对于 Flutter 3.24 之前的版本需要参照本文 Android 一节的流程只是最后一步的下载 URL 换成如下模式替换 engine 哈希https://storage.cloud.google.com/flutter_infra_release/flutter/ENGINE_HASH/ios-release/Flutter.dSYM.zip四、macOS 平台符号化4.1 Flutter 3.27 及之后从 artifact cache 获取自 Flutter 3.27 起macOS 引擎符号包含在 artifact cache 的 xcframework 中bin/cache/artifacts/engine/darwin-x64-release/Flutter.xcframework设备构建的符号位于macos-arm64_x86_64/dSYMs/FlutterMacOS.framework.dSYM包内。3.27 及之后的 release 同样不再上传独立符号压缩包而是通过 artifact cache 获取可直接用如下 URL 下载替换 engine 哈希https://storage.googleapis.com/flutter_infra_release/flutter/ENGINE_HASH/darwin-x64-release/framework.zip4.2 3.27 之前从 Google Cloud Storage 下载参照 Android 一节的流程下载 URL 使用如下模式替换 engine 哈希https://storage.cloud.google.com/flutter_infra_release/flutter/ENGINE_HASH/darwin-x64-release/FlutterMacOS.dSYM.zip4.3 符号化本地构建如果你在debug 或 profile Dart 模式下构建了本地引擎framework 的 dylib 符号不会被剥离开箱即可符号化无需额外下载任何文件。五、调试 Dart AOT 代码中的崩溃iOS如果崩溃发生在AOT Dart 代码中即--release或--profile构建且你能够自行构建引擎以下步骤将产出对 Dart VM 团队修复 bug 非常有用的信息准备一个最小复现用例reduced test case。以 profile 模式编译引擎并关闭优化以获得可符号化的堆栈sky/tools/gn --ios --unopt --runtime-mode profile; ninja -C out/ios_profile_unopt -j800该命令位于仓库的 sky/tools 目录--unopt关闭优化、--runtime-mode profile指定运行时模式下文「六」会结合源码解释这两个参数的底层映射。通过 Xcode 工程启动应用并在调试器中使其崩溃。记录寄存器状态在lldb中执行register read把输出粘贴进 bug。记录回溯在lldb中执行thread backtrace默认显示当前线程如果不在崩溃线程上先用thread select n切换。反汇编最后一帧frame select 0后执行disassemble --frame把结果粘贴进 bug。用gen_snapshot反汇编以获取更详细信息在回溯中找出导致崩溃的预编译函数名在 Xcode 中打开SnapshotterInvoke在RunCommand ... Snapshotter调用处加上--disassemble标志修改RunCommand函数把输出转储到文件重新构建结果会写入该文件在文件中按函数名子串匹配搜索并复制对应信息到 bug 中。在 dart-lang/sdk 上提交 issue并联系相关人员ping跟进。六、Android 本地引擎构建保留符号的两种手段当使用本地引擎构建运行时符号化流程可能显得繁琐。更直接的做法是让引擎产物本身携带符号并阻止 Gradle 自动剥离符号——这同时也是在 Android Studio 的 CPU Profiler 中看到符号名称的前提条件。6.1 让 gn 输出未剥离的 libflutter.so在 Android 引擎配置中为 gn 传入--no-stripped参数gn --android --android-cpuarm64 --unopt --no-stripped这一参数在仓库的构建脚本 tools/gn 中定义--stripped默认值为true帮助文本明确注明 Strip debug symbols from the output. This defaults to true and has no effect on iOS.--no-stripped将其置为false最终写入 GN 参数gn_args[stripped_symbols] args.stripped见 tools/gn。该参数的实际效果可以在 Android shell 的构建定义 shell/platform/android/BUILD.gn 中看到当stripped_symbols为真时android_jar目标把已剥离的lib.stripped/libflutter.so打入产物为假时则直接使用未剥离的libflutter.so。6.2 阻止 Gradle 二次剥离即使引擎产物带符号Gradle 打包时仍可能再次剥离.so的符号。在 Flutter 项目的android/app/build.gradle的android块中加入packagingOptions{ doNotStrip **/*.so }这样 APK 内所有架构的.so都会保留符号ndk-stack、Android Studio CPU Profiler 以及系统 tombstone 都能直接解析出函数名。6.3 补充runtime-mode 与 unopt 的底层映射结合 tools/gn 与 tools/gn 的源码可以理解调试构建的深层关系--unoptimized会直接映射到 GN 的is_debug见 tools/gn即未优化对应调试级构建--runtime-mode debug被映射为 Dart 运行时的develop模式dart_runtime_mode developjit_release映射为release其余模式profile/release则原样传递这些参数组合决定了 Dart VM 的快照类型与优化等级也因此决定了崩溃地址能否与下载的符号包对上——再次印证了符号必须与构建模式严格匹配这一原则。此外仓库的 common/exported_symbols.sym 展示了引擎在动态符号表中必须导出的符号如kDartVmSnapshotData、kDartIsolateSnapshotInstructions等这些符号用于运行时查找与静态调试符号是两套体系不会被--no-stripped影响读者在排查符号缺失时可作区分。七、总结符号化决策速查平台 / 场景符号来源符号化工具Android任意 Flutter 版本按 Engine revision 下载对应模式的symbols.zip需浏览器认证ndk-stack/addr2lineiOS ≥ 3.24artifact cache 内Flutter.xcframework的 dSYMXcode /atosiOS 3.24GCS 下载Flutter.dSYM.zipXcode /atosmacOS ≥ 3.27artifact cache 内FlutterMacOS.framework.dSYMXcode /atosmacOS 3.27GCS 下载FlutterMacOS.dSYM.zipXcode /atos本地引擎构建Androidgn --no-stripped GradledoNotStrip **/*.sondk-stack直接指向 out 目录本地引擎构建iOS/macOS debug/profile符号默认不剥离调试器直接可用实操中的三个铁律符号构建模式必须与崩溃应用一致、Build ID 必须匹配用file校验、日志必须完整优先adb logcat原始输出。遵循本文流程即可把一段pc 0x000000000062d6e0式的原始崩溃帧还原为可读的源码位置为定位与上报引擎级崩溃问题提供坚实依据。赞分享跨平台图形学前端【免费下载链接】engineThe Flutter engine项目地址https://gitcode.com/gh_mirrors/eng/engine点击查看免费下载相关推荐刘海屏菜单栏图标遮挡用 Ice 快速找回清爽的 Mac 菜单栏刘海屏菜单栏图标遮挡用 Ice 快速找回清爽的 Mac 菜单栏 打开 MacBook一排图标挤到刘海后面电池和时间只剩半截。Ice 是一款 macOS 菜桌面应用如何在iOS设备上实现KSCrash符号化解密崩溃堆栈的完整指南如何在iOS设备上实现KSCrash符号化解密崩溃堆栈的完整指南 KSCrash作为一款强大的iOS崩溃报告工具能够帮助开发者捕获和分析应用崩溃信息。本文将CLI开发工具Apple 平台 .ips 崩溃日志解析与 macOS .NET 符号获取全指南Apple 平台 .ips 崩溃日志解析与 macOS .NET 符号获取全指南 导读 本文围绕 dotnet diag 插件 https://link.git人工智能AI 技能AI 评测Benchmark开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表