让wayland接管android——systemd wifi 以及 gsi

484 阅读14分钟

原文

相对于一般的 GNU/Linux 来说,根据前面的文章仅仅启动一个 labwc 是完全没办法正常使用的。比如在我的平板上面,只要"adb stop"后,过不了几秒整个安卓就会被奇怪的程序拉起,占用RAM不说,他还会和 labwc 共用同一个输入,这导致在操作 labwc 时经常会误触安卓的锁屏界面。

labwc(左下) 与 安卓(右上,使用scrcpy) 同时运行

同时,没有 systemd,系统缺少对硬件动态处理的能力。比如手动启动 systemd-networkd dbus-daemon NetworkManager 等服务后,即使连上网络

nmtui (欸..之前还能用来着)

由于缺少对内核的设置(gateway, ip rule 等),总是ping不通。

$ ping 8.8.8.8
connect: Network is unreachable
$

缺少 udevd,使得插入的 otg 等设备没有任何反应。(似乎可以手动运行他? /usr/lib/systemd/systemd-udevd)

为了解决这些问题,打算引入 systemd,但他只能以pid 1 运行

root@localhost:~# /usr/lib/systemd/systemd --system
Can't run system mode unless PID 1.
root@localhost:~# 

所以就只能尝试替换安卓的 init 进程来运行 systemd 了

注: 以下内容只在某闭源骁龙870平板上进行测试

Ramdisk 中的 init

Ramdisk 一般存放于 boot.img 内,可以使用 magiskboot 进行修改,于是向里面添加了 busybox-static 和一个用 shell 写的简单的 init

$ # ramdisk文件结构如下
$ tree -a
.
└── ramdisk
    ├── avb
    │   ├── q-gsi.avbpubkey
    │   ├── r-gsi.avbpubkey
    │   └── s-gsi.avbpubkey
    ├── .backup
    │   ├── init
    │   ├── .magisk
    │   └── .rmlist
    ├── bin
    │   └── busybox  (bin文件夹下的文件似乎无法访问)
    ├── busybox       (所以用这个啦)
    ├── debug_ramdisk
    ├── dev
    ├── fstab.qcom
    ├── init
    ├── mnt
    ├── overlay.d
    │   └── sbin
    │       ├── magisk32.xz
    │       ├── magisk64.xz
    │       └── stub.xz
    ├── proc
    ├── sh  (busybox的sh组件)
    ├── sys
    └── system
        └── bin
            └── e2fsck

14 directories, 15 files

一个简单的 /init, 使用 /sh 当作解释器

打包 boot.img, 刷入并启动手机然后就能看见输出了吧...并不能

缺少 framebuffer console / virtual terminal,屏幕上不会显示任何文本,只有第一屏的 logo

使用 magiskboot 解包 boot.img

$ ./libmagiskboot.so unpack boot.img Parsing boot image: [boot.img]
HEADER_VER      [2]
KERNEL_SZ       [44187664]
RAMDISK_SZ      [1638119]
SECOND_SZ       [0]
RECOV_DTBO_SZ   [0]
DTB_SZ          [1617030]
OS_VERSION      [11.0.0]
OS_PATCH_LEVEL  [2021-10]
PAGESIZE        [4096]
NAME            []
CMDLINE         [console=ttyMSM0,115200n8 earlycon=msm_geni_serial,0xa90000 androidboot.hardware=qcom androidboot.console=ttyMSM0 androidboot.memcg=1 lpm_levels.sleep_disabled=1 video=vfb:640x400,bpp=32,memsize=3072000 msm_rtb.filter=0x237 service_locator.enable=1 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 loop.max_part=7 cgroup.memory=nokmem,nosocket reboot=panic_warm buildvariant=user systemd.log_level=debug selinux=0 enforcing=0]
CHECKSUM        [1e81e0583771617c63cad091dca1e602f65038fa000000000000000000000000]
KERNEL_FMT      [raw]
RAMDISK_FMT     [gzip]
unexpected ASN.1 DER tag: expected SEQUENCE, got APPLICATION [1] (primitive)
VBMETA

可以看到 cmdline 中指定了 console=ttyMSM0,115200n8, 搜索后了解到这个是 ucrt 的输出,需要在主板上外接线才能用。

