WSLg 做了什么(2)
Published:
在前一篇的基础上, 更深入了解一些细节.
先安装一个最简化的 WSL 发行版 miniwsl, 里面基本上只有 busybox 没有 systemd 也没有其他后台服务.
miniwsl 分析
- miniwsl 的进程树
1 {init(miniwsl)} /init
├─ 4 {init} plan9 --control-socket 5 --log-level 4 --server-fd
└─ 7 {SessionLeader} /init
└─ 8 {Relay(n)} /init
└─ 9 -sh
- miniwsl 的环境变量
$ cat /proc/8/environ
WSL2_CROSS_DISTRO=/wsl
$ cat /proc/9/environ
DISPLAY=:0
XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
WAYLAND_DISPLAY=wayland-0
PULSE_SERVER=unix:/mnt/wslg/PulseServer
WSL_INTEROP=/run/WSL/8_interop
我们看见重要的环境变量是 /init 的 Relay 进程在启动 sh 时设置给 sh 的
- miniwsl 的文件系统
暂时推测 wsl-system 挂载 WSL 子系统对应的ext4.vhdx为子系统的/,
然后创建临时文件系统(tmpfs)/mnt/wslg/及/mnt/wslg/runtime-dir/,/mnt/wslg/.X11-unix/,
还有里面 X, Wayland, Pulseaudio 对应的 socket 文件,
将之挂载到子系统mount --bind /mnt/wslg/ /{miniwsl-sub-distro}/mnt/wslg/.
启动子系统后, 子系统大概会mount -o bind,ro /tmp/.X11-unix /mnt/wslg/.X11-unix.
环境变量与对应文件
- X11 相关变量与文件
DISPLAY=:0对应的文件是/tmp/.X11-unix/X0
目录/tmp应该是由wsl --system系统发行版创建并挂载.
当启用 systemd 后, 一般tmp.mount 会重新创建 /tmp 导致 /tmp/.X11-unix/X0 不存在, 必须重新创建目录或文件链接以保证 /tmp/.X11-unix/X0 -> /mnt/wslg/.X11-unix/X0.
Ubuntu@WSL 禁用了 tmp.mount, 方法是只有 /usr/share/systemd/tmp.mount 而没有 /usr/lib/systemd/system/tmp.mount.
Arch 默认就有 /usr/lib/systemd/system/tmp.mount 一直启用 tmp.mount. 可以用在 WSL2 中禁用:
$ sudo systemctl mask tmp.mount
Created symlink /etc/systemd/system/tmp.mount → /dev/null.
修复方法
- 禁用
tmp.mount - 启用
tmp.mount, 目录链接ln -sf /mnt/wslg/.X11-unix /tmp/.X11-unix - 启用
tmp.mount, 文件链接ln -sf /mnt/wslg/.X11-unix/X0 /tmp/.X11-unix/X0 - 启用
tmp.mount, 挂载目录mount -o bind,ro /tmp/.X11-unix /mnt/wslg/.X11-unix - 启用
tmp.mount, 挂载文件mount -o bind,ro /tmp/.X11-unix/X0 /mnt/wslg/.X11-unix/X0
创建链接可以使用 tmpfiles.d 来实现
$ cat /etc/tmpfiles.d/wslg.conf
# See tmpfiles.d(5) for details
# link WSLg display files after system started
# Type Path Mode UID GID Age Argument
#L+ /tmp/.X11-unix - - - - /mnt/wslg/.X11-unix
L+ /tmp/.X11-unix/X0 - - - - /mnt/wslg/.X11-unix/X0
挂载的方法只能写一个 systemd service
- Wayland pulseaudio 相关变量与文件
$ env | grep -E "XDG|PULSE|WAYLAND"
XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
WAYLAND_DISPLAY=wayland-0
PULSE_SERVER=unix:/mnt/wslg/PulseServer
$ ls -al $XDG_RUNTIME_DIR/wayland* $XDG_RUNTIME_DIR/pulse/*
srwxrwxrwx 1 1000 1000 0 Apr 9 03:30 /mnt/wslg/runtime-dir/pulse/native
-rw------- 1 1000 1000 3 Apr 9 03:30 /mnt/wslg/runtime-dir/pulse/pid
srwxrwxrwx 1 1000 1000 0 Apr 9 03:30 /mnt/wslg/runtime-dir/wayland-0
-rw-rw---- 1 1000 1000 0 Apr 9 03:30 /mnt/wslg/runtime-dir/wayland-0.lock
没有启用 systemd 的 WSL2 发行版, 目录/mnt/wslg/runtime-dir应该是由wsl --system系统发行版创建并挂载, XDG_RUNTIME_DIR 是由 进程树中 {Relay(n)} /init 这个进程设置的.
启用 systemd 后 XDG_RUNTIME_DIR 是由 logind 创建并设置的. 创建 /run/user/$(id -u) 目录并设置到 XDG_RUNTIME_DIR, 必须创建上述4个文件的链接.
Ubuntu@WSL 之前能正常创建上述4个文件的链接, 但近日的 24.04 没有创建 wayland-0 等的链接.
保持 XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir 是不可接受的, 那么只能创建链接.
创建链接可以使用 user-tmpfiles.d 来实现, 创建文件 ~/.config/user-tmpfiles.d/wslg.conf 或 /usr/share/user-tmpfiles.d/wslg.conf, 内容为:
# Type Path Mode UID GID Age Argument
L+ %t/wayland-0 - - - - /mnt/wslg/runtime-dir/wayland-0
L+ %t/wayland-0.lock - - - - /mnt/wslg/runtime-dir/wayland-0.lock
L+ %t/pulse/native - - - - /mnt/wslg/runtime-dir/pulse/native
L+ %t/pulse/pid - - - - /mnt/wslg/runtime-dir/pulse/pid
L+ %t/dbus-1 - - - - /mnt/wslg/runtime-dir/dbus-1
然后运行 systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer.