Introduction

Android のアプリをデモして自由に触らせたいという要望があった。
まんま 独自のクラウド エミュレータを作成する の内容なんだけど、これは Google Compute Engine (GCE) で、コンソールを通じて提供される代物。
だけど要望は、 **Amazon Web Services (AWS)**。
なので、GCE で使われている仕組みを手組する必要がある。

幸い、これらは https://github.com/google/android-emulator-container-scripts として提供されている。

が、調べたところ、日本語の記事は Android Emulator Container Scriptsを使ってDocker上でAndroidエミュレータを動かす くらい。

で、上の指示通りにやればできそうな気がするんだけど、なんか順番というか、途中で「ん?このファイル、どのタイミングで作られるの?」って感じで躓いた。
結局、自分は英語の別記事を参考にして環境を構築したので、自分なりの備忘録として残す。

How to use?

前提

1
2
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
  • docker-compose
  • KVM
    • クラウドで実行する場合
      • Azure の場合、ネストされた仮想化 (Nested Virtualization) が有効であること
      • AWS の場合、ベアメタルインスタンスを使用
        • むしろ、AWS だけがこのような制約。他の クラウドプラットフォームは Azure と同様。

注意

Python を使用し、依存パッケージの状態によっては、バージョンアップによって、動かなくなる時があるので適宜対処が必要

ツールのインストール

22.04

Android SDKPython 3.10 venvNodeJSnpm をインストール。

1
$ sudo apt-get install -y android-sdk python3.10-venv nodejs npm

20.04

Android SDKPython 3 venvNodeJSnpm をインストール。

1
$ sudo apt-get install -y android-sdk python3-venv nodejs npm

~/.android/adbkey の作成

Android SDK をインストール後、

1
2
3
4
 adb devices
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached

ソースの取得

特定のコミットのソースをクローン。最新版でも構わないが、動いたのこれなので、メモとして残しておいた。

1
2
3
4
$ mkdir android-emulator-container-scripts
$ cd android-emulator-container-scripts
$ git clone https://github.com/google/android-emulator-container-scripts .
$ git checkout 94592e7dbb46d28ec46497c0bdd00c3a95afe1cc

以後は、このフォルダで作業を行う。

仮想環境の構築

