# 共享 Xvfb 与指定 profile 窗口操作:讨论结论 ## 1. 文档定位与完成标准 本文汇总 gateway 的 DISPLAY 配置、共享 Xvfb 的资源收益、窗口定位和 Openbox 激活机制,供后续需求迭代使用。 - **当前事实**:依据现有代码、配置样例及本次讨论期间的只读查询。 - **建议方案**:尚未实现,不能视为当前产品能力或已经批准的开发任务。 - 本次仅新增文档,不修改代码、配置,不启动或激活浏览器,不发送鼠标事件。 - 文档完成标准:覆盖讨论中的配置、限制、资源、两种输入方式、profile/窗口映射、风险、待办与验收条件,并明确证据边界。 相关资料: - [现有验证记录](native-browser-verification.md) - [现有实施计划](native-browser-implementation-plan.md) - [现有浏览器变更评审](native-browser-change-review.md) 本文讨论的新建议不改变上述文档已有的完成状态,也不表示共享 DISPLAY 或窗口激活功能已经通过验收。 ## 2. 当前 gateway 的 DISPLAY 行为 ### 2.1 默认模式 - 每个 runtime 启动独立 Xvfb。 - 默认从 `:100` 到 `:199` 按顺序分配可用 DISPLAY。 - 当前默认屏幕配置为 `1280x720x24`。 - Chrome 启动时显式设置对应 `DISPLAY`,不是直接继承 gateway 进程的 `DISPLAY`。 - 默认分配范围目前没有对应环境变量,只有 runtime manager 的构造参数。 ### 2.2 外部 DISPLAY 模式 在 gateway 环境配置中设置: ```ini 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//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 ```text profile_id → runtime → 独立 cdp_port → 页面 targetId ``` - `Page.bringToFront`:选择对应页面并请求置于前台。 - `Input.dispatchMouseEvent`:向指定页面发送鼠标事件。 - 事件坐标是主框架视口内的 CSS 像素,不是 Xvfb 桌面坐标。 - 请求通过独立控制连接定位到对应 Chrome,无需按桌面位置寻找账号。 - 这不等于控制系统鼠标,也不覆盖浏览器工具栏或原生系统弹窗。 - 依赖前台焦点或页面可见性的行为仍需协调,不能笼统承诺所有操作均可并发。 **推荐:只需网页内输入时优先采用 CDP。** ### 5.2 桌面输入:X11 + Openbox ```text profile_id → runtime.browser_pid → X11 窗口 ID → 激活窗口 → 桌面输入 ``` 适用于需要真实桌面焦点、VNC 前台窗口或网页之外的操作。必须注意:同一个 DISPLAY 只有一套桌面鼠标和键盘焦点,不能把多个窗口理解为多个独立输入设备。 本文仅说明事件与目标窗口的对应机制,不涉及验证码识别、求解或自动绕过,也不保证网站接受合成输入。 ## 6. Openbox 如何激活指定 profile 的窗口 ### 6.1 职责和绑定关系 ```text Xvfb 提供虚拟屏幕,例如 :99 Openbox 管理该屏幕上的窗口、桌面、遮挡顺序和焦点 Chrome 创建窗口,并声明窗口所属进程 gateway 保存 profile 对应的 Chrome 运行信息 ``` Openbox 不认识 `profile_id`,也不保存账号绑定。绑定关系由 gateway 查询或维护: ```text 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`: ```bash export DISPLAY=:99 # 查看窗口管理器。 wmctrl -m # 查看顶层窗口:窗口 ID、桌面、PID、主机、标题。 wmctrl -lp ``` 示意输出: ```text 0x01200003 0 23456 host 抖音 - Google Chrome 0x01400003 0 34567 host 抖音 - Google Chrome ``` 第三列匹配目标 Chrome PID,因此候选窗口是 `0x01200003`。可进一步检查: ```bash xprop -id 0x01200003 _NET_WM_PID WM_CLASS ``` 确认窗口唯一且仍属于目标 Chrome 后,请求激活: ```bash timeout 5s xdotool windowactivate --sync 0x01200003 ``` `xdotool` 通过 EWMH 窗口管理协议发送请求,Openbox 执行桌面切换、窗口置前和焦点分配;`--sync` 等待目标窗口成为激活窗口,外层超时避免无限等待。超时或失败必须报告,不能继续发送输入。 检查激活结果: ```bash 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 由谁管理。本文不替代这些决策。**