【DFX系列开篇】Flutter 鸿蒙应用崩了、卡了、发烫了-从哪里开始查
伴随着社区 3.41 版本的正式发布,面向 Flutter 鸿蒙开发者,我们规划了合计 11 篇 DFX 系列文章,按问题类型逐个展开,覆盖日志、崩溃、卡死、丢帧、时延、功耗、事件、内存、纹理、多设备等主题,带你整体了解 Flutter 鸿蒙在 DFX 上是怎么做的、怎么用的。本篇作为开篇,先打好基础。
一、DFX 是什么
DFX是为了提升软件质量属性的设计,目前主要包括可靠性和可测试性两大部分。鸿蒙系统上具体功能包括了流水日志、分布式跟踪、卡死故障检测和系统事件埋点,用来帮助开发者了解系统运行状态、定位和恢复故障。
落到Flutter鸿蒙平台上就是内置了一套自我监控:应用在崩溃、卡死、卡顿、内存泄漏发生时,DFX自动把日志和事件记下来,开发者拿这些记录定位原因。
DFX的作用接近飞机的黑匣子:平时不显眼,出问题后靠它还原现场。
二、三件工具和一个通道
OHOS 提供三套诊断工具,职责不重叠:
| 工具 | 记什么 | 类比 |
|---|---|---|
| HiLog | 系统日志,逐行文本 | 浏览器的 Console |
| HiAppEvent | 结构化事件,带参数 | Crashlytics的崩溃报告 |
| HiTrace | 性能追踪,记录每帧耗时 | Android 的 Systrace |
排查问题的第一步永远是抓HiLog-大部分问题的线索都在日志里。HiAppEvent 和 HiTrace 在你需要结构化分析信息或逐帧分析时会用上,对应分析工具可以使用DevEco Studio的Profiler工具或者开源的HiSmartPerf性能工具,这块比较专业了,后面有诉求可以专门写各专栏。
日志来自三个源头,过滤时用得上:
| 来源 | Tag | 典型内容 |
|---|---|---|
| 引擎内部(FML_LOG) | 映射到 HiLog | 崩溃堆栈、卡死检测、GPU 回收 |
| 平台 C++ 层 | XComFlutterOHOS_Native | 引擎初始化、NAPI 调用 |
| ETS 嵌入层 | Flutter | MethodChannel、插件异常、生命周期 |
一条命令看全部 Flutter 日志:
hdc shell hilog | grep -E "Flutter|XComFlutter|flutter"
这条命令把三个源头的日志一起筛出来,不确定问题类型时可以先用它。
再说下hdc(OHOS Device Connector),它是鸿蒙版的adb,负责在电脑和设备之间传文件、执行命令。后面所有命令都通过它执行,下面是三个常用的命令:
# 查看已连接的设备hdc list targets# 在设备上执行命令hdc shell <命令>
# 从设备拉取文件到电脑hdc file recv <设备路径> <电脑路径>
第一条确认设备在线
第二条是所有排查命令的载体
第三条把设备上的日志和 trace 文件拉回电脑分析
三、Flutter 鸿蒙应用通常的卡顿点在哪?
Flutter鸿蒙的卡顿问题,往往最终都定位以下三条线程上:
| 线程 | 职责 | 出问题时的表现 |
|---|---|---|
| UI 线程 | 运行 Dart 代码,构建 Widget 树 | 界面完全冻结,触摸无响应 |
| Raster 线程 | 把 Widget 树绘制成像素,交给 GPU | 界面不更新,触摸可能有响应 |
| Platform 线程 | 和 OHOS 系统交互,处理触摸、系统消息 | 平台通道阻塞,可能间接卡 UI |
前三个阶段在 UI 线程,Dart 代码慢会在这里超时。
Composite 在 Raster 线程,大图、模糊、大量图层会让这里超时。
每个阶段可用的时间由屏幕刷新率决定,这个时间叫帧预算:
| 屏幕刷新率 | 帧预算 | 含义 |
|---|---|---|
| 60Hz | 16.6 ms | 每帧 16.6 毫秒内画完 |
| 90Hz | 11.1 ms | 每帧 11.1 毫秒内画完 |
| 120Hz | 8.3 ms | 每帧 8.3 毫秒内画完 |
某一帧没在预算内画完,这帧就丢了,用户看到的是「卡了一下」。帧预算的直观感受接近翻页动画书:每秒翻 60 页动画才连贯,某一页翻了 50 毫秒,画面就停一下。
到这里,卡顿排查的第一步已经明确:确认哪条线程超时
UI 线程超时查 Dart 代码的 build/layout/paint,Raster 线程超时查绘制复杂度,逐帧的分析方法和触摸到上屏的完整链路。
四、分清是哪一种「卡」
在Flutter鸿蒙应用开发中,用户口中的「卡」多数是这两个出了问题:
| 指标 | 定义 | 感受阈值 |
|---|---|---|
| 响应时延 | 从触摸到首个画面反馈的时间 | 超过 100ms 觉得迟钝 |
| 完成时延 | 从操作到整个操作彻底完成的时间 | 视场景而定 |
两者的成因不同:响应时延慢,多数是主线程被阻塞;完成时延慢,多数是数据加载慢或首屏构建太大。
五、故障速查清单
以下是梳理的一版故障速查清单,具体的讲解后续都会进行介绍,大家先期待下:
| 看到的现象 | 可能的问题 |
|---|---|
| 应用闪退、崩溃 | Native 崩溃 / Dart 异常 / ETS 异常 |
| 应用卡死、无响应、点不动 | 线程卡死(UI/Raster/Platform) |
| 界面卡顿、滑动不流畅 | 丢帧/JANK(帧率不够) |
| 点了按钮反应慢、跟手性差 | 响应时延过长(主线程被阻塞) |
| 页面打开白屏太久才出内容 | 完成时延过长(首屏构建/数据加载慢) |
| 发烫、耗电快、CPU 持续高占用 | 负载异常 / 后台功耗 |
| 内存占用过高、OOM 闪退 | Dart Heap 内存超限 |
| 黑屏、白屏、渲染异常 | GPU 上下文丢失 |
| 视频/相机画面黑屏、不更新、卡顿 | 外接纹理问题 |
| 分栏不生效/避让失效/折叠屏异常 | 多设备适配问题 |
| 不确定是什么问题 | 先抓全量日志 |
六、万能第一步:把日志抓下来
破案要先保护现场,排查问题也是同理。
不管什么问题,先按四步把日志抓下来:
# 1. 清空历史日志,只留复现后的新日志hdc shell hilog -r
# 2. 复现问题(操作应用,触发 bug)
# 3. 抓取日志,Ctrl+C 停止hdc shell hilog > flutter_log.txt
# 4. 筛出 Flutter 相关内容hdc shell hilog | grep -E "Flutter|XComFlutter|flutter"
顺序也要关注下:先清理历史日志再复现,这样日志里只有本次问题的记录,搜索范围小得多,抓完的全量日志留底,筛过的日志用来定位。
已知问题类型时,直接按类型过滤,噪音会少很多。
常用的关键命令行分组如下:
# 崩溃(应用闪退)
hdc shell hilog | grep -E "Caught signal|Unhandled Exception|FLUTTER_DART_EXCEPTION|FLUTTER_ETS_EXCEPTION"
# 卡死(应用无响应)
hdc shell hilog | grep -E "FlutterWatchdog|not alive|HiCollie|THREAD_STUCK"
# 卡顿/丢帧(界面不流畅)
hdc shell hilog | grep -E "JANK|jank|missed|frame"
# 内存(OOM、内存占用高)
hdc shell hilog | grep -E "heap memory|memory|OOM|threshold"
# GPU(黑屏、白屏)
hdc shell hilog | grep -E "GpuReclaim|GPU|gpu"
# 外接纹理(视频/相机画面异常)
hdc shell hilog | grep -E "external_texture|ExternalTexture|NativeImage|DlImage|frame gate|VisibleArea|texture_id"
# 多设备适配(分栏、折叠屏等)
hdc shell hilog | grep -E "SplitView|split_view|avoidArea|displayFeature|foldStatus|device pixel ratio|windowSizeChange|LTPO"
界面卡顿但日志看不出问题时,就得抓性能 Trace了,简单一些可以用 Chrome 打开 chrome://tracing 加载进行分析:
hdc shell hitrace --trace_clock boottime -t 10 flutter -o /data/local/tmp/trace.ftrace
hdc file recv /data/local/tmp/trace.ftrace ./trace.ftrace
更专业的可以使用 HiSmartPerf 性能调优工具,使用方式和功能基本对标了Android 的Perfetto,性能领域专家可以重点关注下。
七、日志里搜什么:关键字与事件
日志打印后,可以按这张表搜关键字,快速判断问题类型:
| 关键字 | 问题类型 | 含义 |
|---|---|---|
| Caught signal SIGSEGV | 引擎崩溃 | 访问非法内存,比如空指针 |
| Caught signal SIGABRT | 引擎崩溃 | 内部断言失败或内存被破坏 |
| Unhandled Exception: | Dart 异常 | 代码有未 try-catch 的异常 |
| is not alive | 卡死 | 某个线程 3 秒没响应 |
| Dart heap memory usage exceeds threshold | 内存超限 | Dart 内存超过 1.5 GB |
| GpuReclaim + kAggressive | GPU 回收 | 系统回收 GPU 资源(退后台时正常) |
| GpuReclaim + kRestore | GPU 恢复 | 资源恢复中(回前台时正常) |
| Poll error: | 消息循环异常 | 系统消息循环出错,可能导致卡死 |
| AwaitVSync…failed | VSync 失败 | 垂直同步信号请求失败,可能导致不渲染 |
| No DlImage available | 外接纹理 | 纹理没有可绘制的画面(黑屏) |
| frame gate enabled | 外接纹理 | 应用在后台,纹理帧被暂停(正常) |
| skip one frame | 外接纹理 | 画面生产太快,跳过了一些帧 |
引擎自动上报的 HiAppEvent 事件对应同一套问题分类:
| 事件 | 含义 |
|---|---|
| FLUTTER_DART_EXCEPTION | Dart 代码 bug 导致崩溃 |
| FLUTTER_ETS_EXCEPTION | ArkTS 插件代码 bug |
| OTHER_JANK | 某一帧渲染太慢 |
| OTHER_JANK_STAT | 一段时间的丢帧汇总 |
| OTHER_JANK_SCROLL | 滑动时某帧超过 50ms |
| FrameworkMemAnomaly | Dart 内存超过 1.5 GB |
| FLUTTER_THREAD_STUCK | 某个线程卡死 |
| FLUTTER_GPU_CONTEXT_LOSS | GPU 资源被系统回收 |
| FLUTTER_ENGINE_CREATE / DESTROY | 引擎被创建或销毁 |
后三个是 FLUTTER_STABILITY_EVENT 的子类型,是通过 eventName 字段进行区分的,事件参数的完整说明后续篇章会细讲。
八、版本边界与文档索引
值得注意的是,部分上报能力有系统版本要求的,事件搜不到时先查这里:
| 功能 | 最低版本 | 低于此版本 |
|---|---|---|
| HiAppEvent 事件上报 | API 18 | 不生成事件,HiLog 仍可用 |
| HiTrace 扩展接口 | API 19 | 丢帧详情,Trace 不可用 |
| 内存异常上报(FrameworkMemAnomaly) | API 26 | 不上报事件,HiLog 仍可用 |
这个系列是结合了最近3.41版本发布整体规划的 ,共计 11 篇:
01 开篇 → 02 日志抓取与过滤 → 03 崩溃定位 → 04 卡死冻屏 → 05 丢帧卡顿 → 06 滑动卡顿与时延深度 → 07 负载与功耗 → 08 DFX 事件字典 → 09 内存与 GPU → 10 外接纹理 → 11 多设备适配
期待下第二篇:日志抓取与过滤 - 从 hilog 到 HiTrace。
小伙伴们记得关注我,关注 CPF-Flutter 社区!
社区官网:https//atomgit.com/CPF-Flutter
“AI再牛,技术不能丢”
更多推荐




所有评论(0)