好在这个高通平板魔改的不是很多,init 进程崩溃后会重启到 900e 模式 (ID: 05c6:900e) (一加还会显示"QUALCOMM CrashDump Mode", 而我这个平板只会黑屏)

$ lsusb 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 002: ID 048d:6006 Integrated Technology Express, Inc. ITE Device(8291)
Bus 003 Device 003: ID 04f2:b71a Chicony Electronics Co., Ltd Integrated IR Camera
Bus 003 Device 004: ID 8087:0026 Intel Corp. AX201 Bluetooth
Bus 003 Device 011: ID 05c6:900e Qualcomm, Inc. QUSB_BULK_SN:34AB1B59 # 900E 模式下的手机
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

此时可以使用 edl 把 LASTKMSG.BIN dump 出来,里面便是 珍贵 的内核日志

[    1.669238] ALSA device list:
[    1.669247]   No soundcards found.
[    1.670808] Freeing unused kernel memory: 6144K
[    1.670906] Run /init as init process
[    1.672942] INIT: before mkdirs
[    1.674525] INIT: after mkdirs
[    1.678339] request_module fs-devtmpfs succeeded, but still no fs?
[    1.678724] INIT: mount /proc /sys /tmp /dev
[    1.679394] Filesystem                Size      Used Available Use% Mounted on
[    1.679394] proc                         0         0         0   0% /proc
[    1.679394] sysfs                        0         0         0   0% /sys
[    1.679394] tmpfs                     3.7G         0      3.7G   0% /tmp
[    1.682495] INIT: mount /dev/pts
[    1.685940] INIT: redirect stdout stderr to /kmsg
[    1.686011] Starting init process...
[    1.686487] BusyBox v1.36.1 (Debian 1:1.36.1-7)
[    1.686490]  multi-call binary.
[    1.686510] BusyBox is copyrighted by many authors between 1998-2015.
[    1.686510] Licensed under GPLv2. See source distribution for detailed
[    1.686510] copyright notices.
[    1.686510] 
[    1.686510] Usage: busybox [function [arguments]...]
[    1.686510]    or: busybox --list[-full]
[    1.686510]    or: busybox --install [-s] [DIR]
[    1.686510]    or: function [arguments]...
[    1.686510] 
[    1.686510] 	BusyBox is a multi-call binary that combines many common Unix
[    1.686510] 	utilities into a single executable.  The shell in this build
....
[    1.687631] Thu Jan  1 00:00:33 UTC 1970 # 此处对应着 /busybox date
....
[    6.720912] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000

研究了一下 magisk 的 init,幻想着他重写了第一阶段的 init 程序....

获取 patch ramdisk 前的 init 程序

替换为原始的 init

但是他并没有

....

既然这样还是看看 init 的源码吧...

$ git clone https://mirrors.ustc.edu.cn/aosp/platform/system/core.git --depth=1
....

可以看见 init 在第一阶段(First Stage),也就是 ramdisk 内, 从 super 分区读取了元数据并创建基于 dm(Device Mapper) 的逻辑分区,最后运行 /system/init。这样的话,可以替换一下 system 分区内的 init,也方便用dsu测试。

core/init/first_stage_mount.cpp

system 内的 init

用c语言写了个小的 init,并把 stderr 和 stdout 重定向到 kmsg

创建kmsg节点并重定向

使用busybox的sh执行/bin/init.sh

使用 dsu 启动后,成功运行 init.sh, 并执行了 df -h 等命令

[    1.797713] init: [libfs_mgr]__mount(source=/dev/block/dm-11,target=/odm,type=ext4)=0: Success
[    1.798148] init: Skipped setting INIT_AVB_VERSION (not in recovery mode)
[    1.877445] mount: mounting proc on /proc failed: Device or resource busy
[    1.878251] mount: mounting sysfs on /sys failed: Device or resource busy
[    1.879599] INIT: mount /proc /sys /tmp /dev
[    1.880246] Filesystem                Size      Used Available Use% Mounted on
[    1.880246] tmpfs                     3.7G         0      3.7G   0% /dev
[    1.880255] df: /dev/pts: No such file or directory
[    1.880395] proc                         0         0         0   0% /proc
[    1.880395] sysfs                        0         0         0   0% /sys
[    1.880395] selinuxfs                    0         0         0   0% /sys/fs/selinux
[    1.880395] tmpfs                     3.7G         0      3.7G   0% /mnt
[    1.880395] tmpfs                     3.7G         0      3.7G   0% /debug_ramdisk
[    1.880395] /dev/block/by-name/metadata
[    1.880395]                          11.5M    280.0K     10.7M   2% /metadata
[    1.880395] /dev/block/dm-7         108.0M      5.3M     98.9M   5% /
[    1.880395] /dev/block/dm-8         360.4M    359.3M         0 100% /system/system_ext
[    1.880395] /dev/block/dm-9         457.8M    456.4M         0 100% /system/product
[    1.880395] /dev/block/dm-10        643.4M    641.5M         0 100% /vendor
[    1.880395] /dev/block/dm-11        908.0K    904.0K         0 100% /odm
[    1.880414] df: /dev/ufxpfdlbchnpfaj: No such file or directory
[    1.880492] magisk                    3.7G      1.1M      3.7G   0% /sys/fs/selinux/load
[    1.880492] magisk                    3.7G      1.1M      3.7G   0% /sys/fs/selinux/enforce
[    1.880492] magisk                    3.7G      1.1M      3.7G   0% /init.rc
[    1.880492] tmpfs                     3.7G         0      3.7G   0% /tmp
[    1.880492] tmpfs                     3.7G         0      3.7G   0% /dev
...
[    6.942006] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
[    6.942006] 
[    6.942018] CPU: 1 PID: 1 Comm: busybox Tainted: G S      W         4.19.157-perf+ #1
[    6.942023] Hardware name: Qualcomm Technologies, Inc. kona standalone MTP (DT)

照着 debian 的 init 脚本抄下来的时候,刷入测试后发现这个内核不支持 devtmpfs。

[    1.678339] request_module fs-devtmpfs succeeded, but still no fs?

在我另一部较新的手机上,也不支持 devtmpfs

# cat /proc/filesystems | grep tmp
nodev   tmpfs
#

所以只能想办法帮忙处理 devtmpfs 的事情了

创建设备节点

根据文档以及 这个回答 可以了解到 devtmpfs 会自动创建设备节点,但这个内核没打开这个功能。这里可以用 busybox mdev -s 来创建设备节点

# busybox mdev
BusyBox v1.36.1 (Debian 1:1.36.1-9+b1) multi-call binary.

Usage: mdev [-vS] { [-s] | [-df] }

        -v      Verbose
        -S      Log to syslog too
        -s      Scan /sys and populate /dev
        -d      Daemon, listen on netlink
        -f      Run in foreground
...

创建完设备节点,也有 system 分区存储基本文件,但这些都是只读的。"你也不想跑起来的 GNU/linux 是挂载到只读文件系统上的吧?"

那么就需要打包 GNU/Linux 到 tgz 文件中,然后解压到读写的 /data 分区上

挂载 data 分区

观察 fstab 可以看到 /data 挂载到了某个物理分区上,但实际上他挂载到了 /dev/dm-10 上

olivine:/ # cat /vendor/etc/fstab.qcom
#<src>                                                 <mnt_point>            <type>  <mnt_flags and options>              <fs_mgr_flags>                                                                
/dev/block/bootdevice/by-name/userdata                  /data                  f2fs    noatime,nosuid,nodev,discard,...   latemount,wait,check,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized+wrappedkey_v0,metadata_encryption=aes-256-xts:wrappedkey_v0,keydirectory=/metadata/vold/metadata_encryption,quota,resize,reservedsize=128M,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,checkpoint=fs
....
olivine:/ # cat /proc/mounts  | grep /data                                                                                                                                                                                                    
/dev/block/dm-10 /data f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,fsync_mode=nobarrier 0 0
tmpfs /data_mirror tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,size=3911952k,nr_inodes=977988,mode=700,gid=1000 0 0
....

查看源码可以了解到

fs_mgr/fs_mgr.cpp

为了实现动态分区,/data 可能会在第一阶段已经挂载上去,这时只能用 dm-linear device-mapper 当做临时的 /data 分区使用。对于 dsu, 必定会使用 /dev/dm-?。

但在 init.sh, 如何知道从哪个节点挂载呢?

因此照着 init 的源码,简单写了个获取dm编号的程序

这个程序包含几个不同的组件, GetDmDevicePathByName 用来根据名称获取节点名称

按照 init 里的逻辑, 新创建的分区是空白的,挂载前需要格式化,所以又写了个自动格式化的程序

