Files
creator-hub/docs/shared-xvfb-window-control.md
T

14 KiB
Raw Blame History

共享 Xvfb 与指定 profile 窗口操作:讨论结论

1. 文档定位与完成标准

本文汇总 gateway 的 DISPLAY 配置、共享 Xvfb 的资源收益、窗口定位和 Openbox 激活机制,供后续需求迭代使用。

  • 当前事实:依据现有代码、配置样例及本次讨论期间的只读查询。
  • 建议方案:尚未实现,不能视为当前产品能力或已经批准的开发任务。
  • 本次仅新增文档,不修改代码、配置,不启动或激活浏览器,不发送鼠标事件。
  • 文档完成标准:覆盖讨论中的配置、限制、资源、两种输入方式、profile/窗口映射、风险、待办与验收条件,并明确证据边界。

相关资料:

本文讨论的新建议不改变上述文档已有的完成状态,也不表示共享 DISPLAY 或窗口激活功能已经通过验收。

2. 当前 gateway 的 DISPLAY 行为

2.1 默认模式

  • 每个 runtime 启动独立 Xvfb。
  • 默认从 :100 到 :199 按顺序分配可用 DISPLAY。
  • 当前默认屏幕配置为 1280x720x24。
  • Chrome 启动时显式设置对应 DISPLAY,不是直接继承 gateway 进程的 DISPLAY。
  • 默认分配范围目前没有对应环境变量,只有 runtime manager 的构造参数。

2.2 外部 DISPLAY 模式

在 gateway 环境配置中设置:

RUNTIME_EXTERNAL_DISPLAY=99

含义:复用已经存在的 DISPLAY=:99。

  • 配置值是正整数,不带冒号。
  • 外部 Xvfb 必须事先运行;gateway 不负责启动或停止它。
  • systemd 部署的环境文件通常是 ~/.config/creatorhub/browser-gateway.env。
  • 修改配置后需重启 gateway;已经运行的 Chrome 不会自动切换 DISPLAY。
  • 当前可用性检查涉及 X11 socket 是否存在,不能将其等同于完整的显示服务健康检查。

配置和实现依据:

  • browser_gateway/server/http.py:环境配置解析。
  • browser_gateway/runtime.py:DISPLAY 分配、启动、恢复及释放。
  • deploy/browser-gateway.env.example:配置样例。
  • deploy/creatorhub-browser-gateway.service.in:环境文件加载。

2.3 当前共享限制

Xvfb 本身支持多个 Chrome 共用同一个 DISPLAY;禁止共享是 gateway 当前的应用限制。

现有外部模式包含两层占用处理:

  1. _reserve_display 检查运行记录:如果其他未 released 的 runtime 已记录同一 DISPLAY,则拒绝启动。检查不只限于正在运行的浏览器,stopped 记录也可能触发。
  2. DisplayAllocator.reserve_existing 对 DISPLAY 使用独占文件锁;当前实现会在浏览器启动后释放 display lease,不能把它描述为贯穿运行期的独占锁。

若允许共享,应同时审查记录检查和外部模式的锁流程,不能只删除报错分支。默认模式自行启动 Xvfb 的分配锁仍有必要保留,避免两个启动流程竞争同一 DISPLAY。

3. 每增加一个 Xvfb 的资源开销

3.1 本次讨论期间的运行快照

屏幕配置 进程显示内存 RSS 共享内存按比例分摊后的 PSS 短时 CPU 均值
1280x720x24 约 64.8 MiB 约 32.0 MiB 0.00%
1920x1080x24 约 53.3 MiB 约 35.5 MiB 0.33%

测量来自现有 Xvfb 的 /proc/<pid>/smaps_rollup 和短时间 pidstat 采样,未为测量启动新进程。

解释与边界:

  • RSS 含共享页,不能简单相加得出额外物理内存;PSS 是当前分摊值,也不是新增一个进程的严格边际成本。
  • 两个进程运行历史和负载不同,不能根据表格推导较高分辨率反而更省内存。
  • CPU 百分比按单核口径理解;本次近乎空闲的采样不代表视频、动画或频繁重绘时的消耗。
  • Chrome、VNC、Openbox 的资源消耗均不包含在上述 Xvfb 数字中。
  • 未保留完整的负载条件和连续曲线,因此这些数据是运行快照,不是性能基准。

3.2 容量规划建议

可暂按 每个 Xvfb 预留 50~70 MiB 估算,10 个约 0.5~0.7 GiB。该数字是当前快照下的粗略预留值,不是上限或保证。

24 位色的像素通常按 32 位存储,1280×720 单帧约 3.52 MiB,但 Xvfb 还包含绘图资源、字体、连接和缓存,不能只用单帧大小估算进程内存。

共享 DISPLAY 能减少独立 Xvfb 的重复固定开销;不会消除各个 Chrome 的内存,也不会让所有窗口绘图资源的占用归零。是否值得共享,仍需结合目标并发数和实际页面负载判断。

