Android Emulator Setup

June 17, 2026 ยท View on GitHub

This page documents the reference emulator shape used for PhoneHarness runs. The goal is to make emulator setup reproducible without publishing local AVD images, app data, credentials, or third-party APK files.

Reference AVD

Use one Android Studio emulator per PhoneHarness slot.

SettingReference value
AVD nameAndroidWorldAvd
Device profilepixel_6
System imagesystem-images;android-33;google_apis_playstore;arm64-v8a
Android API33
RAM2048 MB
Data partition32G recommended
Screen assumption1080x2400
Display densityPixel 6 default; GUI helpers assume 1080-wide coordinates
Start flags-no-snapshot -no-audio -no-boot-anim

Disk guidance:

  • 16G is the practical minimum for light UI smoke tests.
  • 24G is safer once Termux packages, Python wheels, app APKs, traces, and caches accumulate.
  • 32G is the recommended default for repeatable PhoneHarness development.

Create or update the reference AVD:

scripts/create_avd.sh --install-sdk --start

The script creates AndroidWorldAvd, sets the data partition to 32G, and starts it on port 5554 by default. Use another serial for parallel slots:

scripts/create_avd.sh --name AndroidWorldAvd_2 --serial emulator-5556 --start

Runtime Layout

The default single-emulator layout is:

ComponentLocationDefault
gui_proxyhost127.0.0.1:8919
PhoneHarness serveremulator Termuxdevice port 8920
Host to deviceadb forwardhost:8920 -> device:8920
Device to host GUIadb reversedevice:8919 -> host:8919

For multiple emulators, keep device-side ports stable and offset host ports by slot:

SlotSerialHost GUI proxyHost PhoneHarness forward
0emulator-555489198920
1emulator-555689298930
2emulator-555889398940
3emulator-556089498950
4emulator-556289598960
5emulator-556489698970

Always match --serial to adb devices; the gui_proxy.py default is only a fallback.

Required Device Apps

The emulator should have:

  • Termux (com.termux)
  • Termux:API (com.termux.api)
  • ADBKeyboard or another input method that can accept adb text broadcasts
  • Any task-specific real apps needed by a benchmark subset

PhoneHarness does not commit third-party APKs to git. Use config/apk-manifest.example.tsv as a template and install from local APK files or public release URLs:

scripts/install_apps.sh --serial emulator-5554 --manifest config/apk-manifest.example.tsv

Wire adb ports, disable animations, optionally install apps, and start the host GUI proxy:

scripts/setup_emulator.sh --serial emulator-5554 --manifest config/apk-manifest.example.tsv

Self-owned helper APKs may be built from source or distributed as GitHub Release assets. Third-party APKs should be downloaded from their official source or provided locally by the user running the benchmark.

Device State Capture

Capture the current emulator shape before sharing results:

scripts/collect_emulator_info.sh --serial emulator-5554 --out artifacts/emulator-info.md

The report includes Android build properties, screen size, density, disk usage, installed package names, current input method, and animation settings. Commit the report only when it is intentionally part of a reproducibility artifact and does not reveal private apps or account state.

Host Requirements

Install Android Studio or the Android command-line tools so these binaries are available:

  • sdkmanager
  • avdmanager
  • emulator
  • adb

Default macOS SDK path:

export ANDROID_HOME="$HOME/Library/Android/sdk"

The virtual-display helper source builds against Android platform android-33 by default and creates a 1080x1920 virtual display at 320 dpi.

Virtual Display Activity Handoff

Android may move a follow-up activity back to display 0 if the target app starts it without display-aware launch options. PhoneHarness mitigates this only for explicit launches that go through scripts/vdisplay.sh launch, which calls am start --display <id> after force_resizable_activities is enabled. If an app internally opens another activity a few seconds later, that second launch is controlled by the app/Android task stack rather than by PhoneHarness.

For debugging this case, run scripts/vdisplay.sh status and inspect adb shell dumpsys activity activities to see which display owns the resumed activity. When possible, relaunch the final component with scripts/vdisplay.sh launch <package/activity> or keep the workflow on display 0 for apps that do not preserve virtual-display affinity across internal activity transitions.