前言

手机空间不够,某天想上云星铁的时候看到排队人数直接劝退,于是寻思能不能自己搞一台云安卓设备,然后看到群友在香橙派上用redroid挂BA脚本。看了看手头的设备后,做NAS的N5105已经虚拟化了一堆,有核显的x86就剩我的J4125软路由了,反正性能过剩。(

采用的设备为J4125,openwrt为lean的lede,并且已开启docker。接下来的操作全部基于docker开启的条件,需要修改源码重新编译,因为redroid最低为android8,需要在内核开启binder。


源码的内核配置部分修改

截止到这篇文章时,lean的lede在x86_64平台上默认内核版本为6.6。所以修改target/linux/x86/config-6.6。

坑大是因为redroid的readme没有说内核要开哪些东西,能看到的只有binder和ashmem,而这两玩意都是android内核源码里才用的。redroid的作者提供了redroid-modules,里面有binder和ashmem模块,但是因为较旧所以在6.6内核上需要修复。但其实Binder已经进内核主线了(drivers/android/),而ashmem(drivers/staging/android)可以被memfd代替,故不需要用到redroid-modules。

在config-6.6文件最底部追加下述

CONFIG_PSI=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDERFS=y
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
CONFIG_UDMABUF=y
CONFIG_DMABUF_HEAPS=y
CONFIG_DMABUF_SYSFS_STATS=y
CONFIG_DMABUF_HEAPS_SYSTEM=y
CONFIG_CMA=y
CONFIG_CMA_DEBUGFS=y
CONFIG_CMA_SYSFS=y
CONFIG_CMA_AREAS=7
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CMA_SIZE_SEL_MBYTES=y
CONFIG_CMA_ALIGNMENT=8
CONFIG_DMABUF_HEAPS_CMA=y
CONFIG_XEN_GRANT_DMA_ALLOC=y
CONFIG_XEN_GNTDEV_DMABUF=y
  • 主要要开的就是binder和dmabuf,剩下的是为了把DMABUF部分全开起来而开的。

  • PSI是因为android 10开始弃用了LMK而使用了LMKD(低内存终止守护程序)而开的。redroid的issue区有提到lmkd起不来的情况,故开启先。

  • DMA_HEAP是需要开启codec2支持,不然scrcpy会在redroid中报错List of video encoders: (none)。在issue中[server] INFO: List of video encoders: (none)有提到。


源码的内核patch部分修改

大坑二号

在上面部分,开启了dmabuf后scrcpy报错依旧没变化。然后发现/dev下并没有dma_heap节点。手动创建无果,最后发现/sys/class/dma_heap/system/下面什么都没有。于是经过一翻搜寻后,在openwrt官方的issue下找到了这篇dma-heap is not getting integrated into the kernel
由于904-debloat_dma_buf.patch这个补丁修改了dmabuf的makefile,导致system_heap.c根本没有进行编译。故对其补丁进行修改。
补丁位置:target/linux/generic/hack-6.6/904-debloat_dma_buf.patch

/drivers/dma-buf/Makefile部分

@@ -1,12 +1,14 @@

@@ -1,12 +1,15 @@

然后

+obj-$(CONFIG_DMABUF_HEAPS)            += heaps/

+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += heaps/system_heap.o
+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA)        += heaps/cma_heap.o

即可。
不放心的话编译时去build_dir中的linux kernel部分找下这块有没有生成.o就行了。


镜像选用

在x86_64的openwrt上测试了所有redroid镜像,最后发现能正常使用的只有Android 14 64bit only。
arm64没有设备测。

其中,android8.1,9,10,12都可以启动,adb可以连接,但scrcpy连接报空指针,但是控制台看service list可以发现服务没起来。logcat基本都是刷net相关问题,但都是fake error,具体不知道什么原因导致没有启动。

android11,13的镜像运行几秒后自动退出,宿主机的dmesg可以看到相关日志,说是打不开/dev/binder。但是在/dev/binder手动挂载上去的情况下一样报错。(binder挂载参考issue:There is no /dev/binder.... binder is always missing in /dev/ )在issuebinderfs create failed中有提到相关,但是最新的11镜像已经修复,而我这边测得就是最新镜像,故跳过该版本。

android14镜像能运行但是进shell发现连logd服务都没启动。

android12_64only版本可以启动,scrcpy连进去后有画面,但是systemui一直崩溃,参照issue redroid-12.0.0-arm64 SystemUI持续崩溃没有改善。

android13_64only启动失败,好像也是binder问题。
此为本人测试,仅供参考。

最后只有14的64only启动正常。


redroid docker参数配置

我这边用到的参数是:

androidboot.redroid_width=720
androidboot.redroid_height=1280
androidboot.redroid_dpi=320
androidboot.use_memfd=true
androidboot.redroid_gpu_mode=host
androidboot.redroid_fps=60
ro.product.cpu.abilist=x86_64,arm64-v8a
ro.product.cpu.abilist64=x86_64,arm64-v8a
ro.dalvik.vm.isa.arm64=x86_64
ro.enable.native.bridge.exec=1
ro.dalvik.vm.native.bridge=libndk_translation.so

其中,memfd代替ashmem,720p减小性能消耗,我intel uhd600可以驱动所以gpu_mode是宿主机。转译层方面由于我使用的是64only镜像,故只能最多到arm64。


(可选)openwrt添加相关启动命令

echo 1 > /sys/fs/cgroup/cpuset/docker/cgroup.clone_children

用于修复logcat里一直刷的一个couldn't write错误,couldn't write [pid] to /dev/cpuset/foreground/tasks: No space left on device

mkdir /dev/binderfs
mount -t binder binder /dev/binderfs

手动挂载binderfs,实测不需要手动挂载也能启动android12和14的64only版本。


后记

最终还是没能达到我想要的效果,在14 64only镜像上,BA国服运行后黑屏,看到logcat中写system died。。。米家崩/原/铁全部闪退,log看到是unity相关库的问题,应该是ndk翻译层兼容性问题。方舟闪退,log报什么fingerprint太长?但是看issue好像是说改了fingerprint也没用。能正常运行的测试出来只有FGO和公主连结R。。。。。

scrcpy通吃PC,android,ios
iOS上没上商店不知道,我越狱直装的。
scrcpy-mobile(ios版)
scrcpy-android
scrcpy (PC)

Openwrt虽然是Linux但是相比正常的linux发行版还是太不一样(例如没有systemd,我都不知道切cgroup版本的命令在op上是啥)。所以在这上面运行redroid花的时间比较长,相关资料没有。全靠根据日志去翻redroid的issue。再加上修改内核部分我没有编译成modules,直接builtin了,(确保无玄学问题)所以每次都得编译然后刷入。

也测试过类似的东西dockdroid,这玩意就是部署一个linux发行版,在里面kvm跑blissos。但是图形加速必须有X11,op没这玩意。直通显卡的话没试,直通感觉在op上会很麻烦,有兴趣的可以试试。吃性能比redroid大不少。(

下次有设备还是在原生arm64上跑把,应该兼容性会强很多。