ADB & Device Services (Rust)
Relevant source files
The following files were used as context for generating this wiki page:
The ADB & Device Services module forms the backbone of Keynobi's Android interaction layer. Built in Rust, this system orchestrates communication between the application and Android devices or emulators using the Android Debug Bridge (ADB). It provides high-level abstractions for device discovery, application management (install, launch, stop), and emulator control, ensuring a responsive development experience through asynchronous polling and structured data models.
This module is integrated into the Tauri backend, exposing commands to the SolidJS frontend and providing tools for the Model Context Protocol (MCP) server, allowing AI agents to perform device-level operations directly.
Sources: README.md, src-tauri/src/services/mcp_server.rs:1-15, src-tauri/src/services/adb_manager.rs:1-10
Architecture and Core Services
The system is organized into several key services that handle specific domains of Android device interaction.
ADB Manager
The adb_manager.rs service is responsible for low-level process execution of ADB and emulator binaries. It manages device state through a thread-safe DeviceState struct, which uses an Arc<Mutex<DeviceStateInner>> to allow concurrent access across the application.
The diagram above illustrates the functional decomposition of the ADB Manager service.
Sources: src-tauri/src/services/adb_manager.rs:10-50, src-tauri/src/services/adb_manager.rs:885-920
App Inspector
The app_inspector.rs service provides deep visibility into running Android applications. It can resolve launcher activities, track process IDs (PIDs), and measure memory usage (RSS) and thread counts for specific packages.
| Function | Purpose | Return Type |
|---|---|---|
get_runtime_state | Gathers PIDs, threads, and RSS for a package | AppRuntimeState |
restart_app | Cold or warm restart of an application | Result<RestartResult, String> |
resolve_launcher_activity | Uses cmd package resolve-activity to find entry point | Result<String, String> |
wait_for_displayed | Polls logcat to detect when an app is fully rendered | Option<u64> (ms) |
Sources: src-tauri/src/services/app_inspector.rs:24-85, src-tauri/src/services/app_inspector.rs:136-155
Device Lifecycle and Interaction Flow
The interaction with devices follows a structured flow from discovery to application execution.
Device Discovery and Enrichment
Keynobi polls for devices using adb devices -l. Once a device is found, the system performs "enrichment" by querying system properties like ro.build.version.sdk and ro.build.version.release to determine the API level and Android version.
This sequence shows how Keynobi transforms raw ADB output into enriched device models.
Sources: src-tauri/src/services/adb_manager.rs:114-165, src-tauri/src/services/adb_manager.rs:189-215
Application Launch Logic
Launching an application is complex due to build variants and flavor suffixes. Keynobi employs a multi-step strategy:
- Explicit Activity: If an activity is provided, it uses
am start -n. - Authority Resolution: Queries the device using
cmd package resolve-activityfor theLAUNCHERcategory. - Effective Package Discovery: If the package name is not found (e.g., a
.debugsuffix is missing), it lists all packages on the device to find a match. - Monkey Fallback: Uses the
monkeytool as a last resort to fire a launch event.
Sources: src-tauri/src/services/adb_manager.rs:275-345
Emulator and AVD Management
Keynobi interacts with the Android Virtual Device (AVD) system to manage local emulators.
- Discovery: Scans
~/.android/avd/for.inifiles to identify configured AVDs. - Parsing: Reads
config.iniwithin AVD directories to extract display names, ABI types, and target API levels. - Control: Launches emulators with
-no-boot-animand-gpu autoflags, then pollsadb devicesuntil the serial (e.g.,emulator-5554) appears online.
MCP Integration
The AndroidMcpServer exposes these device services as tools for AI clients.
| MCP Tool | Corresponding Rust Service | Description |
|---|---|---|
list_devices | adb_manager::list_devices | Lists connected hardware/emulators |
install_apk | adb_manager::install_apk | Deploys a build artifact to a device |
launch_app | adb_manager::launch_app | Starts an activity on a device |
get_app_runtime_state | app_inspector::get_runtime_state | Returns PIDs and memory usage |
screenshot | device_inspector::take_screenshot | Captures a PNG from the screen |
Sources: src-tauri/src/services/mcp_server.rs:610-650, src-tauri/src/services/mcp_server.rs:690-720
Technical Implementation Details
Path Resolution
The system resolves tool paths dynamically, prioritizing user-defined SDK paths in AppSettings before falling back to system environment variables.
pub fn get_adb_path(settings: &AppSettings) -> PathBuf {
if let Some(sdk) = settings.android.sdk_path.as_deref() {
let candidate = expand_tilde(sdk).join("platform-tools").join("adb");
if candidate.is_file() {
return candidate;
}
}
PathBuf::from("adb")
}
Sources: src-tauri/src/services/adb_manager.rs:13-23, src-tauri/src/models/settings.rs:65-70
APK Package Extraction
To ensure accurate launches, the system uses aapt2 (found in Android SDK build-tools) to dump the packagename from compiled APK files. This prevents mismatch errors when the frontend attempts to launch a package that has a variant-specific suffix not present in the base source code.
Sources: src-tauri/src/services/adb_manager.rs:55-85, src-tauri/src/commands/build.rs:250-275
Summary
The ADB & Device Services module provides a robust, asynchronous interface to the Android toolchain. By combining low-level binary execution with intelligent enrichment and inspection, it enables high-level features like one-click "Run" and automated AI debugging via MCP. The separation of concerns between adb_manager (execution), app_inspector (analysis), and mcp_server (exposure) ensures that device interactions are reliable and performant across the entire Keynobi ecosystem.