Android Emulator with Github Actions on Linux

#actions #android #ci #emulator #github #kvm #self-hosted

 

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

I have previously tried this github action: 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

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

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

Comments (0)


Leave a Comment

Log in to leave a comment.

Most Recent Post

Searching the Parts of the Internet Google Doesn't: Five Years of darksearch.xyz

There's a whole slice of the internet that's public but almost impossible to search. Content on IPFS is addressed by what it is (a content hash, the CID) rather than where it is, so there's no domain to crawl, no robots.txt, and no single server to point a search engine at. If you don't already have...