如果是空白分区则调用 /system/bin/mkfs.f2fs 执行格式化

然后使用 busybox 的 mount 正常挂载提供的节点,并解压打包好的 rootfs

探测输入设备

按照之前的文章,只需要 udevadm test /dev/input/event? 就可以把这些设备写入到 systemd 的数据库内,但 systemd 更新到某个版本后(>255.4),这个方法就失效了

所以现在只能先运行 udevd 再发送 trigger 了

# /usr/lib/systemd/systemd-udevd 
# udevadm trigger /dev/input/event?

加载固件

使用编写的 sh 脚本启动 labwc 后,提示缺少固件

[    9.846046] INIT: /bin/busybox chroot /data/root /bin/bash /wra/run.sh finished with return code: 139
[    9.846127] exec /bin/busybox chroot /data/root /sbin/init --log-level=debug --log-target=kmsg --default-standard-output=kmsg --default-standard-error=kmsg
[    9.862034] magiskinit: Fail to load policy from .magisk/selinux/load
....
[   12.007066] subsys-restart: __subsystem_get(): Changing subsys fw_name to venus
[   12.007112] subsys-pil-tz aab0000.qcom,venus: Falling back to syfs fallback for: venus.mdt
[   12.007644] subsys-pil-tz aab0000.qcom,venus: venus: Failed to locate venus.mdt(rc:-11)
[   12.007654] msm_vidc:   err : ffffffff: .....: Failed to download firmware
[   12.009064] msm_vidc:   err : ffffffff: .....: DBLP Set: status 0
[   12.010508] msm_vidc_v4l2 aa00000.qcom,vidc: Dropping the link to regulator.78
[   12.010521] msm_vidc_v4l2 aa00000.qcom,vidc: Dropping the link to regulator.79
[   12.010529] msm_vidc:   err : ffffffff: .....: Failed to load Venus FW
[   12.010534] msm_vidc:   err : ffffffff: .....: Core init failed
[   12.010539] msm_vidc:   err : 00000002: ....e: Failed to init core, id = 0
[   12.010544] msm_vidc:   err : 00000002: ....e: Failed to move from state: 1 to 3
[   12.010550] msm_vidc:   err : 00000002: ....e: msm_comm_kill_session: no session to kill for inst 00000000433fbabc
[   12.010555] msm_vidc:   err : 00000002: ....e: Failed to move video instance to init state
[   12.010592] msm_vidc:   err : ffffffff: .....: Failed to create instance, core: 0, type = 0

观察 ueventd 的源码(注释)可以了解到,他不仅创建了 /dev 目录下的设备节点

init/ueventd.cpp

还可以从接收到的 uevent 事件加载对应的固件

init/firmware_handler.cpp

而这个功能(Userspace Firmware Loading) systemd 并没有提供

所以静态编译了一份精简版的 ueventd,放到了 /system/bin 里面,也顺便替换掉了之前使用的mdev 程序。

为了防止 systemd-udevd 提前发送"找不到"的消息,顺便把 这个systemd rules 也禁用了。

# stub for immediately telling the kernel that userspace firmware loading
# failed; necessary to avoid long timeouts with CONFIG_FW_LOADER_USER_HELPER=y
- SUBSYSTEM=="firmware", ACTION=="add", ATTR{loading}="-1"
+# SUBSYSTEM=="firmware", ACTION=="add", ATTR{loading}="-1"

捉摸不透的显示

加载固件成功后,理论上可以正常显示输出了。也确实如此,但是有极大的概率花屏..

花屏时的样子

好苦恼啊..不会触发 kernel panic (因为 /sbin/init 进程跑起来了), 也不会进入 900E。

简单写了 panic trigger 来解决这个问题

可以保证60秒内如果 /data/root/wra/.trigger 没有变成空的话,就手动触发 sysrq-trigger

测试后..日志里也看不到有用的信息...

为了测试是否为 drm 的问题,找了个简单的入门程序,打开 drm 设备并随机写入一个颜色,等待5秒后关闭并退出。

drm-test 正在运行,此时屏幕被写入为淡蓝色

静态编译成 drm-test,每次启动前都先运行他。然后 labwc 很奇妙的就不再花屏了...

插上鼠标简单测试了一下

启动 systemd 和 cmst(一个简易的网络管理器) 后,没有wifi。

