Skip to content

Repository files navigation

Droiddriver

A remote Android device you drive from a browser or over the network: a headless emulator, a shell workbench, and a web UI that streams the screen and gives you a terminal (screenshots).

Built for poking at an APK during development, running e2e tests against a reproducible device, or providing a sanboxed agent access to an Android emulator. The device runs on demand — it wakes when the UI or API wants it and stops itself after 30 idle minutes.

Security Warning This project has not been evaluated for security issues. Authentication and trust boundaries are best effort. The authorization model is essentially default admin and intended for single user use on a private network. Prompted with "No bugs, no mistakes".

Quickstart

Requirements: x86_64 Linux with KVM (/dev/kvm readable by your user), Docker or Podman with Compose, and just. Cargo runs containerized — no Rust toolchain needed on the host.

just setup          # generate keys, seed .env
$EDITOR .env        # set DROID_PASSWORD
just compose-up     # all three services (just compose-down to stop)

Web UI: http://localhost:8080. From a script or CI, use emucli:

export EMU_SERVER=http://localhost:8080 EMU_BASIC=admin:hunter2

emucli wait --start                # wake the device, block until booted
emucli install app.apk --launch com.example.app
emucli tap --text "Sign in"        # finds the node, taps its centre
emucli screenshot -o shot.png
emucli logcat --dump --lines 200 --tag MyTag --priority W
emucli pull /sdcard/shot.png

Architecture

component what it is port (default)
emulator/ the device: headless Android under QEMU/KVM 5555 adb, 8554 gRPC
workbench/ dev shell: sshd + adb + SDK tools 2222 ssh
emuserverd the server: Axum HTTP/WS, web UI (wasm) embedded 8080 http
emuctld lifecycle daemon in the emulator container: supervises the emulator, forwards adb/gRPC, binds guest-facing tunnel listeners 8560 http
emucli the CLI client — drives everything over HTTP
emutunnel the reverse-tunnel client as a standalone binary

The four binaries are one Rust workspace, droiddriver-rs/.

  • The server is standalone. It speaks gRPC (screen, input) and the adb protocol (installs, tests, files, device state) natively — no adb binary, no SSH. Every device route works with the workbench absent; the workbench is the human escape hatch behind /term and the only consumer of SSH credentials.
  • Auth is the server's job; reachability is everything else's. adb and gRPC are effectively unauthenticated (google_apis images ship ro.adb.secure=0), so the bind address is the access control. Image defaults bind everything except the web service to 127.0.0.1 — the Kubernetes-pod layout. Compose overrides the binds onto its bridge network but still publishes adb to the host on 127.0.0.1 only. The lifecycle API is gated by a shared DROID_EMUCTL_KEY.
  • The device is disposable. The pristine AVD ships in the image; the data volume is reseeded whenever it is empty or wiped (ANDROID_WIPE_DATA=1 for factory-fresh runs). The emulator container is the root appliance holding /dev/kvm; the workbench and its home volume survive its restarts.

Deploy

Prebuilt images: ghcr.io/<owner>/droid-driver-{emulator,workbench,serve}. Build locally with just build-container-all; test with just test-cargo-all; just with no arguments lists every recipe.

doc covers
CONFIGURATION.md auth modes, secrets, every env var and build arg, SELinux/rootless podman
KUBERNETES.md the one-pod layout: device plugin for KVM, exec probes, binds, NetworkPolicy
REVERSE_PROXY.md TLS, nginx auth_request + body size, WebSocket and SSE routes
CLI.md emucli in full: getting it, every command, CI patterns
APIS.md the HTTP API: install, tests, input, files, logcat, tunnel, keys, status codes

Screenshots

The Screen tab: a live Android home screen you click and type into

The Terminal tab: an adb-equipped shell against the same device

The Logcat tab: a live device-side-filtered logcat stream

Licence

MIT (see LICENSE) — except the vendored droiddriver-rs/proto/emulator_controller.proto slice, which is from google/android-emulator-container-scripts and stays Apache-2.0.

About

A containerized Android Emulator with WebUI, API, and CLI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages