1. 为什么要在 Ubuntu 22.04 上折腾 Redroid 云手机Redroid 这个项目全称是 Remote Android本质上是把 Android 系统跑在 Linux 容器里通过 Docker 直接拉起一个完整的 Android 运行时。它跟传统模拟器的区别在于模拟器是跑在用户态的一套虚拟化方案而 Redroid 是直接利用宿主机的 Linux 内核能力binder、ashmem 等把 Android 的运行时环境塞进容器里。这意味着它的启动速度、资源占用、密度都比传统方案好一大截特别适合做云手机、自动化测试、群控这类场景。我最早接触 Redroid 是因为手头有一批自动化任务需要在 Android 环境里跑用模拟器开十几个实例机器就卡得不行后来换成 Redroid同样一台机器能跑三十多个实例还游刃有余。但问题也随之而来——官方文档写得比较简略尤其是镜像编译和 GPU 加速这两块踩坑的人特别多。网上能搜到的教程要么是直接docker pull现成镜像要么是编译到一半报错就没了下文。这篇文章要解决的就是这个痛点从零开始在 Ubuntu 22.04 上完整走一遍 Redroid 镜像的编译流程并且把 GPU 加速配置讲透。适合谁看如果你手上有 Ubuntu 服务器或者开发板比如 RK3588 这类 ARM 平台想自己编译 Redroid 镜像而不是用现成的或者你已经在用 Redroid 但发现画面卡顿、GPU 没吃上那这篇内容应该能帮到你。需要提前说明的是Redroid 的编译对宿主机环境有比较明确的要求Ubuntu 22.04 是目前兼容性最好的版本之一。整个流程大致分四块环境准备、源码拉取与编译、GPU 加速配置、镜像打包与验证。我会按实际操作顺序来写中间穿插我踩过的坑和对应的解法。2. 编译前的环境准备别急着敲命令2.1 宿主机系统与内核的硬性门槛很多人编译失败的第一步就卡在环境上。Redroid 对内核有明确要求不是随便一个 Ubuntu 22.04 就能跑。核心依赖是binder和ashmem这两个内核模块Android 的进程间通信和内存管理全靠它们。Ubuntu 默认内核里 ashmem 是没有的binder 也可能没编译进去。先确认你的内核版本uname -rUbuntu 22.04 默认是 5.15 系列内核这个版本本身是支持的但需要额外加载模块。检查模块是否存在ls /lib/modules/$(uname -r)/kernel/drivers/android/如果这个目录不存在或者里面没有 binder_linux.ko 和 ashmem_linux.ko那你就得自己编译内核模块。这是整个流程里最容易被忽略的一步。我见过太多人直接跳到 Docker 那一步结果容器起来就报binder: not found。对于不想折腾内核编译的朋友有个取巧的办法Ubuntu 22.04 的linux-modules-extra包里其实带了部分 Android 模块。先试试sudo apt install linux-modules-extra-$(uname -r) sudo modprobe binder_linux sudo modprobe ashmem_linux如果modprobe没报错lsmod | grep -E binder|ashmem能看到输出那恭喜你这步过了。如果报Module not found那就得走内核编译路线后面我会单独讲。提示如果你用的是云服务器很多厂商的定制内核会裁掉 Android 相关模块这种情况下建议换一台标准 Ubuntu 22.04 的机器或者直接用物理机。2.2 编译工具链的安装清单环境确认没问题后装编译工具。Redroid 的编译依赖 AOSP 那套工具链但比完整 AOSP 轻量很多。以下是我实测下来必须装的包sudo apt update sudo apt install -y git-core gnupg flex bison build-essential zip curl \ zlib1g-dev libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev \ libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip \ fontconfig python3 python3-pip这里面有几个包容易漏lib32ncurses5-dev和lib32z1-dev是编译 32 位工具用的缺了会在编译中途报错libc6-dev-i386也是同理。另外python3必须是 3.8 以上Ubuntu 22.04 自带的 3.10 没问题。装完基础工具后还需要 repo 工具来管理源码mkdir -p ~/bin curl https://storage.googleapis.com/git-repo-downloads/repo ~/bin/repo chmod ax ~/bin/repo export PATH~/bin:$PATH把export PATH这行加到~/.bashrc里不然新开终端又找不到 repo 了。这个坑我踩过编译到一半换了个终端窗口结果 repo 命令没了。2.3 Docker 环境的版本选择Redroid 最终是以 Docker 镜像形式交付的所以 Docker 必须装。Ubuntu 22.04 自带的 Docker 版本偏老建议用官方源装最新稳定版sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io装完之后把当前用户加进 docker 组省得每次都要 sudosudo usermod -aG docker $USER newgrp docker这里有个细节newgrp docker只对当前终端生效其他已经打开的终端还是得重新登录。我一般直接sudo reboot一劳永逸反正编译前重启一次也不亏。3. 源码拉取与编译耐心比技术更重要3.1 Redroid 源码的获取方式Redroid 的源码托管在 GitHub 上官方仓库是remote-android/redroid-doc但真正的编译脚本在redroid-script里。我建议直接克隆编译脚本仓库git clone https://github.com/remote-android/redroid-script.git cd redroid-script这个仓库里包含了针对不同 Android 版本的编译脚本目前支持 Android 9、10、11、12、13。选哪个版本我的建议是如果没有特殊需求选 Android 11 或 12。Android 9 太老很多新应用装不上Android 13 刚出不久GPU 驱动兼容性还在完善中。Android 11 是目前最稳的社区支持也最好。进入对应版本的目录cd redroid-script/11.0你会看到几个关键文件Dockerfile、build.sh、config.json。build.sh是主编译脚本Dockerfile定义了最终镜像的构建方式。3.2 编译参数的取舍逻辑打开build.sh看一眼里面有几个关键参数需要根据你的机器调整。我挑几个最重要的说第一个是TARGET_ARCH。这个决定了编译出来的镜像架构。如果你在 x86_64 机器上编译默认是 x86_64如果是 RK3588 这类 ARM 开发板要改成 arm64。改错了会在编译早期就报架构不匹配。第二个是TARGET_BUILD_VARIANT。可选user、userdebug、eng。做云手机建议用userdebug因为它保留了 root 权限和调试接口方便后续 adb 连接和调试。user版本太封闭eng版本又太臃肿。第三个是WITH_GPU。这个参数控制是否编译 GPU 支持。如果你后面要用 GPU 加速这里必须打开。但打开之后编译时间会明显变长因为要额外编译 Mesa 驱动和相关的图形库。我一般会先改build.sh里的这几行export TARGET_ARCHarm64 export TARGET_BUILD_VARIANTuserdebug export WITH_GPUtrue改完之后别急着跑先确认一下磁盘空间。完整编译一次大概需要 60-80GB 的磁盘空间如果空间不够编译到一半会报No space left on device。用df -h看一眼不够的话先清理或者挂载新盘。3.3 编译过程中的资源监控与常见报错编译命令很简单./build.sh但跑起来之后才是真正的考验。整个编译过程视机器性能而定8 核 16G 的机器大概要 2-3 小时16 核 32G 能压缩到 1 小时左右。编译期间 CPU 会跑满内存占用也会飙升建议不要在这台机器上跑其他重负载任务。我整理了几个高频报错和对应的解法报错信息根本原因解决方案binder: not found内核模块未加载执行modprobe binder_linux或重新编译内核No space left on device磁盘空间不足清理/var/lib/docker或扩容磁盘fatal error: ncurses.h缺少 32 位开发库安装lib32ncurses5-devrepo: command not foundPATH 未配置将~/bin加入 PATHOut of memory内存不足减少并行编译任务数或加 swap其中Out of memory这个最恶心因为它是随机出现的有时候编译到 90% 才崩。解法是在build.sh里限制并行任务数export MAKE_JOBS4默认是用nproc的值也就是所有核心全开。内存不够的话把MAKE_JOBS设成核心数的一半甚至更低。慢是慢点但至少能跑完。注意编译过程中如果中断了不要直接重新跑./build.sh先执行make clean清理中间产物否则残留的临时文件会导致各种奇怪的链接错误。4. GPU 加速配置让云手机画面不再卡顿4.1 GPU 加速的两种技术路线Redroid 的 GPU 加速有两条路可走软件渲染和硬件直通。软件渲染用的是 SwiftShader纯 CPU 跑图形计算兼容性无敌但性能拉胯开个 3D 游戏直接卡成幻灯片。硬件直通则是把宿主机的 GPU 能力透传给容器性能接近原生但配置复杂对驱动版本有要求。我建议只要宿主机有独立 GPUNVIDIA 或 AMD就一定要走硬件直通。如果是 Intel 核显也可以走 VA-API 路线但兼容性稍差。下面重点讲 NVIDIA 和 AMD 两种显卡的配置方式。先确认宿主机 GPU 被正确识别lspci | grep -E VGA|3D能看到显卡型号就说明硬件没问题。接下来装驱动NVIDIA 用官方驱动AMD 用 Mesa 开源驱动。4.2 NVIDIA 显卡的直通配置NVIDIA 这块需要装nvidia-driver和nvidia-container-toolkit。驱动版本建议 515 以上太老的版本不支持容器直通。sudo apt install -y nvidia-driver-525 sudo reboot重启后验证nvidia-smi能看到显卡信息就说明驱动装好了。接着装 container toolkitcurl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed s#deb https://#deb [signed-by/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt update sudo apt install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker配置完成后启动 Redroid 容器时加上--gpus all参数docker run -itd --privileged --gpus all \ -p 5555:5555 \ redroid/redroid:11.0.0-latest \ androidboot.redroid_gpu_modehost这里的androidboot.redroid_gpu_modehost是关键它告诉 Redroid 使用宿主机 GPU 而不是软件渲染。4.3 AMD 与 Intel 核显的 VA-API 方案AMD 显卡走的是 Mesa 的 VA-API 路线配置相对简单因为 Mesa 驱动是开源的Ubuntu 22.04 自带。先确认 VA-API 可用sudo apt install -y vainfo vainfo如果输出里能看到VAProfileH264之类的条目说明 VA-API 正常工作。然后启动容器时把 GPU 设备节点挂进去docker run -itd --privileged \ --device /dev/dri:/dev/dri \ -p 5555:5555 \ redroid/redroid:11.0.0-latest \ androidboot.redroid_gpu_modeguest注意这里的gpu_mode是guest因为 AMD 和 Intel 核显是通过 Mesa 在容器内做渲染而不是直接透传设备。/dev/dri目录下是显卡的设备节点挂进去之后容器内的 Mesa 就能调用。Intel 核显的配置和 AMD 基本一样也是挂/dev/dri区别在于驱动包。Intel 需要额外装intel-media-va-driversudo apt install -y intel-media-va-driver-non-free4.4 GPU 加速效果的验证方法配置完 GPU 之后怎么确认真的生效了最直接的办法是进容器跑一个图形测试。先连上 adbadb connect localhost:5555 adb shell进去之后查看 GPU 渲染器信息adb shell dumpsys SurfaceFlinger | grep GLES如果输出里显示的是NVIDIA或Mesa相关的渲染器名称说明 GPU 加速生效了。如果显示的是SwiftShader那还是软件渲染得回去检查配置。另一个验证方式是跑个 3D 基准测试比如安兔兔的 GPU 测试项。软件渲染下分数通常只有硬件渲染的十分之一左右差距非常明显。我实测下来NVIDIA 直通后 GPU 分数能到原生设备的 80% 以上AMD VA-API 大概在 60-70%Intel 核显在 50% 左右。提示GPU 加速配置完成后建议把容器重启一次再测试因为有些驱动初始化只在容器启动时执行一次。5. 镜像打包与多实例部署5.1 从编译产物到可分发镜像编译完成后产物在out/target/product/目录下里面有一堆.img文件。但这时候还不能直接用需要打包成 Docker 镜像。Redroid 的build.sh最后一步其实已经帮你做了这件事它会自动执行docker build生成镜像。查看生成的镜像docker images | grep redroid应该能看到类似redroid/redroid:11.0.0_arm64的条目。如果你想把这个镜像分发到其他机器可以导出成 tar 包docker save redroid/redroid:11.0.0_arm64 -o redroid_11_arm64.tar然后在目标机器上导入docker load -i redroid_11_arm64.tar这里有个坑导出的 tar 包会非常大动辄 2-3GB传输的时候注意网络带宽。另外不同架构的镜像不能混用x86_64 的镜像导到 ARM 机器上是跑不起来的。5.2 多实例并行的资源分配策略云手机的核心价值在于密度一台机器上跑多少个实例直接决定了成本。Redroid 的多实例部署很简单就是起多个容器每个容器映射不同的端口for i in $(seq 1 10); do docker run -itd --privileged --gpus all \ -p $((5555i)):5555 \ --name redroid_$i \ redroid/redroid:11.0.0_arm64 \ androidboot.redroid_gpu_modehost \ androidboot.redroid_width720 \ androidboot.redroid_height1280 \ androidboot.redroid_dpi320 done这段脚本会起 10 个实例端口从 5556 到 5565。每个实例的分辨率设成 720x1280DPI 320这是比较省资源的配置。如果你要跑 1080P 的实例内存占用会翻倍。资源分配上我的经验是每个实例预留 1.5GB 内存和 2 个 CPU 核心。比如 32GB 内存、16 核的机器跑 15-18 个实例比较稳。超过这个数容器之间会开始抢资源表现为画面卡顿、操作延迟。GPU 方面NVIDIA 显卡支持多容器共享但显存是硬限制。一个 1080P 的 Redroid 实例大概占 300-500MB 显存8GB 显存的卡跑 10 个实例就到顶了。AMD 和 Intel 核显共享系统内存没有独立的显存限制但会挤占系统内存。5.3 实例管理中的几个实用技巧跑起来之后管理这些实例也是个麻烦事。我分享几个自己常用的技巧批量操作用docker ps配合xargsdocker ps -q --filter nameredroid_ | xargs -I {} docker stop {}这行命令能一次性停掉所有 Redroid 容器。日志排查用docker logsdocker logs redroid_1 --tail 100如果某个实例起不来先看日志大部分问题日志里都有线索。数据持久化用 volume 挂载docker run -itd --privileged \ -v /data/redroid_1:/data \ ...这样容器删了数据还在重装应用不用重来。不过要注意多个实例不能挂同一个数据目录会冲突。网络隔离方面如果实例之间需要互相隔离可以创建自定义 Docker 网络docker network create redroid_net docker run --network redroid_net ...这样实例之间可以通过容器名互相访问但跟宿主机网络隔离。6. 踩坑实录那些文档里不会写的问题6.1 编译到 90% 突然报错怎么办这个问题我遇到过三次每次都是不同的原因。第一次是磁盘满了/var/lib/docker把根分区撑爆了。第二次是内存不够编译到链接阶段 OOM。第三次最诡异是系统时间不对导致某些文件的 timestamp 校验失败。排查这类问题的通用思路是先看日志最后 50 行找到第一个 error 而不是最后一个。编译报错往往是连锁反应第一个错误才是根因。比如你看到最后报的是linker error但往上翻会发现真正的问题是某个.o文件没生成再往上翻是编译那个文件时缺了头文件。如果日志太长不好翻可以把输出重定向到文件./build.sh 21 | tee build.log然后grep -n error build.log | head -20快速定位。6.2 GPU 加速开启后画面反而更卡这个坑很反直觉但确实存在。原因是 GPU 直通之后如果驱动版本和容器内的 Mesa 版本不匹配会出现渲染路径回退反而比纯软件渲染还慢。判断方法是在容器里跑adb shell dumpsys SurfaceFlinger | grep GLES如果显示的是Mesa但版本号很老或者显示llvmpipe这是软件渲染的另一种形式那就说明驱动没对上。解法是升级宿主机的 Mesasudo add-apt-repository ppa:kisak/kisak-mesa sudo apt update sudo apt upgrade这个 PPA 提供了比较新的 Mesa 版本对 Redroid 的兼容性更好。不过要注意升级 Mesa 之后可能需要重启宿主机才能生效。6.3 容器启动后 adb 连不上的排查链路adb 连不上是最常见的问题排查链路我整理成了一张表现象检查点命令connection refused容器是否在运行docker psconnection refused端口是否映射docker port redroid_1unauthorizedadb 密钥是否授权adb kill-server adb start-serveroffline容器内 adbd 是否启动docker exec redroid_1 ps -ef | grep adbd连上但黑屏GPU 模式是否正确检查gpu_mode参数大部分情况下adb kill-server再重连就能解决。如果不行进容器手动重启 adbddocker exec -it redroid_1 sh setprop ctl.restart adbd还有一个隐藏坑如果你之前连过其他 Redroid 实例adb 可能会缓存旧的连接信息。这时候需要adb disconnect清掉旧连接再重连。6.4 内核模块加载失败的终极解法如果modprobe binder_linux一直报错而你又不想重装系统那就只能自己编译内核模块。步骤不复杂但耗时sudo apt install -y linux-headers-$(uname -r) build-essential git clone https://github.com/anbox/anbox-modules.git cd anbox-modules make sudo make install sudo modprobe binder_linux sudo modprobe ashmem_linux这个 anbox-modules 仓库里的 binder 和 ashmem 模块是专门为容器化 Android 准备的兼容性比内核自带的还好。编译大概需要 5-10 分钟装完之后lsmod能看到模块就成功了。注意每次内核升级后这些模块都需要重新编译安装。所以如果你经常更新系统建议把编译命令写成一个脚本升级后跑一下就行。7. 关于性能调优的一些个人经验编译和部署都跑通之后剩下的就是调优了。我分享几个实测有效的参数调整CPU 调度策略方面把容器的 CPU 调度改成performance模式能明显降低操作延迟echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor内存回收方面Redroid 容器跑久了内存会涨可以在启动参数里加androidboot.redroid_memory_limit1536限制每个实例的内存上限防止单个实例吃光所有内存。磁盘 IO方面如果实例多建议把 Docker 的数据目录放到 SSD 上机械硬盘跑十几个实例会卡到怀疑人生。改 Docker 数据目录的方法是编辑/etc/docker/daemon.json{ data-root: /ssd/docker }然后重启 Docker 服务。最后说一个我自己的体会Redroid 这套方案的上限其实取决于宿主机内核和 GPU 驱动的成熟度。Ubuntu 22.04 是目前最省心的选择但如果你用的是 ARM 开发板比如 RK3588内核适配的工作量会大很多建议优先考虑社区已经有成功案例的板子。GPU 加速这块NVIDIA 的体验最好AMD 次之Intel 核显适合对性能要求不高的场景。编译一次镜像虽然耗时但编译出来的镜像可以反复用长期来看是划算的。