缺少 Type 为 wifi 的设备...

载入内核模块

查看安卓 init 进程的日志可以看到,启动时会加载 /vendor/lib/modules 内的内核模块,此处的“qca6390/qca6490”便是网络内核模块。

[    3.493304] init: Command 'symlink /vendor/bt_firmware /bt_firmware' action=early-init (/vendor/etc/init/hw/init.qcom.rc:42) took 0ms and failed: symlink() failed: Read-only file system
[    3.493586] init: Command 'symlink /vendor/dsp /dsp' action=early-init (/vendor/etc/init/hw/init.qcom.rc:43) took 0ms and failed: symlink() failed: Read-only file system
[    3.499056] init: starting service 'exec 2 (/vendor/bin/modprobe -a -d /vendor/lib/modules msm_11ad_proxy)'...
[    3.501498] init: SVC_EXEC service 'exec 2 (/vendor/bin/modprobe -a -d /vendor/lib/modules msm_11ad_proxy)' pid 616 (uid 0 gid 0+0 context u:r:vendor_modprobe:s0) started; waiting...
....
[    3.531967] init: Service 'exec 2 (/vendor/bin/modprobe -a -d /vendor/lib/modules msm_11ad_proxy)' (pid 616) exited with status 0 waiting took 0.031000 seconds
[    3.531993] init: Sending signal 9 to service 'exec 2 (/vendor/bin/modprobe -a -d /vendor/lib/modules msm_11ad_proxy)' (pid 616) process group...
[    3.532159] libprocessgroup: Successfully killed process cgroup uid 0 pid 616 in 0ms
[    3.532447] init: processing action (early-init) from (/vendor/etc/init/hw/init.target.rc:31)
[    3.532786] init: starting service 'exec 3 (/vendor/bin/modprobe -a -d /vendor/lib/modules audio_q6_pdr audio_q6_notifier audio_snd_event audio_apr audio_adsp_loader audio_q6 audio_native audio_usf audio_pinctrl_wcd audio_pinctrl_lpi audio_swr audio_platform audio_hdmi audio_stub audio_wcd_core audio_wsa881x audio_bolero_cdc audio_wsa_macro audio_va_macro audio_rx_macro audio_tx_macro audio_wcd938x audio_wcd938x_slave audio_machine_kona)'...
[    3.535184] init: SVC_EXEC service 'exec 3 (/vendor/bin/modprobe -a -d /vendor/lib/modules audio_q6_pdr audio_q6_notifier audio_snd_event audio_apr audio_adsp_loader audio_q6 audio_native audio_usf audio_pinctrl_wcd audio_pinctrl_lpi audio_swr audio_platform audio_hdmi audio_stub audio_wcd_core audio_wsa881x audio_bolero_cdc audio_wsa_macro audio_va_macro audio_rx_macro audio_tx_macro audio_wcd938x audio_wcd938x_slave audio_machine_kona)' pid 617 (uid 0 gid 0+0 context u:r:vendor_modprobe:s0) started; waiting...
....
[   12.465931] init: Service 'exec 23 (/vendor/bin/modprobe -a -d /vendor/lib/modules/ qca_cld3_qca6390 qca_cld3_qca6490)' (pid 1228) exited with status 0 oneshot service took 5.991000 seconds in background
[   12.465939] init: Sending signal 9 to service 'exec 23 (/vendor/bin/modprobe -a -d /vendor/lib/modules/ qca_cld3_qca6390 qca_cld3_qca6490)' (pid 1228) process group...
[   12.466033] libprocessgroup: Successfully killed process cgroup uid 0 pid 1228 in 0ms
....

在这里来说最"通用"的方法是按照 /vendor/lib/modules/modules.load 里的顺序全部加载,刚好 init 里也有这个函数

libmodprobe/libmodprobe.cpp

写个小组件调用即可

basePaths 为 module 所在的目录。useBlocklist 是否禁用 modules.blocklist 里的模块。strictMode 任何一个模块加载失败就退出

CNSS

想要高通的 cnss 网络子系统正常启动,需要 /vendor/bin/cnss-daemon 与 /vendor/bin/qrtr-ns 同时运行

前者提供了 cnss 子系统的固件 载入 校正 功能,是闭源的。

后者提供了 cnss 子系统的 qmi 网络功能,有社区开源实现。

