Files
HomeAgent/cmd
JianFeeeee 7bd569eccd fix(gui): 修「长时间挂后台后打开白屏」—— 补 renderer/GPU 崩溃自愈
## 实测故障

GUI 在后台挂很久(数小时)后,从托盘打开是**白屏**,且不会自愈 ——
重启进程才恢复。

本机现场证据:GPU 进程启动于 20:27:56,而主进程是 16:03:29 ——
GPU 进程在主进程运行 4 小时后重启过一次,正是长时间后台后 GPU context
被回收的实证。

## 原因链(三个洞叠加)

1. **没有任何崩溃监听**。全代码搜不到 render-process-gone /
   unresponsive / child-process-gone。renderer 被回收后全程无感知。

2. **窗口「可见」不等于「有内容」**。renderer 挂掉后窗口句柄仍在、
   isVisible() 返回 true,而 showMainWindow() 只判
   `if (!isVisible()) show()` ⇒ show() 被跳过 ⇒ 托盘点一下开出白窗口,
   永远不会好。

3. **ready-to-show 用了 once**。once 只等第一次首帧;窗口被系统回收后
   重建、或 GPU 重启后重新 load,那些路径都需要再 show 一次,
   once 让它们静默失败。

仓库历史上有过「白屏修复(惰性Tray)」提交,但那只修了**首次**显示时机,
没管**长期后台后**。

## 修复

- render-process-gone → reload 自愈;reason==='oom' 时**不** reload
  (内存不足时反复重载只会立刻再崩一次,把机器拖死)
- child-process-gone 且 type==='GPU' → reload 渲染进程
  (无边框窗口在GPU 重启后常停在上一帧/全白,与 renderer 崩溃表现重合
  但成因不同;不重建窗口,避免丢窗口位置与尺寸)
- showMainWindow() 加 webContents.isCrashed() 判定,为真则先 reload
- ready-to-show: once → on
- 通知点击路径改走 showMainWindow(),不再自己调 show()
  (原来的直接 show() 绕过健康检查,同样能开出白窗口)

## 判据(cmd/gui/window-liveness.test.mjs)

9 条,文本扫描(复现需「挂后台数小时 + renderer 被回收」,依赖驱动行为,
CI 不可靠)。覆盖:render-process-gone 监听、崩溃后有 reload、
OOM 不重载、GPU 崩溃监听、isCrashed 判定、判定后重载、
ready-to-show 用 on、无绕过健康检查的直接 show、通知点击走 showMainWindow。

变异测试验证非假红:删掉 isCrashed 分支 ⇒ 对应两条转红。

排障中判据自身报过 2 次假红,根因都写进注释:
  - sliceFunction 从 match 结果换成字符串后,残留的 showFn[0] 取到首字符
  - 注释里也写着 isCrashed(),纯字符串匹配命中注释而非代码
2026-10-05 21:56:14 +08:00
..