# Geph GUI 白屏 —— WebKitWebProcess 占满 100% CPU 死循环(Linux/Flatpak)

> 本文件是英文版 `geph-gui-blank-webview-bug-report.md` 的中文对照版,留档自用。
> 提交 issue 时用英文版,这份方便自己回顾和向别人解释。

**组件:** Flatpak GUI(`io.geph.GephGui`,`gephgui-wry` / Wry + WebKitGTK)
**受影响版本:** 首次出现于 5.9.0,5.9.1 依旧。5.9.0 之前正常。
**严重程度:** GUI 完全不可用。隧道本身不受影响。
**平台范围:** 目前仅 Linux 桌面出现。Windows 和 Android 未复现 —— 注意这两者用的都是
Chromium 系 WebView,而 Linux 桌面是唯一使用 WebKitGTK 的平台,**所以"只有 Linux 出问题"
恰恰是 WebKit 特有故障的典型特征**。

> **定性说明:** 本报告**不**声称是 5.9.0 单独引入的代码回归。故障是在安装 5.9.0 **叠加**
> 之后的一次系统/runtime 刷新后才出现的,且其他平台未见。最可能的情况是 **5.9.x 新前端与
> 特定 Linux/WebKit 环境之间的交互问题**。以下证据如实呈现,供维护者判断。

---

## 摘要

GUI 能打开窗口,标题栏正常,但**内容区一片纯白**。WebKit 的渲染进程
(`WebKitWebProcess`)从启动起就陷入**纯用户态忙循环,稳定占满一个 CPU 核心 100%**,永不
停止。没有崩溃、没有 stderr 输出、journal 里也没有任何报错。

隧道守护进程是独立的 systemd 服务,工作完全正常 —— 坏的只有 GUI 这一层。

---

## 环境

| 项目 | 值 |
|---|---|
| 系统 | Ubuntu 26.04.1 LTS,内核 7.0.0-34-generic |
| 桌面 | GNOME Shell 50.1,**Wayland** 会话 |
| CPU / GPU | Intel Meteor Lake-P,Intel Arc 核显(i915 / xe 驱动) |
| Geph 安装 | Flatpak,`io.geph.GephGui`,分支 `master`,commit `ee6081f9`(2026-09-27) |
| Runtime | `org.gnome.Platform/x86_64/50`(WebKitGTK `libwebkit2gtk-4.1.so.0.24.3`) |
| 沙箱权限 | `sockets=x11;wayland;`、`devices=dri;` —— GPU 设备访问已验证可用 |
| 隧道守护进程 | `geph-manager.service`(systemd)—— **工作正常** |

### 时间线

| 时间 | 事件 |
|---|---|
| 9/20 之前 | GUI 正常 |
| 2026-09-20 01:54 | Geph 升级到 5.9.0(Flatpak 部署) |
| 2026-09-20 09:11–09:14 | **Flatpak 更新了 `org.gnome.Platform` 50 与 Locale 50**(约 7 小时后) |
| 2026-09-24 … 09-27 | 内核更新;09-26 更新了 `xserver-common` |
| 2026-09-27 | 升级 Geph 到 5.9.1 试图解决此问题 —— **无效** |
| 2026-09-28 12:11 | Geph 与 runtime 再次更新 —— **仍然白屏** |

用户回忆:白屏**不是**装完 5.9.0 立刻出现的,而是那次安装 **叠加** 之后的一次系统/runtime
刷新之后才出现。

---

## 症状

1. 窗口正常打开,标题栏与窗口装饰渲染正常;
2. 内容区永久纯白;
3. `WebKitWebProcess` 持续占满 100% CPU(实测:5 秒墙钟消耗 503 jiffies,即整整一个核心);
4. **没有**任何标准输出/错误输出、无崩溃、journal 无记录;
5. 每次重新打开窗口都伴随 GTK 警告:
   `gtk_widget_get_scale_factor: assertion 'GTK_IS_WIDGET (widget)' failed`
6. 杀掉 GUI 进程重启,症状每次必现。

---

## 证据

### 1. 这是用户态忙循环,不是阻塞或 I/O 等待

```
3 秒内自愿上下文切换差值: 0
```

在烧满一个核心的同时自愿上下文切换为 0,意味着进程**从不进入内核** —— 没有系统调用、没有
睡眠。这是一个纯粹的 CPU 自旋(JSC 下紧循环 JS 的典型特征),不是死锁,也不是在等 I/O、
IPC 或 GPU fence。

### 2. 与渲染 / GPU 路径无关

以下每个设置都通过 `flatpak override --user --env=...` 注入,并**已核实变量确实出现在**
渲染进程的 `/proc/<pid>/environ` 中。**没有一个能改变症状**(始终 503 jiffies / 5 秒):

