适用范围:Flutter OHOS 平台(shell/platform/ohos)的渲染流程跟踪、白屏等渲染异常定位。
目标:帮助开发者和运维人员通过日志理解 Flutter 从启动到首帧渲染的完整流程,并快速定位渲染异常。
文档版本:v2(基于 oh-3.22.3-dev 分支 + 新增日志增强,已移除 WhiteScreenDFX 前缀)


一、渲染流程概览

Flutter OHOS 应用从启动到首帧上屏的完整流程:

[ArkTS] FlutterEntry / FlutterView
   │
   ├──> (1) OhosMain::Init ───────────────────────── ohos_main.cpp
   │        └─ 引擎初始化、渲染 API 选择
   │
   ├──> (2) OHOSShellHolder 创建 ─────────────────── ohos_shell_holder.cpp
   │        ├─ 线程创建 (raster/ui/io)
   │        ├─ Shell::Create
   │        └─ PlatformViewOHOS 创建
   │
   ├──> (3) XComponent Surface 回调 ──────────────── ohos_xcomponent_adapter.cpp
   │        ├─ OnSurfaceCreated (OS 触发)
   │        └─ PlatformViewOHOS::NotifyCreate
   │            └─ SetDisplayWindow → Rasterizer::Setup
   │
   ├──> (4) OHOSShellHolder::Launch ──────────────── ohos_shell_holder.cpp
   │        └─ 启动 Dart Engine、运行 isolate
   │
   ├──> (5) VsyncWaiter 创建 ─────────────────────── vsync_waiter_ohos.cpp
   │        └─ 注册 vsync 回调
   │
   ├──> (6) Dart scheduleFrame → 首帧请求 ────────── engine.cc
   │        └─ Animator::RequestFrame → AwaitVSync
   │
   ├──> (7) Vsync 回调 → BeginFrame ──────────────── animator.cc
   │        └─ Dart window.onBeginFrame → build → render
   │
   ├──> (8) Engine::Render ───────────────────────── engine.cc
   │        └─ 校验 layer_tree → Animator::Render
   │
   └──> (9) Rasterizer::Draw ─────────────────────── rasterizer.cc
            ├─ DoDraw → DrawToSurfaces → DrawToSurfaceUnsafe
            ├─ AcquireFrame → Raster → Submit
            └─ 首帧回调 → FlutterView.onFirstFrame

二、关键日志节点(按时序)

以下日志均使用 FML_LOG 输出,Release 版本可见。

阶段 1:引擎初始化

日志内容 级别 来源 含义
OhosMain init done, rendering_api=<api> INFO ohos_main.cpp 引擎初始化完成,api=2 表示 Vulkan Impeller

诊断要点

  • 若此日志未出现,检查引擎初始化失败(如 FML_CHECK 崩溃、资源加载失败)
  • rendering_api 值:1=OpenGL, 2=Vulkan, 3=Software

阶段 2:Surface 绑定

日志内容 级别 来源 含义
Rasterizer::Setup done, surface_valid=true/false INFO rasterizer.cc Rasterizer 已绑定 surface

诊断要点

  • 此日志表示 PlatformViewOHOS::NotifyCreateSetDisplayWindowRasterizer::Setup 链路成功
  • surface_valid=false,surface 存在但无效,后续 AcquireFrame 会失败
  • 注意:在 Impeller Vulkan 路径下,此日志可能不出现(surface 通过独立路径初始化),但不代表异常

阶段 3:Dart 渲染请求

