A Rust library for controlling Android Emulators via gRPC.
- Discover Emulator AVDs: List available Android Virtual Devices
- Spawn Emulators: Configure and start emulator instances programmatically
- Find Running Emulators: Locate existing emulator instances via ADB protocol
- gRPC Control: Full bindings to the Android Emulator gRPC controller API
- Authentication Support: No auth, Basic Auth, and JWT authentication for gRPC
- Export Limited JWT Tokens: Export JWT tokens that can temporarily grant other tools / clients limited access to the emulator.
#[tokio::main] async fn main() { let avds = android_emulator::list_avds().await.expect("Failed to list AVDs"); println!("Available AVDs: {:?}", avds); }
use android_emulator::{EmulatorConfig, list_avds}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Get the first available AVD let avds = list_avds().await?; let avd_name = avds.first().ok_or("No AVDs found")?; let config = EmulatorConfig::new(avd_name) .with_window(false) .with_snapshot_load(false) .with_snapshot_save(false) .with_boot_animation(false); let instance = config.spawn().await?; // Connect to the emulator let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?; // Wait until the emulator is fully booted let elapsed = client.wait_until_booted(Duration::from_secs(200), None).await?; println!("Emulator ready at: {}", instance.grpc_endpoint()); println!("Booted in {:.1} seconds", elapsed.as_secs_f64()); Ok(()) }
Find an existing emulator instance that's running a particular AVD and connect to it:
use android_emulator::{list_avds, list_emulators}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Get the first available AVD let avds = list_avds().await?; let avd_id = avds.first().ok_or("No AVDs found")?; // Find a running emulator with that AVD let emulators = list_emulators().await?; let instance = emulators .into_iter() .find(|e| e.avd_id().unwrap_or_default() == avd_id) .ok_or("No running emulator found")?; println!("Found emulator: {}", instance.serial()); println!("gRPC endpoint: {}", instance.grpc_endpoint()); // Connect to the emulator let mut client = instance.connect(Some(Duration::from_secs(30)), true).await?; // Use the client... Ok(()) }
use android_emulator::{EmulatorConfig, list_avds}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Get the first available AVD let avds = list_avds().await?; let avd_name = avds.first().ok_or("No AVDs found")?; // Start the emulator let instance = EmulatorConfig::new(avd_name) .with_window(false) .spawn() .await?; let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?; // Get emulator status let status = client.protocol_mut().get_status(()).await?.into_inner(); println!("Emulator status: {:?}", status); // Set GPS coordinates let gps_state = android_emulator::proto::GpsState { latitude: 37.7749, longitude: -122.4194, ..Default::default() }; client.protocol_mut().set_gps(gps_state).await?; Ok(()) }
use android_emulator::{EmulatorConfig, list_avds}; use android_emulator::proto::{Touch, TouchEvent}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Get the first available AVD let avds = list_avds().await?; let avd_name = avds.first().ok_or("No AVDs found")?; // Start the emulator let instance = EmulatorConfig::new(avd_name) .with_window(false) .spawn() .await?; let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?; let touch = Touch { x: 500, y: 1000, identifier: 1, pressure: 100, ..Default::default() }; let touch_event = TouchEvent { touches: vec![touch], display: 0, }; client.protocol_mut().send_touch(touch_event).await?; Ok(()) }
The library depends on finding an Android SDK installation in order to be able to spawn new emulators and will look for the Android SDK as follows:
ANDROID_HOMEenvironment variableANDROID_SDK_ROOTenvironment variable (deprecated)- Platform-specific default locations:
- Linux:
$HOME/Android/sdkor$HOME/Android/Sdk - macOS:
$HOME/Library/Android/sdk - Windows:
%LOCALAPPDATA%/Android/Sdk
- Linux:
Emulator AVDs: At least one Android Virtual Device must be created
The library provides complete bindings to the Android Emulator Controller gRPC API, including:
- Sensor control (accelerometer, GPS, etc.)
- Physical model control (rotation, position, etc.)
- Battery state management
- Screenshot and screen streaming
- Audio streaming
- Touch, mouse, and keyboard input
- Phone calls and SMS
- VM state management
- Display configuration
- And more...
This crate includes pre-generated protobuf bindings, so consumers don't need protoc installed.
If you modify the .proto files, regenerate the bindings by running:
cargo xtask codegen
This will update android-emulator/src/generated/android.emulation.control.rs.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/license/mit)
at your option.