4. 共享 DISPLAY 的收益与代价

项目 独立 DISPLAY 共享 DISPLAY
Xvfb 固定开销 每个 runtime 一份 多个 runtime 共用
Chrome 数据目录、控制端口 各自独立 仍须各自独立
桌面鼠标、键盘焦点、剪贴板 各自独立 全部共享
VNC 可见窗口 单个浏览器为主 多窗口可能遮挡
Xvfb 故障影响范围 对应 runtime 所有共享者
桌面输入协调 每个 DISPLAY 内协调 所有共享者统一协调

建议方向,尚未实现:默认保留独立 Xvfb;外部 DISPLAY 模式允许共享。

停止一个浏览器时,外部模式没有由该 runtime 持有的 Xvfb unit,现有清理流程不会主动关闭外部 Xvfb。共享后的启动、恢复、停止、状态判断仍需完整验证。

5. 指定 profile 的两种输入方式

5.1 直接控制网页:CDP

profile_id → runtime → 独立 cdp_port → 页面 targetId
  • Page.bringToFront:选择对应页面并请求置于前台。
  • Input.dispatchMouseEvent:向指定页面发送鼠标事件。
  • 事件坐标是主框架视口内的 CSS 像素,不是 Xvfb 桌面坐标。
  • 请求通过独立控制连接定位到对应 Chrome,无需按桌面位置寻找账号。
  • 这不等于控制系统鼠标,也不覆盖浏览器工具栏或原生系统弹窗。
  • 依赖前台焦点或页面可见性的行为仍需协调,不能笼统承诺所有操作均可并发。

推荐:只需网页内输入时优先采用 CDP。

5.2 桌面输入:X11 + Openbox

profile_id → runtime.browser_pid → X11 窗口 ID → 激活窗口 → 桌面输入

适用于需要真实桌面焦点、VNC 前台窗口或网页之外的操作。必须注意:同一个 DISPLAY 只有一套桌面鼠标和键盘焦点,不能把多个窗口理解为多个独立输入设备。

本文仅说明事件与目标窗口的对应机制,不涉及验证码识别、求解或自动绕过,也不保证网站接受合成输入。

6. Openbox 如何激活指定 profile 的窗口

6.1 职责和绑定关系

Xvfb       提供虚拟屏幕,例如 :99
Openbox    管理该屏幕上的窗口、桌面、遮挡顺序和焦点
Chrome     创建窗口,并声明窗口所属进程
gateway    保存 profile 对应的 Chrome 运行信息

Openbox 不认识 profile_id,也不保存账号绑定。绑定关系由 gateway 查询或维护:

profile_id
  → 当前 runtime 的 display、browser_pid、browser_start_time
  → 同一 DISPLAY 上 _NET_WM_PID 匹配的顶层窗口
  → X11 窗口 ID
  → 向 Openbox 发送激活请求

当前每个 profile 使用独立的 --user-data-dir 和 Chrome 进程,这是按 PID 对应 profile 的前提。若未来改为多个 profile 共用同一 Chrome 进程,这条映射将不再足够,不能沿用结论。

一个 DISPLAY 通常运行一个窗口管理器。Xvfb 自身不提供窗口管理;若该 DISPLAY 尚无窗口管理器,可由部署方在该 DISPLAY 上运行 Openbox。gateway 目前不会因此自动具备管理 Openbox 生命周期的能力。

6.2 命令示例

以下 PID、窗口 ID 是示意值;本次没有实际执行激活。

假设运行记录是 display=99、browser_pid=23456:

export DISPLAY=:99

# 查看窗口管理器。
wmctrl -m

# 查看顶层窗口:窗口 ID、桌面、PID、主机、标题。
wmctrl -lp

示意输出:

0x01200003  0 23456 host 抖音 - Google Chrome
0x01400003  0 34567 host 抖音 - Google Chrome

第三列匹配目标 Chrome PID,因此候选窗口是 0x01200003。可进一步检查:

xprop -id 0x01200003 _NET_WM_PID WM_CLASS

确认窗口唯一且仍属于目标 Chrome 后,请求激活:

timeout 5s xdotool windowactivate --sync 0x01200003

xdotool 通过 EWMH 窗口管理协议发送请求,Openbox 执行桌面切换、窗口置前和焦点分配;--sync 等待目标窗口成为激活窗口,外层超时避免无限等待。超时或失败必须报告,不能继续发送输入。

检查激活结果:

xdotool getactivewindow
xdotool getactivewindow getwindowpid

不仅检查 PID,还应确认激活的是选定窗口;同一 PID 可能有多个窗口。

6.3 只读验证证据

本次讨论期间,在本机 DISPLAY=:99 上只读检查发现:

  • wmctrl -m 报告窗口管理器为 Openbox。
  • 一个 Chrome 窗口的 _NET_WM_PID 与实际 Chrome 进程 PID 一致。
  • 该 Chrome 进程命令行包含其独立 --user-data-dir。
  • 本地 xdotool 手册确认 windowactivate --sync 的激活等待行为。