需要对 /dev/ipa 写入 1 才能启动子系统。

需要对 /sys/kernel/cnss/fs_ready 写入 1 才能通知内核准备执行校正

总之很麻烦,也很 dirty。网上也没多少资料。

如果 cnss 没有正确初始化而载入了 wlan 网络模块的话,便会 kernel panic

[   33.649082] pm8150b_charger: smblib_run_aicl: re-running AICL
[   33.649318] FCC_MAIN: effective vote is now 3599978 voted by FCC_STEPPER_VOTER,1
[   33.649323] pm8150b_charger: is_cp_topo_vbatt: true
[   33.649340] pm8150b_charger: smblib_set_charge_param: fast charge current = 3599978 (0x47)
[   33.760053] cnss: fatal: Timeout waiting for FW ready indication
[   33.760115] subsys-restart: subsystem_restart_dev(): Restart sequence requested for wlan, restart_level = SYSTEM.
[   33.864080] Kernel panic - not syncing: subsys-restart: Resetting the SoC - wlan crashed.
[   33.864089] CPU: 0 PID: 663 Comm: kworker/0:4 Tainted: G S      W  O      4.19.157-perf+ #1
[   33.864094] Hardware name: Qualcomm Technologies, Inc. kona standalone MTP (DT)
[   33.864111] Workqueue: events device_restart_work_hdlr
[   33.864117] Call trace:
[   33.864126]  dump_backtrace+0x0/0x248
[   33.864133]  show_stack+0x14/0x20
[   33.864141]  dump_stack+0xb8/0xf4
[   33.864149]  panic+0x158/0x2d8
[   33.864154]  device_restart_work_hdlr+0x44/0x48
[   33.864162]  process_one_work+0x278/0x440
[   33.864167]  worker_thread+0x260/0x4a8
[   33.864174]  kthread+0x140/0x150
[   33.864180]  ret_from_fork+0x10/0x18
[   33.864191] SMP: stopping secondary CPUs
....

为了能运行这两个二进制文件,只能提取 Android GSI 里的 /system/lib64/* 以及 /system/bin/linker64 来创建基本的运行环境。

cnss 加载成功后,启动 cmst 连接网络,试着 ping一下,但是..

明明都 sudo 了为什么还会 Permission denied 呢

奇怪的网络

根据这个回答可以了解到安卓内核有个特别的Patch,只允许属于某些硬编码GID的用户访问网络。而且 postmarketos 也不要打开这个内核配置(CONFIG_ANDROID_PARANOID_NETWORK)

解决方法就是把使用网络的用户添加到 gid 为 3001 及以上的组里面

# groupadd -g 3001 aid_bt
# groupadd -g 3002 aid_bt_net
# groupadd -g 3003 aid_inet
# groupadd -g 3004 aid_net_raw
# groupadd -g 3005 aid_admin
# usermod -a -G aid_bt,aid_bt_net,aid_inet,aid_net_raw,aid_admin [someuser]

这里的用户不是有很多吗,后面可能也会创建不同的用户。

怎么打开屏幕键盘,修改后的软件更新怎么办?

触摸输入这些命令是不是太不方便了?

Control Panel

那就只能写一个软件来补充了,现在暂时是这个样子。

可以很方便的设置 labwc 的触摸输入旋转

FAQ

Q: 为什么只弄到网络?

A: 有了网络就方便装包,也可以电脑远程debug。

Q: 有项目地址吗?

A: github.com/SnowNF/wra.… 有帮助的话记得点个星星 作者会高兴好几天的..

Q: 有简单的展示吗?

A:

Since Thu 1970, 这个平板已经运行 54 年了 hahaha

连接的是 busybox 的 telnetd,所以 Terminal 是 busybox

Q: GSI的镜像“格式”

A: 使用了 system-as-root 所以是 system-arm64-ab.img

Q: 兼容性怎么样?

A: WORKS ON MY MACHINE, 我也不清楚呀..试试就知道啦。不过我的 8+gen1 的手机启动不了,没有日志,暂时不清楚什么原因。(可能是缺少/system/bin/snapuserd)

Q: 未来的计划?

A: 有空的话修修声音吧...如果有其他备用机的话也会试试,尝试提升一下兼容性。

Q: 性能怎么样?

A: 和上一篇文章一样,不过少了安卓服务所以RAM占用更少。