docker android 模拟器
背景
android 应用开发后,会有ci和自动化测试的需求,如何将android模拟器运行在docker上,
google 几年前在github上发布过相关的脚本解决这个问题,https://github.com/google/android-emulator-container-scripts
本文介绍实际操作和脚本的一些含义。
操作
本文操作环境是ubuntu 20.04.3
安装好Python
安装好 Docker
安装好 Docker-compose
首先clone
git clone https://github.com/google/android-emulator-container-scripts
目录结构如下
#ls -l
-rw-r--r-- 1 root root 157 12月 16 08:37 aemu-container.code-workspace
drwxr-xr-x 2 root root 4096 12月 16 08:37 cloud-init
-rwxr-xr-x 1 root root 1583 12月 16 08:37 configure.sh
-rw-r--r-- 1 root root 1101 12月 16 08:37 CONTRIBUTING.md
-rwxr-xr-x 1 root root 4034 12月 16 08:37 create_web_container.sh
drwxr-xr-x 4 root root 4096 12月 16 08:37 emu
drwxr-xr-x 8 root root 4096 12月 16 08:37 js
-rw-r--r-- 1 root root 11332 12月 16 08:37 LICENSE
-rw-r--r-- 1 root root 46 12月 16 08:37 MANIFEST.in
-rw-r--r-- 1 root root 164 12月 16 08:37 pyproject.toml
-rw-r--r-- 1 root root 18644 12月 16 08:37 README.md
-rw-r--r-- 1 root root 4359 12月 16 08:37 REGISTRY.MD
-rwxr-xr-x 1 root root 1440 12月 16 08:37 run-in-script-example.sh
-rwxr-xr-x 1 root root 899 12月 16 08:37 run.sh
-rwxr-xr-x 1 root root 1222 12月 16 08:37 run-with-gpu.sh
-rw-r--r-- 1 root root 781 12月 16 08:37 setup.cfg
-rw-r--r-- 1 root root 8386 12月 16 08:37 setup.py
drwxr-xr-x 3 root root 4096 12月 16 08:37 tests
-rw-r--r-- 1 root root 730 12月 16 08:37 tox.ini
-rw-r--r-- 1 root root 8553 12月 16 08:37 TROUBLESHOOTING.md
-rw-r--r-- 1 root root 68611 12月 16 08:37 versioneer.py
安装脚本命令,该命令会创建Python独立环境,同时安装emu_docker命令,emu_docker命令本质就是 emu_docker脚本
# source ./configure.sh
....
Ready to run emu-docker
列出可用的android系统镜像和模拟器
#emu-docker list
SYSIMG K android x86 19 https://dl.google.com/android/repository/sys-img/android/x86-19_r06.zip
SYSIMG K google_apis x86 19 https://dl.google.com/android/repository/sys-img/google_apis/x86-19_r40.zip
SYSIMG L android x86 21 https://dl.google.com/android/repository/sys-img/android/x86-21_r05.zip
SYSIMG L android-tv x86 21 https://dl.google.com/android/repository/sys-img/android-tv/x86-21_r03.zip
SYSIMG L google_apis x86 21 https://dl.google.com/android/repository/sys-img/google_apis/x86-21_r32.zip
SYSIMG L android x86 22 https://dl.google.com/android/repository/sys-img/android/x86-22_r06.zip
SYSIMG L android-tv x86 22 https://dl.google.com/android/repository/sys-img/android-tv/x86-22_r03.zip
SYSIMG L google_apis x86 22 https://dl.google.com/android/repository/sys-img/google_apis/x86-22_r26.zip
SYSIMG M android x86 23 https://dl.google.com/android/repository/sys-img/android/x86-23_r10.zip
SYSIMG M android-tv x86 23 https://dl.google.com/android/repository/sys-img/android-tv/x86-23_r21.zip
SYSIMG M google_apis x86 23 https://dl.google.com/android/repository/sys-img/google_apis/x86-23_r33.zip
SYSIMG N android x86 24 https://dl.google.com/android/repository/sys-img/android/x86-24_r08.zip
SYSIMG N android-tv x86 24 https://dl.google.com/android/repository/sys-img/android-tv/x86-24_r22.zip
SYSIMG N google_apis x86 24 https://dl.google.com/android/repository/sys-img/google_apis/x86-24_r27.zip
SYSIMG N google_apis_playstore x86 24 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-24_r19.zip
SYSIMG N android x86 25 https://dl.google.com/android/repository/sys-img/android/x86-25_r01.zip
SYSIMG N android-tv x86 25 https://dl.google.com/android/repository/sys-img/android-tv/x86-25_r16.zip
SYSIMG N google_apis x86 25 https://dl.google.com/android/repository/sys-img/google_apis/x86-25_r18.zip
SYSIMG N google_apis_playstore x86 25 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-25_r09.zip
SYSIMG O android x86_64 26 https://dl.google.com/android/repository/sys-img/android/x86_64-26_r01.zip
SYSIMG O android x86 26 https://dl.google.com/android/repository/sys-img/android/x86-26_r01.zip
SYSIMG O android-tv x86 26 https://dl.google.com/android/repository/sys-img/android-tv/x86-26_r14.zip
SYSIMG O google_apis x86_64 26 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-26_r16.zip
SYSIMG O google_apis x86 26 https://dl.google.com/android/repository/sys-img/google_apis/x86-26_r16.zip
SYSIMG O google_apis_playstore x86 26 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-26_r07.zip
SYSIMG O android x86_64 27 https://dl.google.com/android/repository/sys-img/android/x86_64-27_r01.zip
SYSIMG O android x86 27 https://dl.google.com/android/repository/sys-img/android/x86-27_r01.zip
SYSIMG O android-tv x86 27 https://dl.google.com/android/repository/sys-img/android-tv/x86-27_r09.zip
SYSIMG O google_apis x86 27 https://dl.google.com/android/repository/sys-img/google_apis/x86-27_r11.zip
SYSIMG O google_apis_playstore x86 27 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-27_r03.zip
SYSIMG P android x86_64 28 https://dl.google.com/android/repository/sys-img/android/x86_64-28_r04.zip
SYSIMG P android x86 28 https://dl.google.com/android/repository/sys-img/android/x86-28_r04.zip
SYSIMG P android-tv x86 28 https://dl.google.com/android/repository/sys-img/android-tv/x86-28_r10.zip
SYSIMG P google_apis x86_64 28 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-28_r11.zip
SYSIMG P google_apis x86 28 https://dl.google.com/android/repository/sys-img/google_apis/x86-28_r12.zip
SYSIMG P google_apis_playstore x86_64 28 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-28_r08.zip
SYSIMG P google_apis_playstore x86 28 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-28_r08.zip
SYSIMG P google_apis_playstore x86 28 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-28_r09.zip
SYSIMG Q android x86_64 29 https://dl.google.com/android/repository/sys-img/android/x86_64-29_r08-linux.zip
SYSIMG Q android x86 29 https://dl.google.com/android/repository/sys-img/android/x86-29_r08-linux.zip
SYSIMG Q android-tv x86 29 https://dl.google.com/android/repository/sys-img/android-tv/x86-29_r03.zip
SYSIMG Q google_apis x86_64 29 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-29_r12.zip
SYSIMG Q google_apis x86 29 https://dl.google.com/android/repository/sys-img/google_apis/x86-29_r12.zip
SYSIMG Q google_apis_playstore x86_64 29 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-29_r08-linux.zip
SYSIMG Q google_apis_playstore x86 29 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-29_r08-linux.zip
SYSIMG R android x86_64 30 https://dl.google.com/android/repository/sys-img/android/x86_64-30_r10.zip
SYSIMG R android-tv x86 30 https://dl.google.com/android/repository/sys-img/android-tv/x86-30_r03.zip
SYSIMG R google_apis x86_64 30 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-30_r11.zip
SYSIMG R google_apis x86 30 https://dl.google.com/android/repository/sys-img/google_apis/x86-30_r10.zip
SYSIMG R google_apis_playstore x86_64 30 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-30_r10-linux.zip
SYSIMG R google_apis_playstore x86 30 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86-30_r09-linux.zip
SYSIMG S android x86_64 31 https://dl.google.com/android/repository/sys-img/android/x86_64-31_r03.zip
SYSIMG S android-tv x86 31 https://dl.google.com/android/repository/sys-img/android-tv/x86-31_r03.zip
SYSIMG S google_apis x86_64 31 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-31_r09.zip
SYSIMG S google_apis_playstore x86_64 31 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-31_r09.zip
SYSIMG S google_apis x86_64 32 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-32_r03.zip
SYSIMG Tiramisu google_apis x86_64 32 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-Tiramisu_r01.zip
SYSIMG S google_apis_playstore x86_64 32 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-32_r03-linux.zip
SYSIMG Tiramisu google_apis_playstore x86_64 32 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-Tiramisu_r01.zip
EMU canary 31.3.4 macosx https://dl.google.com/android/repository/emulator-darwin_x64-8220659.zip
EMU canary 31.3.4 linux https://dl.google.com/android/repository/emulator-linux_x64-8220659.zip
EMU canary 31.3.4 windows https://dl.google.com/android/repository/emulator-windows_x64-8220659.zip
EMU stable 31.2.8 linux https://dl.google.com/android/repository/emulator-linux_x64-8143646.zip
EMU stable 31.2.8 windows https://dl.google.com/android/repository/emulator-windows_x64-8143646.zip
EMU stable 31.2.8 macosx https://dl.google.com/android/repository/emulator-darwin_x64-8143646.zip
EMU开头是模拟器,其他是系统镜像,我们选择其中一个版本下载,同时下载linux版本模拟器。
//下载系统镜像 SYSIMG S android x86_64 31
wget https://dl.google.com/android/repository/sys-img/android/x86_64-31_r03.zip
//下载模拟器 EMU stable 31.2.8 linux
wget https://dl.google.com/android/repository/emulator-linux_x64-8143646.zip
基于系统镜像和模拟器创建dockerfile,dockerfile用于创建android 模拟器 的 docker image
//emu-docker create <emulator-zip> <system-image-zip> [--dest docker-src-dir (getcwd()/src by default)]
emu-docker create 模拟器.zip 系统镜像.zip --dest src
//--dest 指定生成dockerfile的存放路径,默认就是 pwd/src. 所以--dest src可以不加
官方说emu-docker create没有生成可用的镜像,需要 docker build 生成。 但实际生成了。也就是不用 src 目录下docker build . 镜像也存在了。
当然也可以跟官方的操作执行docker build . 再创建一个镜像。
This places all the right elements to run a docker image, but does not build, run or publish yet. A Linux emulator zip file must be used.
cd src
docker build .
主要生成的docker镜像有2个
#android系统docker镜像
us-docker.pkg.dev/android-emulator-268719/images/sys-31-aosp-x64
上面android 系统镜像的docker镜像,基于模板 Dockerfile.system_image 生成.
Dockerfile.system_image主要步骤
拷贝android系统镜像,解压
基于 nvidia/opengl:1.2-glvnd-runtime-ubuntu20.04 创建镜像
拷贝解压的系统镜像到容器 /android/sdk/system-images/android/ 目录
拷贝 adb
chmod +x adb
#模拟器docker镜像
us-docker.pkg.dev/android-emulator-268719/images/31-aosp-x64-no-metrics
模拟器docker镜像 基于模板 Dockerfile.emulator 生成
Dockerfile.emulator主要步骤
基于 上面的android系统docker镜像
安装相关依赖
拷贝 launch-emulator.sh 脚本(容器启动用) 到 容器 /android/sdk/目录
设置容器启动命令:启动执行 launch-emulator.sh
src目录下生成的docekrfile 就是基于Dockerfile.emulator模板的,这也是为什么说(官方说emu-docker create没有生成可用的镜像,需要 docker build 生成。 但实际生成了).
运行容器
docker run -d \
-e ADBKEY="$(cat ~/.android/adbkey)" \
--device /dev/kvm \
--publish 8554:8554/tcp \
--publish 5555:5555/tcp \
us-docker.pkg.dev/android-emulator-268719/images/31-aosp-x64-no-metrics
--device /dev/kvm 表示需要用到kvm设备用于硬件加速,所以宿主机要支持kvm,本地机器没问题,但是放到阿里云k8s服务上会有问题,因为没有kvm。不过阿里云有个 弹性云手机服务
通过adb 连接设备
adb connect localhost:5555
也可以安装 scrcpy投屏
image.png
launch-emulator.sh
介绍下launch-emulator.sh
主要是安装证书,运行模拟器
LAUNCH_CMD=emulator/emulator
var_append LAUNCH_CMD -avd Pixel2
var_append LAUNCH_CMD -ports 5556,5557 -grpc 8554 -no-window
var_append LAUNCH_CMD -skip-adb-auth -no-snapshot-save -wipe-data -no-boot-anim
var_append LAUNCH_CMD -shell-serial file:/tmp/android-unknown/kernel.log
var_append LAUNCH_CMD -logcat "*:V"
var_append LAUNCH_CMD -logcat-output /tmp/android-unknown/logcat.log
var_append LAUNCH_CMD -logcat "*:V"
var_append LAUNCH_CMD -feature AllowSnapshotMigration
var_append LAUNCH_CMD -gpu swiftshader_indirect {{extra}}
上面是构造运行模拟器的命令 emulator/emulator ....
其中 -grpc 8554 是用于对客户端开放 grpc服务,被 android-emulator-webrtc 用到。
也是网页端显示和操纵模拟器的基础。
模拟器 grpc说明 emulator grpc
web端操作
生成3个镜像
./create_web_container.sh -h
emulator_nginx
emulator_envoy
//就是us-docker.pkg.dev/android-emulator-268719/images/31-aosp-x64-no-metrics
emulator_emulator
web端操作主要是通过grpc和android-emulator-webrtc
ngnix用于web端代理.
Envoy 也是代理,istio中的sidecar就是用的Envoy。这里用于proxy grpc给 android-emulator-webrtc 组件。
运行
docker-compose -f js/docker/docker-compose.yaml up
Docker-compose 文件对emulator_nginx,emulator_envoy,emulator_emulator 3个服务作了编排。
启动3个容器后就可以通过浏览器访问模拟器了。