这验证了环境与映射依据,不代表 gateway 已经实现或验证按 profile 激活窗口;本次未执行窗口切换、拖动或网页操作。

7. 窗口定位和输入的必要约束

  1. 不按标题或窗口顺序绑定:页面标题会变,不同 profile 可能打开相同页面。
  2. 重启后重新定位:PID 和 X11 窗口 ID 都可能改变;校验进程启动时间,防止 PID 被复用。
  3. 多窗口必须明确目标:一个 profile 可以有多个窗口。找不到窗口或找到多个候选时明确报错,不能自动取第一个。
  4. 窗口与标签页分开处理:激活 Chrome 窗口不代表选中了指定标签页。指定页面使用 CDP 的 targetId。
  5. 两种窗口 ID 不能混用:Browser.getWindowForTarget 返回的 CDP windowId 不等于 X11 窗口 ID。
  6. 同屏桌面操作串行:协调范围至少覆盖“定位、激活、确认、按下、移动、释放”,不能只锁激活步骤。若存在多个控制进程,必须明确单一控制者或跨进程协调方式。
  7. 人工操作也会抢焦点:VNC 使用者不受程序锁约束。操作期间应避免人工输入;检测到目标变化时中止并报告,不能声称程序锁能消除全部竞争。
  8. 错误必须可见:窗口管理器缺失、窗口不存在、映射歧义、激活超时、焦点丢失均应报告。中断输入时应清理本次按键/按钮状态,不能静默改投其他窗口。

8. 后续迭代事项(待确认后实施)

A. 外部 DISPLAY 共享

  • 调整外部模式的运行记录独占检查和 display lease 处理。
  • 保留默认独立模式的 Xvfb 分配和生命周期隔离。
  • 核查共享模式的启动、停止、释放、gateway 重启恢复、显示服务失效等路径。
  • 更新配置说明、相关测试及与行为发生冲突的既有文档。

B. 按 profile 激活窗口

  • 从当前 runtime 获取 DISPLAY、浏览器 PID 和进程启动时间。
  • 在对应 DISPLAY 上查询受管理的 Chrome 顶层窗口。
  • 定义多窗口时的目标选择规则;未确定规则前,不新增猜测或兜底行为。
  • 使用现有 X11 工具请求激活,并校验结果、设置超时、报告错误。
  • 窗口 ID 优先即时查询,不为短生命周期标识新增数据库绑定表。

C. 输入方式及协调

  • 根据实际需求明确采用网页 CDP 输入还是桌面 X11 输入,不把两者混作同一能力。
  • 桌面输入按 DISPLAY 协调整个操作过程,并明确人工 VNC 输入的处理约定。
  • 是否由 gateway 管理 Openbox、是否需要专用操作接口,由后续需求单独确认;当前不新增部署层或接口。

D. 日志与资源验证

  • 关键记录至少包括:操作编号、profile、runtime、DISPLAY、浏览器 PID/启动时间、目标窗口、激活前后状态、耗时和失败原因。
  • 区分“未找到窗口”“多个候选”“服务不可用”“激活失败”“焦点改变”,避免只记录通用失败。
  • 若节省内存是迭代目的,应在相同页面、相同 profile 数量与相同负载下对比独立/共享模式;统计 Xvfb、Chrome、Openbox、VNC 整体资源,而不是只累加 RSS。

9. 后续开发验收条件

功能开发遵循 TDD,相关单元测试覆盖率至少 65%;不主动编写或运行 E2E 测试。

单元测试应覆盖

  • 默认模式为不同 runtime 分配独立 DISPLAY。
  • 共享外部模式允许多个 runtime 使用同一 DISPLAY,且保留独立数据目录和控制端口。
  • 停止一个 runtime 不关闭外部 Xvfb,不影响另一个 runtime。
  • gateway 恢复时正确识别共享 DISPLAY 与各自浏览器状态。
  • 外部 DISPLAY 不可用时明确报错,不自动切换到其他屏幕。
  • profile/PID/窗口定位成功、窗口缺失、多窗口歧义、PID 失效和窗口失效。
  • 激活成功、超时、窗口管理器缺失与结果不匹配。
  • 同一 DISPLAY 的桌面输入不会交叉执行;失败能释放协调资源并报告。

需要使用者明确授权的现场验证

  • 两个独立 profile 共用一个 Xvfb,确认窗口和账号数据互不混淆。
  • 按 profile 激活窗口,包含窗口被遮挡、位于其他桌面以及重启后的情形。
  • 在普通可拖动页面验证目标窗口与输入坐标,避免以验证码求解作为验证标准。
  • 检查停止其中一个浏览器后另一浏览器和外部 Xvfb 是否正常。
  • 记录相同负载下的资源变化及日志证据。

实施前仍需确认:是否启用共享外部 DISPLAY、是否需要桌面输入、多窗口选择规则、Openbox 由谁管理。本文不替代这些决策。