Files
MobileGL/docs/Disaggregated/guide/container-client.md
T
BZLZHH 2e43df6125 [Docs] (disaggregated): the container as a client of the phone's on-screen server, and the two things that cost a run
Measured on the Redmi today: the Droidspaces container shares the phone's network namespace, so a
client in the container reaches the server's loopback listener with no adb forward and no LAN
address; the server owns the window (MOBILEGL_IPC_SURFACE=server), the Adreno does the drawing,
and a screenshot of the phone shows the colour that headless client asked for.

The two traps are written down because both cost a run: MOBILEGL_IPC_REQUIRE_SAME_BUILD=1 on the
server turns a Connect handshake's build-stamp warning into Refuse{BuildFingerprint} against a
release APK whose stamp is 0, and the client then dies on a caps gate that names something else.
2026-10-01 00:39:49 +08:00

64 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 容器当 client,手机当 server(上屏)
> 2026-10-01 在 Redmi 23117RK66C(Adreno 750,Android 16)与它的 Droidspaces Fedora 44
> 容器上实测通过。本文记的是那条链路上**真正要设的东西**,以及两个会让人白跑一次的坑。
## 为什么不需要 `adb forward`
Droidspaces 容器与 Android **共用网络命名空间**(实测:容器里 `127.0.0.1:22` 就是 Android 的
sshd,`ip addr` 列出的是手机的 `wlan0` / `rmnet_data5`)。所以服务端监听手机回环即可,
容器直接用 `tcp://127.0.0.1:<port>` 连上去,不需要 `adb forward`,也不需要局域网地址。
## 起服务端(手机侧,上屏形态)
```bash
TOKEN=<>=16 字节>
adb shell am start -n top.mobilegl.plugin/top.mobilegl.plugin.MobileGLDisplayActivity \
--es listen tcp://127.0.0.1:40613 --es token "$TOKEN"
# 就绪行:
# MG_Remote server: pid=… listening on tcp://127.0.0.1:40613 (in-process display server, display installed)
```
**不要**给这次启动加 `--es env MOBILEGL_IPC_REQUIRE_SAME_BUILD=1`,除非两端确实同 build:
按契约,`Dial == Connect` 时 build stamp 不同**只应警告**;加上它,服务端会因为 app 的戳(发布
APK 里是 0)与容器客户端的戳(源码树短哈希)不同而 `Refuse{BuildFingerprint}`——症状是客户端
在 `eglCreateWindowSurface` 之前就被 abort,日志里只有一条与真正原因无关的 caps 门。
## 容器侧(客户端)
```bash
export MOBILEGL_TRANSPORT=spawn # 两进程;endpoint 由下面这条给
export MOBILEGL_IPC_CONTROL=tcp://127.0.0.1:40613
export MOBILEGL_IPC_DATA=stream # 跨进程字节流;同机共享段是另一条轴
export MOBILEGL_IPC_SURFACE=server # 窗口是服务端的:客户端传 NULL 窗口
export MOBILEGL_IPC_TOKEN=<同一个>
export LD_LIBRARY_PATH=/root/build-cont # 容器里那份 split 构建
./onscreen_client # eglCreateWindowSurface(dpy, cfg, NULL, {EGL_WIDTH,EGL_HEIGHT})
```
客户端侧不需要 GPU、不需要 `/dev/dri`、不需要 Wayland:它只记录,画的是服务端。
## 实测结果
```
EGL 1.5 vendor=MobileGL version=1.5 MobileGL
surface created: 1440x3200 (asked 1440x3200)
GL_RENDERER=Espryt (MobileGL Core) (Adreno (TM) 750, OpenGL ES 3.2)
frame 0..11 swap=1
```
服务端逐帧:
```
P65ServerFrame frame=8..12 records=4 apply_ms=1.0..1.7
```
抓屏为整屏 `#72e3d8`,即客户端第 3 种清屏色 `(0.20, 0.90, 0.85)` 经 sRGB 转换后的值——
容器里那个没有 GPU 的进程要求画的东西,出现在手机屏幕上。
## 待办(本页不含)
- kwin:让 Plasma 的合成也走这条客户端(`LD_PRELOAD` 或直接链接容器里那份 `libEGL`),
窗口面仍是服务端形态;此时 Anland 只剩 Wayland 协议与输入。
- 两端同 build:容器里的源码树与 APK 从同一 revision 构建后,`REQUIRE_SAME_BUILD=1` 才有意义。