尝试在RISC-V上运行Waydroid

我头脑发热为了那小破比赛淘了块电子垃圾,比赛结束后绞尽脑汁想榨干他的剩余价值。

众所周知,MilkV Jupiter是一个8核16G内存的RISC-V PC,既然内存这么大,那么就从开虚拟机榨干内存开始吧!但是这破CPU并没有实现H扩展,KVM是没可能了,那么就玩玩容器,欸,Android我玩了老久了,就玩个Android容器Waydroid吧~

折腾结果: Waydroid勉强在MilkV Jupiter(SpaceMiT X60, Ubuntu 23.10)上跑了起来,使用llvmpipe调用CPU渲染,很卡,连玩具的水平都没有...

但是这玩意的好处是通用性,理论上可以在合适的RISC-V机器上的使用Wayland的桌面环境中运行。

Current Status: WIP

On MilkV Jupiter(SpaceMiT X60, Ubuntu 23.10), it can boot into home launcher, but extremely slow. Ideally it can work on every RISC-V Linux using desktop environment with Wayland support.

项目地址/Project HomePage

效果图

可以在项目首页查看

食用方法

安装软件包

对于Ubuntu 22.04及24.04,可以直接添加PPA源:

sudo add-apt-repository ppa:tanyuliang2/waydroid-riscv
sudo apt update

对于Ubuntu 23.10(MilkV Jupiter上我测试运行的版本),可以在Github这里下载deb安装。

下载镜像并初始化waydroid

镜像system.imgvendor.img可以从Github这里下载,并拷贝到/usr/share/waydroid-extra/images目录下。

使用如下命令初始化之后,在桌面上启动waydroid就能食用啦。

sudo waydroid init -f

MilkV Jupiter上额外的设置

gralloc不能从GPU的/dev/card0分配显存,但是可以从SoC的display engine /dev/card1获取。

首先修改/var/lib/waydroid/waydroid.cfg,在[properties]节添加以下设置,然后sudo waydroid upgrade -o更新

[properties]
gralloc.gbm.device = /dev/dri/card1

然后修改/var/lib/waydroid/lxc/waydroid/config_nodes

在/dev/card0那一行后加一行:

lxc.mount.entry = /dev/dri/card0 dev/dri/card0 none bind,create=file,optional 0 0
lxc.mount.entry = /dev/dri/card1 dev/dri/card1 none bind,create=file,optional 0 0

过程记录

了解Android on RISC-V支持

直至写文章这一刻,似乎没有找到Google官方明确说某个版本支持RISC-V的,而根据google的这个仓库的构建指南来看,应该是Android 14开始提供官方支持。这个说法和T-Head他们的Android on RISC-V的路线图似乎是一致的。

RISC-V社区方面,有这个RISC-V Android仓库,这个有PLCT Lab的参与,最终选定构建android 10的waydroid也是使用了他们仓库的patches。

还有一个arv仓库,他们做的事情可能是在jh7100的板子上跑起来Android,根据这里的描述来看,Android 12是能够启动的,但也同样缺乏GPU驱动的支持。

而T-Head那边,通过licheepi 4a官网找到了这个项目是T-Head官方的Android支持,看上去应该是Android 14并且有GPU驱动的支持。

尝试构建redroid 14

在尝试构建waydroid镜像前,我先是尝试了redroid,因为redroid有android 14的支持,但是结果连ART虚拟机都开不动...构建过程中也遇到很多麻烦,看起来好像对RISC-V的支持还不太足够?也可能是我漏了一些patch或者版本太老(redroid 14是android14.0.0_r2),缺了一些代码,由于我对这块知之甚少,于是很快放弃了直接构建redroid 14的想法。

报错日志:

