嗯,好像距离上次研究Halium已经过了很久了。虽然一直没时间弄这个,但是没全部驱动心里一直不太服气,最近还是抽出时间来把它弄好了(好了,但没完全好)。小米平板4终于有机会可以摆脱“大手机”的称号,可以弄一点生产力方面的事情,虽然还是有很多坑,不过作为一个看看视频、写写码的小电脑还是可以胜任的。个人不是很懂lineage os & halium的适配,很多commit都是照搬各位大神的,希望未来有大神能有时间帮我完善一下这个项目。
Droidian项目
感觉Ubuntu Touch采用的mir+lomiri的图形界面方案对于我的需求还是太过于遥远了,尽管ubuntu touch可以使用容器运行一部分xorg和wayland的应用,但是用不了3d加速和奇怪的兼容性,导致android + chroot可能要来的更为实用和方便一点。底层一直卡在Ubuntu 16.04也是我决定选用其他Halium发行版的原因之一。
幸运的是我找到了mobian项目的一个分支droidian,它基于debian11,图形界面使用的phosh,wayland的使用使得大部分linux程序都可以没有压力的运行,它也打包了xorg的hybris驱动,halium上的linux终于可以像pc上的linux一样自由切换桌面了。但是目前droidian还处于很早期的开发阶段,可能不是很稳定。
迷惑的 Treble
Project Treble是谷歌在android 8推出的技术,它通过在原来的分区表划分中多出一个vendor分区,把用户层的那一套对接hal的驱动程序独立出来。只需要一个通用的system.img就能让同一个系统在不同的设备上运行。
Droidian为了项目发展的方便,同样也采用了treble包(gsi)的形式发布它们的刷机包。很多支持treble的手机只需要通过修改内核就能跑起来,但也只限于出厂就带有安卓9 vendor的设备(不知道表述的准不准确,反正我的设备用gsi的halium会卡在keymaster验证那里)。小米平板4就处于这种尴尬的位置,出厂时恰好是8.1的vendor分区,而且官方不肯出安卓9以上的更新,也只能通过编译出halium的system.img来适配Droidian了。
跑起wifi
高通的安卓内核wifi部分做的很复杂,相较于主线中的驱动程序只需要内核驱动和固件到位就能跑起来,还需要用户空间里的私有库和守护进程(cnss-daemon)正常工作才能把wifi跑起来。有一个部分的模块的启动时间不对都会导致wifi没有办法启动,比如说halium里面的安卓是作为一个lxc容器来启动的,会比一般的安卓启动的更慢一些,wifi的内核模块在很早之前加载很有可能会导致cnss-daemon得不到mac地址,所以Halium的wifi驱动必须以ko内核模块的形式在合适的时候加载,才可以跑通wifi。一个修改的例子就如下所示,ko模块的加载需要自己处理(module-load.d),Halium是不会帮你加载安卓vendor分区的内核模块的。
--- a/arch/arm64/configs/clover_halium_defconfig
+++ b/arch/arm64/configs/clover_halium_defconfig
@@ -1780,7 +1780,7 @@ CONFIG_ATH_CARDS=y
# CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS is not set
# CONFIG_ATH5K_PCI is not set
# CONFIG_ATH6KL is not set
-CONFIG_WIL6210=y
+CONFIG_WIL6210=m
CONFIG_WIL6210_ISR_COR=y
CONFIG_WIL6210_TRACING=y
CONFIG_WIL6210_WRITE_IOCTL=y
@@ -4103,7 +4103,7 @@ CONFIG_ION_MSM=y
#
# Qualcomm Atheros CLD WLAN module
#
-CONFIG_QCA_CLD_WLAN=y
+CONFIG_QCA_CLD_WLAN=m
CONFIG_QCACLD_WLAN_LFR3=y
CONFIG_PRIMA_WLAN_OKC=y
CONFIG_PRIMA_WLAN_11AC_HIGH_TP=y
@@ -4155,7 +4155,7 @@ CONFIG_RMNET_IPA3=y
# CONFIG_IPA_UT is not set
CONFIG_GPIO_USB_DETECT=y
# CONFIG_MSM_MHI is not set
-CONFIG_MSM_11AD=y
+CONFIG_MSM_11AD=m
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_MSM_EXT_DISPLAY=y
下面就开始用户空间里wifi部分的debug了,在device仓库里面,红米note7的ubuntu touch移植有这样一个commit。
diff --git a/BoardConfig.mk b/BoardConfig.mk
index 991cea0..be799da 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -246,11 +246,11 @@ BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flag 2
# WiFi
BOARD_HAS_QCOM_WLAN := true
BOARD_HAS_QCOM_WLAN_SDK := true
-BOARD_WLAN_DEVICE := qcwcn
+#BOARD_WLAN_DEVICE := qcwcn
BOARD_HOSTAPD_DRIVER := NL80211
-BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
+#BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
-BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
+#BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
WIFI_DRIVER_FW_PATH_AP := "ap"
WIFI_DRIVER_FW_PATH_STA := "sta"
WIFI_DRIVER_FW_PATH_P2P := "p2p"
我一开始认为同一个芯片做的修改应该都差不多,所以就直接把这个commit搬到我的仓库里面了。结果就是cnss-daemon找不到一些动态链接库一直起不来。仔细分析以后发现红米note7的vendor里已经包含了这个commit注释掉的东西的产物了,而小米平板4没有,所以做如下修改cnss-daemon就应该能启动wifi了。
@@ -239,7 +240,7 @@ VENDOR_SECURITY_PATCH := 2019-04-01
# Wifi
BOARD_HAS_QCOM_WLAN := true
BOARD_HAS_QCOM_WLAN_SDK := true
-#BOARD_WLAN_DEVICE := qcwcn
+BOARD_WLAN_DEVICE := qcwcn
BOARD_HOSTAPD_DRIVER := NL80211
#BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
后来才发现是vendor的问题,有些cnss-daemon必须要wifi以模块形式编译才能启动。
触摸屏
这里本来在ubuntu touch里面已经调通了,但是在droidian里面没有反应,在内核日志里面和安卓的日志里都没有发现有什么关于触摸屏的报错。直接cat /dev/input/event* 设备,再操作触摸屏发现有数据出来。最后锁定是udev的问题,给udev加入一条新的语句就行了。
# Goodix Touchscreen
ACTION=="add", KERNEL=="input[0-9]*", SUBSYSTEM=="input", ATTRS{name}=="goodix-ts", ENV{ID_INPUT}=="1", ENV{ID_INPUT_TOUCHSCREEN}="1"
Droidian 设备专用包的适配
就如前文所说的,Droidian并没有提供如何生成设备专用包的教程,能利用的就只有一个gsi刷机包。
研究一番后发现,Droidian和Ubuntu Touch挂载安卓系统分区的方式不是完全一样,Droidian是直接把安卓的rootfs作为系统的一个包放在/var/lib/lxc/android下,而Ubuntu Touch是通过halium-install脚本把安卓rootfs和ubuntu touch的rootfs放在/data下,注意这里的安卓rootfs和GNU/Linux的rootfs都是linux mount指令能够直接挂载的格式。
So,把Halium生成的system.img直接转换成ext4 img的形式,然后直接替换掉rootfs中的安卓rootfs就行了,转换指令如下。
$ simg2img system.img android-rootfs.img
# 调整镜像至合适的大小
$ resize2fs -M android-rootfs.img
在twrp中把修改过的刷机包、vendor.img、halium-boot.img依次刷入就可以进入Droidian系统了!
GitHub Action 构建系统的完善
在前面写的文章里面,我提到了一个白嫖Github Action编译Halium的方案,但是最近好像Github的容器加了一些东西(大概1-2G),以前恰好能够在硬盘塞满之前弄出system.img的那个action已经行不通了。
由easimon/maximize-build-space这个项目得知github其实除了容器默认的60G数据盘之外还存在一个放swap的盘,好像有10多个G,所以只需要把容器里面没用的软件弄掉,减少swap空间,再弄一个硬盘池把这两个盘包含进来,大体上可以获得80G左右的空间,编译和上传镜像应该绰绰有余了。
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/buildvg-buildlv 78G 57M 78G 1% /home/runner/work/halium
Action脚本放在这里有需求的可以直接弄到你们的Action里面
- name: Cleanup Disk
uses: HandsomeYingyan/cleanup-disk-action@v3.0
- name: Maximize build space
uses: easimon/maximize-build-space@master
with:
root-reserve-mb: 512
swap-size-mb: 1024
build-mount-path: '$ANDROID_ROOT'
多启动?
理论上多启动(安卓与Halium共存)是可行的,Halium在设计上就只占用了boot分区和data分区的一部分,这个在双boot分区的平台上很好弄,只需要一个分区装安卓的boot.img另一个装halium-boot.img通过选择启动的boot分区就能做到。但是小米平板4只有一个boot.img分区,可能需要牺牲recovery分区来实现双启动,使用进recovery的方式进到另一个系统,但是没时间弄而且也不需要安卓,这个方案以后有时间再试试。
效果
运行Vscode
neofetch
运行Gnome40
系统资源
phosh桌面
相关链接
github项目主页
小米平板4的github action以及Halium镜像下载
droidian项目
droidian镜像下载(GSI API 28)
未完待续
目前整个系统处于比较可用的状态,但是还有传感器、相机、流量上网还没有搞完的。另外还有很多小细节不是很完美,希望有一天我能把这些东西都弄出来吧。。。