| 设置 | 目的 | 结果 |
|---|---|---|
| `WEBKIT_DISABLE_DMABUF_RENDERER=1` | 绕过 DMABUF 零拷贝路径 | 无变化 |
| `WEBKIT_DISABLE_COMPOSITING_MODE=1` | 禁用加速合成 | 无变化 |
| `GDK_BACKEND=x11` | 退回 XWayland | 无变化 |
| `JSC_useJIT=0` | 禁用 JavaScriptCore JIT | 无变化 |

### 3. 不是 WebKit **版本** 的回归

在两个 runtime 上复现**完全一致**,并通过进程实际的挂载信息(`/proc/<pid>/mountinfo`)
确认旧 runtime 确实生效:

| Runtime | WebKitGTK | `libwebkit2gtk-4.1.so` | 结果 |
|---|---|---|---|
| `org.gnome.Platform//50` | 2.50+ | `0.24.3` | 100% CPU 自旋 |
| `org.gnome.Platform//47` | 2.46 | `0.19.4` | **100% CPU 自旋(完全一致)** |

### 4. 沙箱内 GPU 访问正常

从沙箱内部验证:`/dev/dri/renderD128` 与 `/dev/dri/card1` 均可成功打开。排除设备权限问题。

### 5. 前端代码本身在 Blink 下运行正常 —— 只在 JavaScriptCore 下崩

GUI 前端由 `gephgui-wry` 通过本地 HTTP(`http://127.0.0.1:5678`)提供。
用 Chromium 加载**完全相同的 URL** 一切正常:页面标题更新为「迷雾通」、Svelte 应用挂载
成功、组件样式被注入。

### 6. 可疑点:所服务的 HTML 只有 "legacy" 入口

```html
<title>Vite + Svelte + TS</title>
<script id="vite-legacy-polyfill" src="./assets/polyfills-legacy-DtlIMfjT.js"></script>
<script id="vite-legacy-entry"
        data-src="./assets/index-legacy-B_jLTHuj.js">System.import(...)</script>
```

* 这是 `@vitejs/plugin-legacy` 的产物;
* **完全没有 `<script type="module">` 现代入口** —— 所有引擎,包括完全现代的引擎,都被
  强制走 legacy(SystemJS + core-js)路径;
* 也没有 `nomodule` 属性,因此 polyfill 是无条件加载的;
* `polyfills-legacy-*.js`(171 KB)内含 core-js;`index-legacy-*.js` 为 978 KB;
* 探测现代版同名文件(`index-B_jLTHuj.js`)返回 404 —— 只发布了 legacy 构建。

**假设(未证实):** core-js 的 legacy polyfill,或 SystemJS 加载器,在 JavaScriptCore 下
进入死循环。这与上述所有观察一致 —— 纯用户态自旋、与图形栈无关、与 WebKit 版本无关。

---

## 未能排除的因素

明确说明本次排查的边界:

* **上述所有对照实验都在"当前已更新过的系统"上进行。** 它们排除了"runtime / WebKit 版本"
  这个变量,但**无法**排除系统层面(内核、X server、驱动)的贡献,因为没有一个"更新前的
  系统状态"可供对照测试。
* 唯一反对"系统层面致病"的结果:同一页面在**同一套内核、X server 和驱动**下用 Chromium
  打开是正常的。
* core-js 假设**无法**通过直接干预证实,因为 Flatpak 应用文件是只读的,既不能修改该 bundle,
  也无法替换成现代构建。
* **降级 Geph 的方案被有意排除**:5.9.0 为应对一次安全事件修改了账号机制,装回 5.9.0 之前的
  版本等于退回旧的账号机制。

---

## 影响

GUI 100% 不可用。用户无法通过界面连接、切换出口或修改设置。

---

## 变通方案

随包分发的 `geph5` 二进制是一个完整的命令行客户端,**且不需要 root**:

```bash
geph5 status                            # 查看状态
geph5 connect                           # 建立隧道
geph5 disconnect                        # 断开隧道
geph5 exits                             # 列出可用出口
geph5 exit-constraint set "<名称>"       # 切换出口偏好
geph5 logs                              # 查看引擎日志
```

因为隧道由 `geph-manager.service` 承载、GUI 只是个前端,所以这套命令可以完全替代 GUI 的
日常使用。(建议官方考虑为 Linux 用户补一份文档。)

---

## 建议的后续步骤

1. **在现代构建之外同时发布一份现代(ES module)构建**,配合标准的
   `type="module"` + `nomodule` 特性检测组合,让现代引擎走现代路径。如果 polyfill 假设成立,
   这一条就是修复方案,而且改动成本很低。
2. 如果必须保留 legacy 构建,请排查 core-js / SystemJS 与 JavaScriptCore 的交互。
3. 愿意配合进一步诊断,或在本机测试修复版 / 开发版构建 —— 该环境可随时复现。