android-emulator-container-scripts 直下にあるスクリプトを source で実行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ source ./configure.sh
Using python 3
Requirement already satisfied: pip in ./venv/lib/python3.10/site-packages (22.0.2)
Collecting pip
Downloading pip-22.2.2-py3-none-any.whl (2.0 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.0/2.0 MB 7.9 MB/s eta 0:00:00
Installing collected packages: pip

(略)

Processing textwrap3-0.9.2-py2.py3-none-any.whl
Installing textwrap3-0.9.2-py2.py3-none-any.whl to /home/user/work/android-emulator-container-scripts/venv/lib/python3.10/site-packages
Adding textwrap3 0.9.2 to easy-install.pth file

Installed /home/user/work/android-emulator-container-scripts/venv/lib/python3.10/site-packages/textwrap3-0.9.2-py3.10.egg
Finished processing dependencies for emu-docker==0+untagged.301.g94592e7
Ready to run emu-docker!

実行が終わると、仮想環境に切り替わる。

注意

ここで、emu-docker コマンドが使えるかどうかを試すこと。
実行すると

1
2
3
4
5
6
7
8
9
10
11
12
13
$ emu-docker
Traceback (most recent call last):
File "/home/t-takeuchi/work/android-emulator-container-scripts2/venv/bin/emu-docker", line 33, in <module>
sys.exit(load_entry_point('emu-docker', 'console_scripts', 'emu-docker')())
File "/home/t-takeuchi/work/android-emulator-container-scripts2/venv/bin/emu-docker", line 25, in importlib_load_entry_point
return next(matches).load()
File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 171, in load

(略)

ImportError: cannot import name 'soft_unicode' from 'markupsafe' (/home/user/work/android-emulator-container-scripts/venv/lib/python3.10/site-packages/MarkupSafe-2.1.1-py3.10-linux-x86_64.egg/markupsafe/__init__.py)

(venv) user@TERMINAL:~/work/android-emulator-container-scripts$ python -m pip install markupsafe==2.0.1

となる時がある。
Python の依存パッケージのバージョンアップしており、API が壊れている。
そのため、強制的にインストールしなおす。

1
$ python -m pip install markupsafe==2.0.1

再度実行すると、下記のように無事に動くはず。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ emu-docker
usage: emu-docker [-h] [-v] {list,licenses,create,interactive,cloud-build} ...

List and create emulator docker containers (0+untagged.301.g94592e7).

positional arguments:
{list,licenses,create,interactive,cloud-build}
list list all the available the publicly available emulators and system images.
licenses Lists all licenses and gives you a chance to accept or reject them.
create Given an emulator and system image zip file, generates a Docker image comprising complete environment in which the Android Emulator runs. After the Docker image is started up, interaction with the emulator is
made possible via port forwarding and ADB, or gRPC and WebRTC.
interactive Interactively select which system image and emulator binary to use when creating a docker container
cloud-build Create a cloud builder distribution. This will create a distribution for publishing container images to a GCE repository.This is likely only useful if you are within Google.

options:
-h, --help show this help message and exit
-v, --verbose Set verbose logging (default: False)

実行したいエミュレータを調べる

emu-docker list を実行すると、実行可能なエミュレータとイメージの一覧を取得できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ 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 Tiramisu android-tv x86 32 https://dl.google.com/android/repository/sys-img/android-tv/x86-Tiramisu_r03.zip
SYSIMG S google_apis x86_64 32 https://dl.google.com/android/repository/sys-img/google_apis/x86_64-32_r03.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 TiramisuPrivacySandbox google_apis_playstore x86_64 33 https://dl.google.com/android/repository/sys-img/google_apis_playstore/x86_64-TiramisuPrivacySandbox_r06.zip
EMU canary 31.3.8 macosx https://dl.google.com/android/repository/emulator-darwin_x64-8598121.zip
EMU canary 31.3.8 linux https://dl.google.com/android/repository/emulator-linux_x64-8598121.zip
EMU canary 31.3.8 windows https://dl.google.com/android/repository/emulator-windows_x64-8598121.zip
EMU beta 31.3.10 macosx https://dl.google.com/android/repository/emulator-darwin_x64-8807927.zip
EMU beta 31.3.10 linux https://dl.google.com/android/repository/emulator-linux_x64-8807927.zip
EMU beta 31.3.10 windows https://dl.google.com/android/repository/emulator-windows_x64-8807927.zip
EMU stable 31.3.10 linux https://dl.google.com/android/repository/emulator-linux_x64-8807927.zip
EMU stable 31.3.10 windows https://dl.google.com/android/repository/emulator-windows_x64-8807927.zip
EMU stable 31.3.10 macosx https://dl.google.com/android/repository/emulator-darwin_x64-8807927.zip

例えば。Android R が欲しいなら、grep で絞り込める。

1
2
3
4
5
6
7
$ emu-docker list | grep R
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

Android R の場合、下記のようなイメージが利用できる。

種別 アーキテクチャ 名称
Android x86_64 android
Android TV x86 android-tv
Android (Google API 付き) x86_64 google_apis
Android (Google API 付き) x86 google_apis
Android (Google API と Playstore 付き) x86_64 google_apis_playstore
Android (Google API と Playstore 付き) x86 google_apis_playstore

がある。

また、エミュレータは、各ホスト OS に対応するものが提供されている。

リリースチャネル OS
canary macosx
canary linux
canary windows
beta macosx
beta linux
beta windows
stable macosx
stable linux
stable windows

がある。

エミュレータの docker イメージ作成

例えば、emulator は stable、Android のイメージはバニラなバイナリを使いたい場合は、下記のように指定する。

1
$ emu-docker create stable "R android x86_64"

または、直接 zip をダウンロードして、指定する方法もある。

1
2
3
$ curl -O 'https://dl.google.com/android/repository/emulator-linux_x64-8807927.zip'
$ curl -O 'https://dl.google.com/android/repository/sys-img/android/x86_64-30_r10.zip'
$ emu-docker create emulator-linux_x64-8807927.zip x86_64-30_r10.zip

上記のどちらかを実行すると、docker イメージのビルドが始まる。
Google API 付きイメージを指定した場合は、ライセンスへの同意が求められるので適宜対応。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
WARNING:Please opt in or out of metrics collection.
You will receive this warning until an option is selected.
To opt in or out pass the --metrics or --no-metrics flag
Note, that metrics will only be collected if you opt in.
Downloading platform tools to /home/user/work/android-emulator-container-scripts/platform-tools-
100%|█████████████████████████████████████████████████████████████████████████████████████████████████
docker build /home/user/work/android-emulator-container-scripts/src -t us-docker.pkg.dev/android
Step 1/14 : FROM alpine:3.3 AS unzipper
---> a6fc1dbfa81a
Step 2/14 : RUN apk add --update unzip
---> Running in 7fbb84a724c6
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
(1/1) Installing unzip (6.0-r1)
Executing busybox-1.24.2-r2.trigger
OK: 5 MiB in 12 packages
Removing intermediate container 7fbb84a724c6

(略)

---> 88ceedcefc7b
Successfully built 88ceedcefc7b
Successfully tagged us-docker.pkg.dev/android-emulator-268719/images/30-aosp-x64-no-metrics:8807927

Web アクセスインターフェースの構築

docker-compose によって提供される Web インターフェースを動かすための docker イメージを作成。

create_web_container.sh を使用する。
引数には <username>,<password> と、Web インターフェースにログインするユーザ情報を指定する。複数指定可能。

下記は user1 と user2 を指定した例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ./create_web_container.sh -p user1,password1,user2,password2
make: Entering directory '/home/user/work/android-emulator-container-scripts/js'

up to date, audited 1632 packages in 17s

82 packages are looking for funding
run `npm fund` for details

(略)

Successfully built be471d032521
Successfully tagged emulator_nginx:latest
Created container, you can launch it as follows:
docker-compose -f js/docker/docker-compose-build.yaml up

エミュレータとブラウザは下記の図に従ってやり取りされる模様。

web
(引用:https://source.android.com/static/docs/devices/automotive/images/avd_cloud_01.png?hl=ja)

注意

1
2
3
4
ERROR: pip's dependency resolver does not currently take into account all the packages that are instal
led. This behaviour is the source of the following dependency conflicts.
emu-docker 0+untagged.301.g94592e7.dirty requires jinja2==2.11.1, but you have jinja2 3.1.2 which is i
ncompatible.

となる時がある。

setup.py に明示的に jinja2 のバージョンが指定されているためである。
そのため、手動で下記のように書き換え、

1
2
-       "jinja2==2.11.1",
+ "jinja2",

仮想環境に入りなおし、jinja2 をインストールしなおすことで対処する。

1
2
source ./configure.sh
python -m pip install jinja2==3.1.2

コンテナの起動・停止

ADB を使わない場合

起動

1
$ docker-compose -f js/docker/docker-compose.yaml up -d

停止

1
$ docker-compose -f js/docker/docker-compose.yaml down

ADB を使う場合

起動

1
$ docker-compose -f js/docker/docker-compose.yaml -f js/docker/development.yaml up -d

停止

1
$ docker-compose -f js/docker/docker-compose.yaml -f js/docker/development.yaml down

ブラウザからのアクセス

80 ポートで待機しているので、アクセスしてみる。

web

create_web_container.sh 実行時に指定したユーザ名とパスワードを使用してログインする。

web

真っ黒な画面が出るが、右上の赤枠のアイコンを押下するとエミュレータ側の描画が始まる。

web

ちなみに、全ての処理は共有しているので、別ユーザでログインしているかどうかで、画面が異なることは無い。
別ユーザが操作した内容はそのまま、自分の画面に適用される。

アプリのインストール

ADB を使って起動している場合、 *.apk をインストールできる。

まず adb から起動している adb サーバーに接続。接続後、デバイスの認識を確認。

1
2
3
4
5
$ adb connect localhost:5555
connected to localhost:5555
$ adb devices
List of devices attached
localhost:5555 device

接続確認後、下記でインストールが可能。

1
2
3
4
5
$ adb install <apk ファイルのパス>
* daemon not running; starting now at tcp:5037
* daemon started successfully
Performing Streamed Install
Success

多重起動しているエラーが出たら

1
2
$ adb emu kill 
$ adb kill-server

で対処。