Occasionally, I work on some Android apps and in order to test them, I have a computer connected to a few phones running a self-hosted github runner hooked into the CI on the repositories for these apps.
The CI was recently failing so I checked on the phones. It turns out because they were connected, they were continually charging and caused the batteries to very nearly fail. I decided I needed to find a solution to use an emulator for the tests.
![file](/uploads/image-1629049082799.jpg)
I have previously tried this github action: [https://github.com/marketplace/actions/android-emulator-runner](https://github.com/marketplace/actions/android-emulator-runner), however, it requires the macOS VM because it exposes hardware acceleration. I tried this, it works fine, but it means you run out of your free actions credits quite quickly.
So instead I wanted to make use of my existing self-hosted runner. In a previous post, I had setup the self-hosted runner with ansible: [https://www.jasonernst.com/posts/2021/04/10/Automatically-Deployable-Self-Hosted-Github-Actions-Runner-via-Docker-%26-Ansible](https://www.jasonernst.com/posts/2021/04/10/Automatically-Deployable-Self-Hosted-Github-Actions-Runner-via-Docker-%26-Ansible)
Android runs a repository with some containers now which run the emulator in them, so I made use of this: [https://github.com/google/android-emulator-container-scripts](https://github.com/google/android-emulator-container-scripts)
Once the container is up, you just need to tell adb about it, and everything works as before. So the two things I needed to do, was let the github-runner container from previously connect to the new container with the emulator, and then inside the github actions logic, tell adb to connect to the new container with the emulator in it.
So in ansible:
```
# https://github.com/myoung34/docker-github-actions-runner
- name: Github Actions Runner
tags: gh-actions
vars:
ansible_python_interpreter: "/usr/bin/env python3-docker"
docker_container:
name: github-runner
image: myoung34/github-runner:latest
pull: true
volumes:
- "/dev/bus/usb:/dev/bus/usb"
- "/var/run/docker.sock:/var/run/docker.sock"
- "/tmp/github-runner-your-repo:/tmp/github-runner"
restart_policy: unless-stopped
privileged: true
env:
ACCESS_TOKEN: "{{ github_access_token }}"
RUNNER_NAME: home.jasonernst.com
RUNNER_WORKDIR: /tmp/github-runner
RUNNER_GROUP: default
REPO_URL: https://github.com/compscidr/grape-networking-java
LABELS: "self-hosted"
ORG_RUNNER: "false"
links:
- "android-emulator"
# https://github.com/google/android-emulator-container-scripts
- name: Android Emulator
tags: android-emulator
vars:
ansible_python_interpreter: "/usr/bin/env python3-docker"
docker_container:
name: android-emulator
image: us-docker.pkg.dev/android-emulator-268719/images/30-google-x64:30.1.2
pull: true
restart_policy: unless-stopped
devices:
- "/dev/kvm"
ports:
- "5555:5555"
```
Notice, the links which connects the runner to the new container. Also, notice the devices in the new container, which is required in order for the emulator to work. I'll leave it as an exercise for the reader to ensure kvm is working, but you can test with the `kvm-ok` command (you likely need to install the `cpu-checker` package on ubuntu to check this).
Next, in the github actions workflow, I made a slight modification. Where it previously ran the connectedCheck, I now had it connecting to adb and waiting for devices:
```
android_checks:
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: set up JDK 11
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11.0.4'
- name: Setup Android SDK
uses: android-actions/setup-android@v2.0.7
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
- name: check app dependency update
run: ./gradlew app:generatePomFileForDebugPublication && diff app/pom.xml app/build/publications/debug/pom-default.xml
- name: lint
run: ./gradlew app:lint
- name: app lint results
uses: yutailang0119/action-android-lint@v1.1.0
with:
xml_path: app/build/reports/lint/report.xml
- name: checkstyle
run: ./gradlew app:checkstyle
- name: junit5 instrumented tests (with jacoco coverage reports))
run: adb connect android-emulator:5555 && adb wait-for-device && ./gradlew app:connectedCheck && ./gradlew app:jacocoTestDebugUnitTestReport
- uses: actions/upload-artifact@v2
with:
name: app-reports
path: app/build/reports
```