某天在翻看linux新闻时,意外了解到几年前,Android也使用现在GNU/Linux普遍使用的DRM(Direct Rendering Manager)显示架构
Android容器内的drm_info
所以,理论上可以让Wayland合成器接替Android合成器,让wayland直接显示输出,减少termux-x11这些中转产生的性能损耗。尝试在chroot内直接运行kwin_wayland合成器,以及基于wlroots的labwc,均以失败告终:
kwin_wayland
wlroots的seat后端提示
根据seat的提示,可以推测是Android的合成器占用了drm,从而wlroots等合成器无法运行。临近考试,这件事也被搁置了很久
既然被占用,杀掉不就可以了吗?
连接电脑,adb shell
diting:/ # lsof /dev/dri/card0
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
composer-servic 4328 system 9u CHR 226,0 0t0 1448 /dev/dri/card0
composer-servic 4328 system 17u CHR 226,0 0t0 1448 /dev/dri/card0
composer-servic 4328 system 20u CHR 226,0 0t0 1448 /dev/dri/card0
......
再开个窗口
使用termux的ssh二进制文件连接容器内sshd
diting:/ # /data/data/com.termux/files/usr/bin/ssh SnowNF@127.0.0.1
SnowNF@127.0.0.1's password:
SnowNF@localhost:~$
写两个脚本方便后续执行
SnowNF@localhost:~$ cat ./run.sh
sh chmod.sh&
export SEATD_VTBOUND=0
sudo -E seatd
SnowNF@localhost:~$ cat ./chmod.sh
sleep 1
sudo chmod 777 /run/seatd.sock
然后运行seatd
SnowNF@localhost:~$ ./run.sh
00:00:00.000 [seatd/seat.c:41] Created seat seat0
00:00:00.000 [seatd/seatd.c:194] seatd started
再开一个,设置环境变量使用cpu渲染[1],随后启动labwc
SnowNF@localhost:~$ export WLR_RENDERER=pixman
SnowNF@localhost:~$ labwc -d
此时可以在seatd看到drm设备被占用的信息
00:01:11.336 [seatd/server.c:145] New client connected (pid: 21205, uid: 1000, gid: 60000)
00:01:11.336 [seatd/seat.c:170] Added client 2 to seat0
00:01:11.336 [seatd/seat.c:480] Opened client 2 on seat0
00:01:11.340 [seatd/seat.c:281] Could not make device fd drm master: Device or resource busy
00:01:11.344 [seatd/client.c:471] Client disconnected
00:01:11.344 [seatd/seat.c:332] Could not revoke drm master on device fd: Invalid argument
00:01:11.344 [seatd/seat.c:418] No clients on seat0 to activate
00:01:11.344 [seatd/seat.c:524] Closed client 2 on seat0
00:01:11.344 [seatd/seat.c:192] Removed client 2 from seat0
以及labwc失败的信息
00:00:00.001 [backend/session/session.c:109] Successfully loaded libseat session
00:00:00.004 [backend/backend.c:220] Found 1 GPUs
00:00:00.005 [backend/drm/backend.c:200] Initializing DRM backend for /dev/dri/card0 (msm_drm)
00:00:00.005 [backend/drm/drm.c:88] Using atomic DRM interface
00:00:00.005 [backend/drm/drm.c:100] ADDFB2 modifiers supported
00:00:00.005 [backend/drm/drm.c:253] Found 2 DRM CRTCs
00:00:00.005 [backend/drm/drm.c:180] Found 16 DRM planes
00:00:00.006 [util/env.c:25] Loading WLR_RENDERER option: pixman
00:00:00.006 [render/pixman/renderer.c:515] Creating pixman renderer
00:00:00.006 [render/allocator/allocator.c:143] Failed to create allocator
00:00:00.006 [../src/server.c:276] unable to create allocator
再开一个,得到pid为4328,先记住,后面要用
$ adb shell
diting:/ $ su
diting:/ # lsof /dev/dri/card0
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
composer-servic 4328 system 9u CHR 226,0 0t0 1448 /dev/dri/card0
diting:/ # stop # 停止安卓服务防止被快速拉起
把之前labwc的窗口稍作修改,4328要替换为自己的
SnowNF@localhost:~$ sudo kill 4328 && labwc -d
不出意外会因为缺少输入设备而失败
libinput initialization failed, no input devices
可以暂时用 ```shell SnowNF@localhost:~$ export WLR_LIBINPUT_NO_DEVICES=1 ``` 环境变量顶替一下可能运行成功,因为 labwc 默认就是一张纯黑的壁纸,手机是OLED屏,无法判断是否真的"亮起"
此时可以临时换成 sway -d
然后就可以看见经典的 sway 标志了
图片的左上角是sway的标题栏,可见手机的DPI还是很高的
也能看见容器内进程正在使用 /dev/dri/card0
diting:/ # lsof /dev/dri/card0
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
seatd 20218 root 7u CHR 226,0 0t0 1448 /data/data/com.termux/files/home/debian/dev/dri/card0
sway 20815 system 10u CHR 226,0 0t0 1448 /data/data/com.termux/files/home/debian/dev/dri/card0
Xwayland 20835 system 4u CHR 226,0 0t0 1448 /data/data/com.termux/files/home/debian/dev/dri/card0
composer-servic 20246 system 9u CHR 226,0 0t0 1448 /dev/dri/card0
composer-servic 20246 system 17u CHR 226,0 0t0 1448 /dev/dri/card0
没有输入只能看着...(还不如不搞)
SnowNF@localhost:~$ libinput list-devices
返回为空
搜索&翻看源码可知是调用了systemd的udev
网上都是执行
sudo udevadm trigger
来让systemd刷新一下设备列表
但容器内会提示
SnowNF@localhost:~$ sudo udevadm trigger
Running in chroot, ignoring request.
怎么办呢,只能看源码然后想办法去掉判断了
意外找到的注释
根据注释只需SnowNF@localhost:~$ SYSTEMD_IGNORE_CHROOT=1 sudo -E udevadm trigger
随后我的手机重启了
估计是把所有硬件都刷新了一遍,导致安卓误以为故障导致重启
那有什么办法只“刷新”自己想要的吗
evtest 真的救我老命了(
SnowNF@localhost:~$ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event0: gpio-keys
/dev/input/event1: qcom-hv-haptics
/dev/input/event2: uinput-goodix
/dev/input/event3: pmic_pwrkey
/dev/input/event4: pmic_resin
/dev/input/event5: pmic_pwrkey_bark
/dev/input/event6: pmic_pwrkey_resin_bark
/dev/input/event7: goodix_ts
/dev/input/event8: waipio-mtp-snd-card Headset Jack
/dev/input/event9: waipio-mtp-snd-card Button Jack
Select the device event number [0-9]:
可见触摸等各种设备,这边就只弄个触摸就行了,即 /dev/input/event7
SnowNF@localhost:~$ sudo udevadm test /dev/input/event7
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.
Trying to open "/etc/systemd/hwdb/hwdb.bin"...
Trying to open "/etc/udev/hwdb.bin"...
Trying to open "/usr/lib/systemd/hwdb/hwdb.bin"...
Trying to open "/usr/lib/udev/hwdb.bin"...
.....
DEVPATH=/devices/virtual/input/input7/event7
DEVNAME=/dev/input/event7
MAJOR=13
MINOR=71
SUBSYSTEM=input
ACTION=add
TAGS=:power-switch:
ID_INPUT=1
ID_INPUT_TOUCHSCREEN=1
ID_INPUT_KEY=1
CURRENT_TAGS=:power-switch:
LIBINPUT_DEVICE_GROUP=0/beef/dead:goodix_ts
USEC_INITIALIZED=17731339063
run: 'libinput-fuzz-to-zero /sys/devices/virtual/input/input7/event7'
Unload kernel module index.
Unloaded link configuration context.
然后就注册完成了
SnowNF@localhost:~$ libinput list-devices
Failed to open /dev/input/event7 (Permission denied) # 不知道为什么systemd把权限搞坏了
SnowNF@localhost:~$ sudo chmod 777 /dev/input/event7
SnowNF@localhost:~$ libinput list-devices
Device: goodix_ts
Kernel: /dev/input/event7
Group: 1
Seat: seat0, default
Capabilities: keyboard touch
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: identity matrix
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Disable-w-trackpointing: n/a
Accel profiles: n/a
Rotation: 0.0
触摸也有反应了
SnowNF@localhost:~$ libinput debug-events
-event7 DEVICE_ADDED goodix_ts seat0 default group1 cap:kt ntouches 10 calib
event7 TOUCH_DOWN +0.000s 0 (0) 55.67/65.18 (6792.00/17678.00mm)
event7 TOUCH_FRAME +0.000s
event7 TOUCH_UP +0.043s 0 (0)
event7 TOUCH_FRAME +0.043s
^C
使用同样的方法注册了蓝牙鼠标
不会配置 labwc/sway 的触摸就用终端简单开了一些程序[2]
wlroots 和 android 内核
打开的终端以及vkcube (重影是因为平板的相机不是很好)
运行完毕后,Ctrl+C 结束 seatd 以及 labwc,随后在 adb shell 内执行以下命令
diting:/ # lsof /dev/dri/card0
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
composer-servic 15890 system 9u CHR 226,0 0t0 1448 /dev/dri/card0
composer-servic 15890 system 17u CHR 226,0 0t0 1448 /dev/dri/card0
.....
diting:/ # start
diting:/ # kill 15890 # 杀掉无法正常显示的android合成器,随后会自动拉起
最后手机正常开机
FAQ:
Q: 为什么要使用cpu渲染?
A: 因为如果使用 gles2 渲染, 需要 msm_drm 驱动来把渲染直接输出到DRM层,而现在mesa没有提供只能使用cpu渲染。更新: 修改 mesa 后实现了 msm-drm 驱动,成功在高通设备上实现了部分硬件加速
使用 WLR_RENDERER=gles2 渲染的报错
Q: 有什么可以改进的地方吗?A: 这些操作大概可以封装成几个脚本,最后Vulkan可以使用turnip驱动,OpenGL可以使用zink来实现Wayland合成器以外的全局硬件加速,同时systemd的注册设备应该可以写一个循环执行的脚本,对硬件变更实时响应。
Q: 有声音吗?
A: 没有,理论上可以在adb start后,在安卓端跑个pulseaudio桥接到容器内部.........或者用udevadm刷新音频设备,再由容器内接管?(比如alsa)(嘛....对音频架构这块不是很清楚..期待大佬们补充)。
Q: 使用场景&展望
A: 成熟后应该是可以把手机当做纯GNU/Linux来使用
Q: 性能怎么样?
A: 可能比容器内运行vncserver或者使用termux-x11要高,如果有 msm_drm 驱动,那么应该和手机直接运行主线Linux性能一致(比如postmarketos)。
总之部分systemd功能可以使用,使用 udevadm 刷新设备后基本都能在容器里的/run/udev/data上看见对应的节点。(也许,可能,大概)外设只是缺少容器内用户空间的驱动..........所以上限取决于大家的找(写)驱动的能力以及脑洞。
[1]详见 WLR_RENDERER
[2]第一次运行vkcube的时候屏幕上看不见窗体,估计是labwc等合成器默认把手机的DP输出当做主屏幕了,所以我接了鼠标把光标移动到副屏(即手机的主屏幕),这时vkcube窗体被放置到了副屏,我才可以看见。