ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Flutter OH 卡死冻屏问题定位指南

Flutter OH 卡死冻屏问题定位指南 卡死冻屏问题定位指南返回 Flutter OH平台 DFX 问题定位导航1. 什么是应用卡死应用卡死AppFreeze就是应用冻住了——界面不更新、点按钮没反应、滑动没效果。就像电脑死机一样。Flutter 应用有三个关键线程可以理解为三个工人任何一个罢工了都会导致卡死线程工人负责什么卡死时的表现严重程度UI 线程运行你的 Dart 代码、构建界面界面完全冻结触摸无响应致命Raster 线程画画的工人把界面画成像素交给 GPU界面不更新但触摸可能有响应严重Platform 线程和系统打交道的工人处理触摸事件、系统消息系统消息阻塞可能间接卡 UI严重新手提示UI 线程卡死是最严重的6 秒后系统可能会弹出应用无响应弹窗或直接杀掉你的应用Raster 线程阻塞不会直接被检测到但会导致帧画不出来间接把 UI 线程也拖死Platform 线程阻塞会导致系统消息触摸、键盘等无法处理1.1 卡死检测机制引擎怎么知道卡死了Flutter 引擎内置了一个看门狗Watchdog就像一个巡逻保安保安每 3 秒巡逻一次 │ ├─ 给 UI 线程发一个签到请求 │ └─ 3 秒后检查 ├─ UI 线程签到了 → 正常继续巡逻 └─ UI 线程没签到 → 卡死了触发报警 ├─ 卡死 3 秒 → 记录一次事件不弹窗 └─ 卡死 6 秒 → 上报系统可能弹无响应弹窗注意看门狗直接监控的是UI 线程。Raster 和 Platform 线程阻塞会间接导致 UI 线程卡死比如 Raster 不画帧UI 线程等着提交帧也卡住了最终被 UI 线程的看门狗检测到。1.2 两阶段上报3 秒和 6 秒的区别阶段卡死时间会发生什么用户能看到吗第 1 阶段3 秒记录到日志不弹窗用户可能感觉到卡但没弹窗第 2 阶段6 秒上报系统可能弹应用无响应弹窗用户看到弹窗可选择等待或关闭2. 怎么定位卡死问题2.1 快速定位流程应用卡死了 │ ├─ 在日志里搜索 is not alive │ └─ 搜到了 FlutterUiThread is not alive → UI 线程卡死了 → 看 §3 │ ├─ 在日志里搜索 FLUTTER_THREAD_STUCK │ └─ 搜到了 → 看门狗检测到卡死看 description 确定哪个线程 │ ├─ 在日志里搜索 APP_FREEZE │ └─ 搜到了 → UI 线程卡死超过 6 秒系统要杀进程了 │ └─ 找间接原因为什么卡死 ├─ 搜索 GpuReclaim → GPU 回收导致 Raster 阻塞 → 看 §4 ├─ 搜索 handlePlatformMessage → 平台通道阻塞 → 看 §5 └─ 搜索 external_texture → 纹理回调阻塞 → 看 §4最关键的一步一定要看卡死前 5-10 秒的日志卡死的原因通常在看门狗报警之前就发生了。就像查车祸事故要看撞车前的行车记录仪。3. UI 线程卡死3.1 怎么确认是 UI 线程卡死搜索命令hdc shell hilog|grep-EFlutterUiThread|FlutterWatchdog|HiCollie典型日志你会看到这样的内容[T3s] E Flutter: FlutterWatchdog: FlutterUiThread is not alive [T3s] W Flutter: FlutterWatchdog: calling OH_HiCollie_Report(), m_is_six_second_event false [T3s] I Flutter: FlutterWatchdog: OH_HiCollie_Report() success [T3s] HiAppEvent: FLUTTER_STABILITY_EVENT, eventNameFLUTTER_THREAD_STUCK description: Flutter UI thread stuck. isSixSecondEventfalse [T6s] E Flutter: FlutterWatchdog: FlutterUiThread is not alive [T6s] W Flutter: FlutterWatchdog: calling OH_HiCollie_Report(), m_is_six_second_event true [T6s] HiAppEvent: FLUTTER_STABILITY_EVENT, eventNameFLUTTER_THREAD_STUCK description: Flutter UI thread stuck. isSixSecondEventtrue [T6s] 系统生成 APP_FREEZE 事件可能弹出应用无响应弹窗怎么读这些日志FlutterUiThread is not alive→ UI 线程 3 秒没响应了m_is_six_second_event false→ 第 1 阶段卡死 3 秒只记录不弹窗m_is_six_second_event true→ 第 2 阶段卡死 6 秒可能弹窗APP_FREEZE→ 系统级卡死事件可能杀进程3.2 具体现象你看到的现象严重程度说明界面完全冻结点哪里都没反应致命UI 线程被长时间阻塞6 秒后弹出应用无响应弹窗致命系统级 APP_FREEZE 触发卡了一会儿后自动恢复中3 秒阶段记录但 6 秒前恢复了3.3 怎么排查第 1 步搜索卡死日志hdc shell hilog|grep-EFlutterUiThread|FlutterWatchdog|FLUTTER_THREAD_STUCK第 2 步看卡死前的日志这一步最重要hdc shell hilogflutter_log.txt# 在日志文件中找到 is not alive 的行往上翻 5-10 秒的日志# 那里面通常藏着卡死的罪魁祸首第 3 步抓取 HiTrace 分析如果能复现hdc shell hitrace--trace_clockboottime-t30flutter-o/data/local/tmp/trace.ftrace hdcfilerecv /data/local/tmp/trace.ftrace ./trace.ftrace# 用 Chrome 打开 chrome://tracing → Load 文件# 搜索 feedFlutterWatchdog 检查心跳是否中断3.4 常见原因和修复方法原因 1Dart 代码里有死循环或死锁通俗解释你的代码陷入了无限循环或者两个锁互相等待UI 线程就永远跑不出来了。修复方法// ❌ 错误死循环condition 永远不为 truewhile(true){if(condition)break;}// ❌ 错误死锁两个锁互相等// 线程 A 拿了锁 1等锁 2// 线程 B 拿了锁 2等锁 1// → 两个线程永远等下去// ✅ 正确避免嵌套锁加超时awaitlock.synchronized(()async{awaitsomeWork();},timeout:Duration(seconds:5));原因 2在主线程做了耗时操作文件读写、网络请求通俗解释UI 线程就像收银台如果你在收银台慢慢数钱后面排队的人就都卡住了。修复方法// ❌ 错误在主线程同步读大文件finaldataFile(large_file.json).readAsStringSync();// 阻塞 UI// ✅ 正确用异步 IOfinaldataawaitFile(large_file.json).readAsString();// 不阻塞// ✅ 正确用 compute() 把耗时任务放到独立线程finaldataawaitcompute(_readFile,large_file.json);// ✅ 正确分批处理大数据for(vari0;ilist.length;ibatchSize){// 处理一批awaitFuture.delayed(Duration.zero);// 让 UI 有机会响应}原因 3复杂计算任务阻塞 UI 线程通俗解释你在主线程里处理 10 万条数据当然会卡。修复方法// ❌ 错误在 UI 线程处理 10 万条数据ListDataparseData(Stringjson){finallistjsonDecode(json)asList;returnlist.map((e)Data.fromJson(e)).toList();// 10 万条会卡死}// ✅ 正确用 compute 移到独立 isolatefinaldataawaitcompute(_parseData,json);原因 4等待锁/信号量但持有者不释放通俗解释你等着用洗手间但里面的人不出来可能崩溃了你就永远等着。修复方法// ❌ 错误无超时等待awaitlock.synchronized(()async{// 如果持有者崩溃了锁永远不释放});// ✅ 正确加超时awaitlock.synchronized(()async{// ...},timeout:Duration(seconds:5)).catchError((e){print(锁超时:$e);returnnull;});4. Raster 线程阻塞画画的工人卡了Raster 线程负责把界面画成像素。它卡了不会直接被看门狗检测到但会导致帧画不出来最终把 UI 线程也拖死。4.1 怎么排查搜索命令# 搜索 GPU 相关日志GPU 回收经常导致 Raster 阻塞hdc shell hilog|grep-EGpuReclaim|Teardown|SetDisplayWindow|Surface# 搜索外接纹理相关日志hdc shell hilog|grep-Eexternal_texture|NativeImage|AcquireNativeWindowBuffer抓取 HiTrace 检查 Raster 心跳hdc shell hitrace--trace_clockboottime-t30flutter sched-o/data/local/tmp/trace.ftrace# 在 Chrome 中搜索 feedFlutterRasterWatchdog 检查 Raster 心跳# 搜索 flutter::Frame 检查帧渲染耗时4.2 常见原因和修复方法原因通俗解释怎么修GPU 管线阻塞GPU 忙不过来了详见 Flutter OH 内存与 GPU 问题定位指南 §3Vulkan 渲染开销大Vulkan 后端渲染太慢简化场景或切 OpenGL ES纹理回调阻塞纹理的画面传送带卡了详见 Flutter OH 外接纹理问题定位指南 §4图层太多一帧要画太多层减少 Layer 数量用RepaintBoundaryGPU 回收期间阻塞系统回收 GPU 时 Raster 被卡等待Surface REBUILT后再渲染5. Platform 线程阻塞和系统打交道的工人卡了Platform 线程负责和 OHOS 系统交互处理触摸事件、系统消息等。它卡了会导致系统消息无法处理。5.1 怎么排查搜索命令hdc shell hilog|grep-EhandlePlatformMessage|onTouchEvent|MethodChannel|DartMessenger5.2 常见原因和修复方法原因 1ArkTS 插件处理 MethodChannel 消息时太慢通俗解释Platform 线程收到 Dart 发来的消息后会同步调用 ArkTS 插件处理。如果插件处理太慢比如同步读文件Platform 线程就卡住了。修复方法ArkTS 插件代码// ❌ 错误在 onMethodCall 里同步读文件onMethodCall(call:MethodCall,result:MethodResult):void{constdatafs.readFileSync(path);// 阻塞result.success(data);}// ✅ 正确用异步 IOasynconMethodCall(call:MethodCall,result:MethodResult):Promisevoid{try{constdataawaitfs.readFile(path);// 不阻塞result.success(data);}catch(e){result.error(IO_ERROR,e.message,null);}}原因 2Platform 线程等待 Raster 线程同步等待引擎中有 6 处地方会让 Platform 线程同步等待 Raster 线程完成。如果 Raster 线程正忙Platform 线程就会卡住。这些等待发生在以下操作中Surface 窗口变化NotifySurfaceWindowChanged窗口尺寸变化NotifyChanged引擎销毁NotifyDestroyed纹理注销UnRegisterExternalTexture纹理替换SetExternalNativeImage纹理重置ResetExternalTexture修复方法这些是引擎内部的同步等待开发者能做的是避免在 Raster 线程繁忙时触发这些操作。原因 3触摸事件处理太慢Platform 线程还负责分发触摸事件。如果触摸事件处理太慢会阻塞 Platform 线程。修复方法确保 ArkTS 侧的触摸事件处理是轻量的不要在触摸回调里做耗时操作。6. 日志关键字速查表搜索这个关键字含义什么时候出现FlutterUiThread is not aliveUI 线程卡死了UI 卡死时每次都有calling OH_HiCollie_Report()正在上报关卡UI 卡死时OH_HiCollie_Report() success上报成功UI 卡死时m_is_six_second_event false第 1 阶段卡死 3 秒卡死 3 秒时m_is_six_second_event true第 2 阶段卡死 6 秒卡死 6 秒时thread may be blocked, do not report防误报跳过高负载时偶尔出现正常FLUTTER_THREAD_STUCK卡死事件每次卡死上报APP_FREEZE系统级卡死事件卡死 6 秒时GpuReclaimGPU 回收卡死的间接原因GPU 相关卡死handlePlatformMessage平台消息卡死的间接原因Platform 阻塞7. HiAppEvent 事件7.1 FLUTTER_THREAD_STUCK事件名FLUTTER_STABILITY_EVENT类型FAULTeventNameFLUTTER_THREAD_STUCK参数说明frameworkName固定FLUTTEReventName固定FLUTTER_THREAD_STUCKdescription告诉你是哪个线程卡死了、卡了多久pid进程 IDtimeStamp事件时间description 怎么读description 内容通俗解释Flutter UI thread stuck. isSixSecondEventfalseUI 线程卡了 3 秒还没弹窗Flutter UI thread stuck. isSixSecondEventtrueUI 线程卡了 6 秒可能弹窗了Flutter Raster thread stuck. isSixSecondEventfalseRaster 线程卡了Flutter Platform thread stuck. isSixSecondEventfalsePlatform 线程卡了7.2 系统级 APP_FREEZE当 UI 线程卡死 6 秒时系统会生成APP_FREEZE事件。这是系统级的由 HiCollie 服务直接生成。可能导致应用无响应弹窗用户可选等待或关闭系统自动杀进程8. 排查清单第一步确认卡死抓取全量日志hdc shell hilog flutter_log.txt搜索is not alive确认哪个线程卡死搜索FLUTTER_THREAD_STUCK查看事件详情搜索APP_FREEZE确认是否触发系统事件查看卡死前 5-10 秒的日志最重要第二步找原因搜索GpuReclaim→ 是否 GPU 回收导致搜索external_texture→ 是否纹理回调阻塞搜索handlePlatformMessage→ 是否平台通道阻塞检查 Dart 代码是否有死循环/死锁检查是否有同步 IO/网络请求在主线程检查是否有复杂计算阻塞 UI 线程第三步HiTrace 分析抓取 Tracehdc shell hitrace --trace_clock boottime -t 30 flutter搜索feedFlutterWatchdog检查 UI 心跳搜索feedFlutterRasterWatchdog检查 Raster 心跳搜索flutter::Frame查看帧渲染耗时记录卡死时的操作场景9. Trace 分析技巧9.1 正常的心跳健康的正常情况下feedFlutterWatchdog每 3 秒出现一次就像心电图一样规律[0.0s] feedFlutterWatchdog ← UI 心跳 ✓ [0.0s] feedFlutterRasterWatchdog ← Raster 心跳 ✓ [3.0s] feedFlutterWatchdog ← UI 心跳 ✓ [3.0s] feedFlutterRasterWatchdog ← Raster 心跳 ✓9.2 异常的心跳卡死了如果 UI 线程卡死心跳就断了[0.0s] feedFlutterWatchdog ← 最后一次正常心跳 [3.0s] runHiCollieStuckDetectionTask ← 保安发现 UI 没签到 [6.0s] runHiCollieStuckDetectionTask ← 还是没签到触发 6 秒报警 feedFlutterWatchdog 不再出现 UI 线程卡死了9.3 抓取和分析 Trace# 抓取 30 秒的 Trace在这 30 秒内复现卡死hdc shell hitrace--trace_clockboottime-t30flutter-o/data/local/tmp/trace.ftrace hdcfilerecv /data/local/tmp/trace.ftrace ./trace.ftrace# 用 Chrome 浏览器打开# 访问 chrome://tracing → 点击 Load → 选择 trace.ftrace# 快捷键w 放大、s 缩小、a 左移、d 右移
返回列表