日志内容 级别 来源 是否 Release 可见 含义
Render layer_tree IS NULL WARNING engine.cc Dart 传入的 layer_tree 为 null(严重异常)
engin Render frame_size is empty DLOG engine.cc ❌(仅 Debug) 启动时 viewport 未就绪,帧被跳过(预期内,非异常
engin Render device_pixel_ratio <= 0 DLOG engine.cc ❌(仅 Debug) 启动时 viewport 未就绪,帧被跳过(预期内,非异常

诊断要点

  • layer_tree IS NULL:Dart 侧出现严重错误,需检查 Dart 代码
  • frame_size is empty / device_pixel_ratio <= 0仅在 Debug 版本可见。启动早期(XComponent 就绪前)出现是正常时序,Release 版本不会输出

阶段 4:Rasterizer 渲染

日志内容 级别 来源 含义
rasterizer no surface, frame dropped (kNotSetUp). This is expected during startup before XComponent surface is ready. ERROR rasterizer.cc surface 未就绪,帧被丢弃(启动时预期内
GPU unavailable (sync switch), frame dropped ERROR rasterizer.cc GPU 被禁用(如后台切换),帧被丢弃
AcquireFrame returned null, surface_valid=... ERROR rasterizer.cc surface 有效但 AcquireFrame 失败(swapchain 失效)
compositor AcquireFrame failed ERROR rasterizer.cc Compositor 无法获取绘制帧

诊断要点

  • kNotSetUp仅在启动早期出现一次是正常的。若持续出现或出现在运行中,说明:
    • Rasterizer::Setup 未被调用(ArkTS 侧未调用 notifyCreate
    • Surface 被销毁后未重建(如后台/前台切换异常)
  • GPU unavailable:应用处于后台或 GPU 被系统回收,返回前台后应自动恢复
  • AcquireFrame null:surface 丢失或 GPU 资源不足,可能需要重启应用

三、正常启动日志示例

# 阶段 1: 引擎初始化
[INFO:ohos_main.cpp] OhosMain init done, rendering_api=2

# 阶段 2: XComponent 加载(ArkTS 侧日志)
[INFO:AceXcomponent] XComponent[oh_flutter_1] triggers onLoad and OnSurfaceCreated callback
[INFO:AceXcomponent] XComponent[oh_flutter_1] native OnSurfaceCreated

# 阶段 3: 启动时序竞争(可能出现,属正常)
[ERROR:rasterizer.cc] rasterizer no surface, frame dropped (kNotSetUp). This is expected during startup before XComponent surface is ready.

# 阶段 4: Surface 绑定成功
[INFO:rasterizer.cc] Rasterizer::Setup done, surface_valid=true

# (后续无新增 ERROR 日志 = 渲染正常)

四、异常场景诊断

场景 1:白屏(首帧迟迟不上屏)

诊断流程

  1. 检查引擎是否初始化

    • 搜索 OhosMain init done
    • 未出现 → 引擎初始化失败,查崩溃日志或 FML_CHECK
  2. 检查 XComponent 是否加载

    • 搜索 XComponent 相关日志(ArkTS 侧)
    • 未出现 → ArkTS 侧未触发 onLoad,检查 FlutterView 配置
  3. 检查 Surface 是否绑定

    • 搜索 Rasterizer::Setup done
    • 未出现 → NotifyCreate 未被调用,检查 ArkTS 侧是否调用 flutterView?.notifyCreate(nativeWindow)
  4. 检查是否有持续 kNotSetUp

    • kNotSetUp 日志持续出现(非仅启动时一次)
    • → Surface 绑定失败或持续丢失,检查 SetDisplayWindow 返回值
  5. 检查 GPU 是否可用

    • 搜索 GPU unavailable → 应用在后台或 GPU 被回收
  6. 检查 AcquireFrame 是否失败

    • 搜索 AcquireFrame returned null → swapchain 失效,检查 surface 生命周期

场景 2:启动后画面闪烁/花屏

诊断流程

  1. 检查 Rasterizer::Setup done, surface_valid=false

    • surface 无效但仍尝试渲染 → 检查 EGL/Vulkan 上下文创建日志
  2. 检查 ohos_surface_vulkan_impeller.cppohos_surface_gl_*.cpp 的 ERROR 日志

场景 3:后台返回后白屏

诊断流程

  1. 检查是否有 GPU unavailable 日志

    • 返回前台后应自动恢复,若持续出现 → Reclaim 状态机异常
  2. 检查 Rasterizer::Setup done 是否再次出现

    • 后台/前台切换应触发 surface 重建,若未出现 → ShouldRebuildOnscreenContext 返回 false
  3. 检查 PlatformViewOHOS reclaim 相关日志

场景 4:Dart 层初始化异常(新增)

诊断流程

  1. 检查 OhosMain init done 是否出现

    • 出现 → 引擎初始化成功
  2. 检查后续是否有 Rasterizer::Setup doneengine Render 等日志

    • OhosMain init done 后长时间无任何 Flutter 渲染相关日志
    • → 可能是 Dart 层 WidgetsBinding 初始化异常、runApp() 未执行、或 Platform Channel 阻塞
  3. 检查是否有 FlutterWatchdog: FlutterUiThread is not alive

    • 出现 → UI 线程阻塞,需检查 Dart 代码是否有死锁或长时间同步操作

典型案例

  • 自定义 WidgetsFlutterBinding 重写 initInstances() 导致初始化不完整
  • 插件在 initInstances() 中过早初始化,Platform Channel 未就绪
  • runApp() 未被调用或调用前发生异常

五、日志级别速查

日志前缀 级别 是否 Release 可见 出现场景
OhosMain init done INFO 引擎初始化完成
Rasterizer::Setup done INFO Surface 绑定成功
rasterizer no surface ERROR surface 未就绪(启动时一次为正常
GPU unavailable ERROR GPU 被禁用
AcquireFrame returned null ERROR swapchain 失效
compositor AcquireFrame failed ERROR Compositor 失败
Render layer_tree IS NULL WARNING Dart 传入 null(异常)
engin Render frame_size is empty DLOG ❌(仅 Debug) 启动时 viewport 未就绪(正常时序)
engin Render device_pixel_ratio <= 0 DLOG ❌(仅 Debug) 启动时 viewport 未就绪(正常时序)
FlutterWatchdog: FlutterUiThread is not alive ERROR UI 线程阻塞(10秒无响应)

六、常见问题 FAQ

Q1: 为什么启动时看到 rasterizer no surface, frame dropped (kNotSetUp),但应用正常?

A: 这是正常的启动时序。流程是:

  1. Dart 引擎先启动,开始请求帧
  2. XComponent 的 onLoad / OnSurfaceCreated 后触发
  3. 在 (2) 完成前,rasterizer 没有 surface,因此帧被丢弃
  4. 一旦 NotifyCreateRasterizer::Setup 完成,后续帧正常渲染

此日志仅打印一次,且带有说明文字 "This is expected during startup"

Q2: 为什么没有看到 Rasterizer::Setup done 日志,但画面正常?

A: 在使用 Impeller Vulkan 后端时,surface 可能通过独立路径初始化(不经过 Rasterizer::Setup)。此时:

  • Rasterizer::Setup 可能未被调用
  • 但 Vulkan surface 通过 OHOSurfaceVulkanImpeller 直接绑定到 XComponent
  • 只要 XComponent.onLoad 触发了 onSurfaceCreated(),Vulkan 路径就能正常工作

建议:ArkTS 侧仍应调用 flutterView?.notifyCreate(nativeWindow) 以确保所有路径兼容。

Q3: 启动时看到 Animator RequestFrame skipped (semaphore busy) 日志?

A: 此日志不存在于当前代码中animator.ccRequestFramepending_frame_semaphore_.TryWait() 失败时仅记录 TRACE_EVENT(用于 systrace 分析),不会输出任何 WARNING 级别日志。

若你在旧版本引擎中看到此日志,说明当时添加了额外的 FML_LOG(WARNING),该日志因启动时序竞争高频出现,已被移除。

Q4: 如何确认首帧真正渲染成功?

A:

  • Debug 版本:搜索 FlutterViewOnFirstFrame 日志
  • Release 版本:ArkTS 侧监听 FlutterView.onFirstFrame 回调
  • Rasterizer::Setup done 后出现且再无新增 ERROR 日志,说明渲染管线已通

Q5: 白屏时 OhosMain init done 后出现,但之后没有任何 Flutter 渲染日志?

A: 这说明 Dart 层初始化或执行异常,而非 Flutter Engine 渲染管线问题。可能原因:

  1. WidgetsFlutterBinding.ensureInitialized() 未正确调用
  2. 自定义 WidgetsFlutterBinding 重写了 initInstances() 导致初始化不完整
  3. runApp() 未被调用或调用前发生异常
  4. Platform Channel 在 Engine 未就绪时被调用,导致 Dart 侧阻塞

排查方向

  • 检查 Dart 层日志(print 输出)
  • 检查是否有 FlutterWatchdog: FlutterUiThread is not alive(10秒后出现)
  • 检查 ArkTS 侧是否正确调用了 flutterView?.notifyCreate(nativeWindow)

七、诊断 Checklist

遇到白屏或渲染异常时,按以下顺序检查:

□ 1. 搜索 "OhosMain init done" → 确认引擎初始化
□ 2. 搜索 "Rasterizer::Setup done" → 确认 surface 绑定(Impeller 可能无此日志)
□ 3. 搜索新增 ERROR 日志 → 定位具体失败点
□ 4. 检查 XComponent 生命周期日志(ArkTS 侧)→ 确认 onLoad/onSurfaceCreated
□ 5. 检查是否有持续的 kNotSetUp/GPU unavailable/AcquireFrame null
□ 6. 检查 ohos_surface_*.cpp 的 ERROR 日志 → GPU 上下文问题
□ 7. 检查 vsync_waiter_ohos.cpp 日志 → 帧调度问题
□ 8. 检查 FlutterWatchdog 日志 → UI 线程是否阻塞
□ 9. 若 OhosMain init done 后无任何渲染日志 → 检查 Dart 层初始化

八、附录:相关文件索引

模块 文件 关键功能
OHOS 入口 shell/platform/ohos/ohos_main.cpp 引擎初始化
Shell Holder shell/platform/ohos/ohos_shell_holder.cpp Shell 创建与启动
PlatformView shell/platform/ohos/platform_view_ohos.cpp Surface 绑定、生命周期
XComponent shell/platform/ohos/ohos_xcomponent_adapter.cpp OS Surface 回调
Vsync shell/platform/ohos/vsync_waiter_ohos.cpp 帧同步
Engine shell/common/engine.cc Dart 渲染请求处理
Animator shell/common/animator.cc 帧调度
Rasterizer shell/common/rasterizer.cc 渲染执行
SurfaceFrame flow/surface_frame.cc 帧提交

九、实战案例对比分析

案例:正常启动 vs 白屏启动日志对比

正常启动(4log.txt)

[INFO]  OhosMain init done, rendering_api=2
[WARN]  Unknown GPU Driver Vendor: 6629
[WARN]  engine Render frame_size is empty          ← Debug 可见,启动时序正常
[WARN]  engine Render device_pixel_ratio <= 0, dpr=1
[ERROR] cannot get pixelmap orientation:401        ← 图片解码警告
[ERROR] Failed to SetPresentInfo                   ← 上屏警告
[ERROR] FlutterWatchdog: FlutterUiThread is not alive  ← 10秒后出现

特征OhosMain init done 后有完整的渲染流程日志(engine Render、image decode、SetPresentInfo)。

白屏启动(3log.txt)

[INFO]  OhosMain init done, rendering_api=2
[WARN]  Unknown GPU Driver Vendor: 6629
[ERROR] FlutterWatchdog: FlutterUiThread is not alive  ← 10秒后出现

特征OhosMain init done没有任何 Flutter 渲染流程日志,10秒后出现 UI 线程阻塞。

诊断结论

对比项 正常启动 白屏启动 结论
OhosMain init 引擎初始化成功
engine Render 白屏时未执行到 Render
image decode 白屏时未加载图片
SetPresentInfo 白屏时未上屏
FlutterWatchdog 两者都有,非根因

根因推断:白屏场景下,Dart 层在 OhosMain init done完全卡死,未执行到 Engine::Render 阶段。这是典型的 Dart 层初始化异常,而非 Flutter Engine 渲染管线问题。

排查方向

  1. 检查 Dart 层 main() 是否执行
  2. 检查 WidgetsFlutterBinding.ensureInitialized() 是否正确调用
  3. 检查自定义 WidgetsFlutterBinding 是否重写了 initInstances()
  4. 检查是否有 Platform Channel 在 Engine 未就绪时被调用
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