08-27 03:39:20.638   131   131 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 131 (main), pid 131 (main)08-27 03:39:20.677   198   198 W crash_dump64: failed to read selinux label: Bad file descriptor
08-27 03:39:20.695   198   198 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto                          08-27 03:39:20.696    43    43 I tombstoned: received crash request for pid 131                                                             08-27 03:39:20.697   198   198 I crash_dump64: performing dump of process 131 (target tid = 131)                                            08-27 03:39:21.050   198   198 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***                                  08-27 03:39:21.050   198   198 F DEBUG   : Build fingerprint: 'redroid/redroid_riscv64/redroid_riscv64:14/UP1A.231005.007.A1/eng.root.20240811.134956:userdebug/test-keys'
08-27 03:39:21.050   198   198 F DEBUG   : Revision: '0'
08-27 03:39:21.050   198   198 F DEBUG   : ABI: 'riscv64'
08-27 03:39:21.050   198   198 F DEBUG   : Timestamp: 2024-08-27 03:39:20.715055098+0000
08-27 03:39:21.050   198   198 F DEBUG   : Process uptime: 2s
08-27 03:39:21.050   198   198 F DEBUG   : Cmdline: zygote64
08-27 03:39:21.050   198   198 F DEBUG   : pid: 131, tid: 131, name: main  >>> zygote64 <<<
08-27 03:39:21.050   198   198 F DEBUG   : uid: 0
08-27 03:39:21.050   198   198 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
08-27 03:39:21.050   198   198 F DEBUG   : Cause: null pointer dereference
08-27 03:39:21.051   198   198 F DEBUG   :     gp  000000385d2ea000  tp  000000385ccf9cc8  t0  00000000705c1408  t1  000000362b5e2c6c
08-27 03:39:21.051   198   198 F DEBUG   :     t2  0000000000000000  t3  000000384fab22a0  t4  000000362b5d025c  t5  000000362b5d0304
08-27 03:39:21.051   198   198 F DEBUG   :     t6  000000362b5d03c4  s0  000000379e3ca380  s1  000000382e3ca560  s2  0000000000000000
08-27 03:39:21.051   198   198 F DEBUG   :     s3  0000003fe226dfb0  s4  0000000000000000  s5  0000003fe226e050  s6  0000003fe226dfb0
08-27 03:39:21.051   198   198 F DEBUG   :     s7  000000362b9fb498  s8  0000000000000001  s9  0000003fe226dfc8  s10 0000000000000000
08-27 03:39:21.051   198   198 F DEBUG   :     s11 0000003fe226dfec  a0  0000003fe226dfd8  a1  0000000000000000  a2  0000000000000000
08-27 03:39:21.051   198   198 F DEBUG   :     a3  000000379e3cadd0  a4  000000379e3cab7f  a5  0000003fe226df58  a6  0000003fe226e050
08-27 03:39:21.051   198   198 F DEBUG   :     a7  0000000000000000
08-27 03:39:21.051   198   198 F DEBUG   :     pc  000000362b2d8e1a  ra  000000362b5cfd3a  sp  0000003fe226dd10
08-27 03:39:21.051   198   198 F DEBUG   : 45 total frames
08-27 03:39:21.051   198   198 F DEBUG   : backtrace:
08-27 03:39:21.051   198   198 F DEBUG   :       #00 pc 00000000004b9e1a  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+296) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #01 pc 00000000007b0d36  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #02 pc 00000000004ab226  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.__uniq.112435418011751916792819755956732575238)+476) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #03 pc 000000000079db9e  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+1108) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #04 pc 00000000007b1632  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #05 pc 00000000007b148e  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #06 pc 000000000035d90a  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+394) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #07 pc 00000000004b27ac  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+2004) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #08 pc 00000000004bd1a6  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+13492) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.051   198   198 F DEBUG   :       #09 pc 00000000007b0d36  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #10 pc 00000000004ab226  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.__uniq.112435418011751916792819755956732575238)+476) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #11 pc 000000000079db9e  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+1108) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #12 pc 00000000007b1632  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #13 pc 00000000007b148e  /apex/com.android.art/lib64/libart.so (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #14 pc 000000000035d90a  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+394) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #15 pc 0000000000387e26  /apex/com.android.art/lib64/libart.so (art::ClassLinker::InitializeClass(art::Thread*, art::Handle<art::mirror::Class>, bool, bool)+2622) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #16 pc 000000000036c8e6  /apex/com.android.art/lib64/libart.so (art::ClassLinker::EnsureInitialized(art::Thread*, art::Handle<art::mirror::Class>, bool, bool)+132) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #17 pc 00000000007b39c4  /apex/com.android.art/lib64/libart.so (NterpGetStaticField+412) (BuildId: 13579e0aad0c837425ffd1e426e48095)
08-27 03:39:21.052   198   198 F DEBUG   :       #18 pc 00000000004c186e  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+31612) (BuildId: 13579e0aad0c837425ffd1e426e48095)

了解LLVM的JIT支持

redroid和waydroid最开始的编译我都使用swiftshader作为渲染后端,但是我发现都不能正常启动,随后又尝试切换到mesa的llvmpipe似乎都不能工作。

开始的时候并不知道LLVM的JIT的深坑,只是看到这里,适配swiftshader on RISC-V的作者倡议升级到LLVM13,一时半会儿弄不明白为啥要升级,稀里糊涂地也跟着升,就是把waydroid的llvm_project的lineage18分支直接backport到lineage17,这个仓库的LLVM版本是17。后来在这里才了解到LLVM的JIT支持是LLVM15之后才达到开箱可用的状态。

LLVM的JIT链接器有两种实现: RuntimeDyld(MCJIT的组件)和JITLink(OrcJIT的组件),JITLink的支持已经添加到了RISC-V中,而RuntimeDyld因为官方宣布不再支持因而没有RISC-V支持的相关patch合并。

Mesa

这篇笔记和arv仓库中jh7100设备树做过的尝试来看,SpaceMiT X60上用的这个GPU如果用开源驱动可能很大概率是驱动不了的,所以初期计划暂时不考虑使用GPU,而是使用软件方式(LLVMPIPE)进行渲染。

因为前面提到RISC-V上LLVM的JIT链接器只有JITLink,但是Mesa一直使用的是MCJIT,也就是使用RuntimeDyld作为链接器,也就是不支持RISC-V架构的。

但是在这个合并请求之后的版本中,Mesa是能够在RISC-V上运行的。搜索这个作者的相关信息,顺藤摸瓜找到了他为(版本23.2的Mesa做的patch)[https://github.com/YukariChiba/deepin-mesa/commit/8d5e7c317493d459948e8cf6f29110e39f823ca0],刚好waydroid仓库里lineageos18分支下有使用相同版本的,看起来成功概率挺大,就选择了lineageos18.1-mesa23.2这个分支加上那个patch的方案。

此外,23.2版本(或者稍微更早一些的版本)的Mesa的Android.mk有些变化,不能正常在Android 10的AOSP工程中编译,报错提示缺少某些头文件,在Mesa上搜到了这个合并请求,参考对应部分做了修改后成功编译。

打好patch的mesa仓库我放在了Github上,在这里

系统镜像构建方法

参考Waydroid的文档克隆Lineageos项目并打上Waydroid的补丁,然后合并RISC-V Android仓库下所有项目的RISC-V补丁。

合并补丁的版本及相应的manifest.xml随后放出...关键的设备树,LLVM及Mesa库已经放在了Github上

标签: none

添加新评论