Skip to content

ADR-001: Emulation Backend Selection

Status: Accepted

Context

DroidFarm runs Android virtual devices inside Kubernetes pods. The backend must: (a) run inside a container, (b) support KVM acceleration, (c) be accessible via a web browser, (d) be open-source, and (e) support Android 12+.

Three candidates were evaluated:

  • budtmo/docker-android — packages Android SDK + QEMU emulator + noVNC. noVNC only (no WebRTC); QEMU overhead is heavier than Cuttlefish.
  • google/android-emulator-container-scripts — official Google scripts wrapping the Android SDK emulator with a separate WebRTC frontend container. QEMU-based; requires two containers per device.
  • Google Cuttlefish — Google's reference virtual Android device for AOSP testing. Uses KVM directly (not QEMU); built-in WebRTC relay on port 8443; maintained by Google at scale.

Decision

DroidFarm uses Google Cuttlefish as the emulation backend.

Cuttlefish uses KVM directly rather than QEMU-on-KVM, reducing per-instance memory footprint (~2–3 GB vs ~4–5 GB RAM). Its built-in WebRTC relay on port 8443 eliminates the need for a separate streaming sidecar. Non-privileged Kubernetes deployment is achieved via squat/generic-device-plugin, which exposes /dev/kvm, /dev/vhost-net, /dev/vhost-vsock, and /dev/vsock as Kubernetes resource limits. Required capabilities are NET_ADMIN, NET_RAW, and SYS_ADMIN; --privileged mode is not used.

Node setup

Kernel modules required on every emulator node:

modprobe vhost_vsock vhost_net vsock

This is automated via the node-setup-daemonset.yaml Helm template.

Device plugin resource requests

resources:
  limits:
    squat.ai/kvm: "1"
    squat.ai/vhost: "3"   # one each for vhost-net, vhost-vsock, vsock

Emulator pod security context

securityContext:
  capabilities:
    add:
      - NET_ADMIN
      - NET_RAW
      - SYS_ADMIN

Cuttlefish container image

The Cuttlefish image is built by layering host tools (cvd-host_package.tar.gz) and Android system images onto a base Debian container. DroidFarm provides docker/Dockerfile.cuttlefish and a GitHub Actions matrix workflow that builds and pushes ghcr.io/christopherime/cuttlefish:{android-version} for Android 13, 14, and 15.

Ports

Port Protocol Purpose
8443 HTTPS/WSS Cuttlefish WebRTC relay (browser access)
5554 TCP ADB (Android Debug Bridge)
6444 TCP Cuttlefish operator API
15550–15599 UDP WebRTC media (SRTP, requires TURN for NAT)

TURN server

coturn is deployed as a Helm component for WebRTC across NAT. TURN credentials are stored in a Kubernetes Secret and never appear in values files or process arguments.

Consequences

  • Cuttlefish images must be built and published per Android version (handled by CI).
  • Image size is larger than docker-android due to Android system disk images (~3–8 GB per version).
  • WebRTC streaming works from first deploy — no intermediate noVNC phase.
  • coturn is a required component for non-LAN WebRTC access; TURN bandwidth must be budgeted per concurrent session.