add android-test + android-reproduce for emulator testing and ticket reproduction#8672
Conversation
Usage: scripts/android/android-test <apk> [ENV_KEY=VALUE ...] Example: scripts/android/android-test lantern.apk RADIANCE_COUNTRY=BG RADIANCE_FEATURE_OVERRIDES=dns_ruleset_host_bypass Starts an emulator, installs the APK, pushes a .env file with overrides to the app's data dir (via adb root on Google APIs images, run-as on debug APKs, or su on rooted devices), restarts the app, and streams filtered logcat. Prefers the "lantern-test" AVD if it exists (create with Google APIs image for root access): sdkmanager "system-images;android-35;google_apis;arm64-v8a" avdmanager create avd -n lantern-test -k "system-images;android-35;google_apis;arm64-v8a" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new scripts/android/android-test harness to streamline installing a Lantern APK onto an Android emulator, optionally pushing environment overrides via a .env, restarting the app, and tailing filtered logcat output.
Changes:
- Introduces
scripts/android/android-testto start/select an emulator, install an APK, and stream relevant logs. - Adds
.envoverride generation and multiple strategies for pushing it into the app’s data directory (adb root / run-as / su). - Automates app restart after installation/override push to apply changes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use -s <serial> throughout so multiple devices don't break adb - Fix su -c quoting so $(stat ...) expands on-device - Add trap to clean up temp .env on EXIT/INT/TERM - Fix header comment (no /sdcard/ fallback) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Go env package reads .env from the data directory (via env.LoadFromDir called from common.Init), not from the app's root data dir. Push to /data/data/$PKG/.lantern/.env so radiance finds it. Companion: getlantern/radiance#421 (env.LoadFromDir) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
If no AVDs are found, the script now automatically: 1. Detects host arch (arm64 vs x86_64) 2. Installs the Google APIs system image via sdkmanager 3. Creates a "lantern-test" AVD via avdmanager This means running android-test on a fresh machine with just the Android SDK installed works out of the box — no manual AVD setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use bash array for ADB_CMD so paths with spaces work correctly - Add configurable timeouts for emulator appear (120s) and boot (300s) - Remove unused EMULATOR_PID — emulator intentionally left running between invocations so subsequent runs don't pay boot cost Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Usage: android-reproduce /tmp/ticket-172722 # auto-downloads APK android-reproduce /tmp/ticket-172722 lantern.apk # uses provided APK After running /analyze-ticket, this script: 1. Extracts country + version from the ticket's config/logs 2. Downloads the matching APK from GitHub releases (gh CLI) 3. Pushes the user's exact config.json, servers.json, split-tunnel.json to the emulator so it gets the same proxies, DNS rules, rule sets 4. Sets RADIANCE_COUNTRY to match the user's region 5. Installs, restarts, and streams filtered logcat This gives near-exact reproduction of Android-specific issues by replicating the user's proxy assignments, country routing, and sing-box config on a local emulator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extracts sdkInt, osVersion, and model from flutter.log's "Device info" line. Creates an AVD with the matching API level (e.g. "lantern-api36" for a user on Android 16/SDK 36). Falls back to API 35 if the target image isn't available. Example for ticket #172722 (Android 16, SM-A556B): Creates lantern-api35 (API 36 clamped to 35), installs matching APK, pushes user's exact config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of hardcoding a fallback to API 35, step down from the user's sdkInt until we find an installable Google APIs image. Each API level gets its own AVD (lantern-api29, lantern-api34, etc.) that persists across runs, building up a catalog over time. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…le search - Install APK + launch once before pushing configs (so data dir exists) - Replace eval with mapfile for device info extraction (no shell injection) - Fix f-string syntax error in locations display - Search both ticket-dir and config-dir for servers.json/split-tunnel.json - Remove unused SCRIPT_DIR - Update android-test header to document auto-AVD-creation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Two scripts for Android emulator testing:
scripts/android/android-test— Quick emulator test harness.envwith overrides to the app's.lanterndata dir (viaadb root/run-as/su)scripts/android/android-reproduce— Reproduce Freshdesk tickets on emulator# After /analyze-ticket downloads config to /tmp/ticket-<id>/ android-reproduce /tmp/ticket-172722flutter.loggh release download)lantern-api34for Android 14) — builds up a catalog over time, reused across ticketsconfig.json,servers.json,split-tunnel.jsonto the emulatorRADIANCE_COUNTRYto match the user's regionIntegrated with
/analyze-ticket— when diagnosing an Android ticket, it now offers "Reproduce on Android emulator" as a next action.Companion PRs
env.LoadFromDir(dataDir)so the Go code reads.envfrom the data directory on AndroidFeatures
-s <serial>for all adb invocations (safe with multiple devices)APPEAR_TIMEOUT,BOOT_TIMEOUT)🤖 Generated with Claude Code