radb/lib.rs
1//! # ADB Utils - Android Debug Bridge Utilities for Rust
2//!
3//! A comprehensive Rust library for interacting with Android devices through ADB (Android Debug Bridge).
4//! This library provides both synchronous and asynchronous interfaces for device management, file operations,
5//! shell command execution, and more.
6//!
7//! ## Features
8//!
9//! - **Dual API Support**: Both blocking and async/await interfaces
10//! - **Device Management**: Connect, disconnect, and manage multiple devices
11//! - **File Operations**: Push, pull, list, and manipulate files on devices
12//! - **Shell Commands**: Execute shell commands with streaming support
13//! - **Screen Operations**: Screenshots, input simulation, and screen control
14//! - **App Management**: Install, uninstall, start, and stop applications
15//! - **Network Operations**: Port forwarding, reverse forwarding, WiFi control, and network information
16//! - **System Information**: Device properties, Android version, hardware info
17//! - **Logging**: Logcat streaming and filtering
18//!
19//! ## Quick Start
20//!
21//! ### Blocking API
22//!
23//! ```rust,no_run
24//! # #[cfg(feature = "blocking")]
25//! # mod blocking_example {
26//! use radb::prelude::*;
27//!
28//! fn main() -> AdbResult<()> {
29//! // Connect to ADB server
30//! let mut client = AdbClient::connect("127.0.0.1:5037")?;
31//!
32//! // Get device list
33//! let devices = client.list_devices()?;
34//! let mut device = devices.into_iter().next().unwrap();
35//!
36//! // Execute shell command
37//! let result = device.shell(["echo", "Hello, ADB!"])?;
38//! println!("Output: {}", result);
39//!
40//! // Take screenshot
41//! let screenshot = device.screenshot()?;
42//! println!("Screenshot: {}x{}", screenshot.width(), screenshot.height());
43//!
44//! Ok(())
45//! }
46//! # }
47//! ```
48//!
49//! ### Async API
50//!
51//! ```rust,no_run
52//! # #[cfg(feature = "tokio_async")]
53//! # mod async_example {
54//! use radb::prelude::*;
55//! use radb::AdbResult;
56//! #[tokio::main]
57//! async fn main() -> AdbResult<()> {
58//! // Connect to ADB server
59//! let mut client = AdbClient::connect("127.0.0.1:5037").await?;
60//!
61//! // Get device list
62//! let devices = client.list_devices().await?;
63//! let mut device = devices.into_iter().next().unwrap();
64//!
65//! // Execute shell command
66//! let result = device.shell(["echo", "Hello, ADB!"]).await?;
67//! println!("Output: {}", result);
68//!
69//! // Stream logcat
70//! let mut logcat = Box::pin(device.logcat(true, None).await?);
71//! while let Some(line) = logcat.as_mut().next().await {
72//! println!("Log: {}", line?);
73//! }
74//!
75//! Ok(())
76//! }
77//! # }
78//! ```
79//!
80//! ## Feature Flags
81//!
82//! - `blocking`: Enable blocking/synchronous API (default)
83//! - `tokio_async`: Enable async/await API with Tokio runtime
84//!
85//! `blocking` and `tokio_async` share command construction, response parsing,
86//! and ADB sync frame handling. The runtime-specific layers only handle
87//! connection setup, IO, and `await` adaptation.
88//!
89//! ## Error Handling
90//!
91//! The library uses a comprehensive error system with specific error types:
92//!
93//! ```rust,no_run
94//! use radb::prelude::*;
95//!
96//! let result: AdbResult<String> = Err(AdbError::command_failed(
97//! "shell invalid_command",
98//! "not found",
99//! ));
100//!
101//! match result {
102//! Ok(output) => println!("Success: {}", output),
103//! Err(AdbError::CommandFailed { command, reason }) => {
104//! eprintln!("Command '{}' failed: {}", command, reason);
105//! }
106//! Err(AdbError::DeviceNotFound { serial }) => {
107//! eprintln!("Device '{}' not found", serial);
108//! }
109//! Err(e) => eprintln!("Other error: {}", e),
110//! }
111//! ```
112
113// Core modules
114pub mod beans;
115pub mod client;
116pub mod errors;
117pub mod protocols;
118pub mod sync_protocol;
119pub mod utils;
120
121// Re-exports for convenience
122pub use client::{AdbClient, AdbDevice};
123pub use errors::{AdbError, AdbResult};
124
125// Prelude module for common imports
126pub mod prelude {
127 //! Common imports for ADB utilities
128 //!
129 //! This module re-exports the most commonly used types and traits.
130 //! Import this module to get started quickly:
131 //!
132 //! ```rust
133 //! use radb::prelude::*;
134 //! ```
135
136 pub use crate::beans::{AdbCommand, AppInfo, FileInfo, ForwardItem, NetworkType};
137 pub use crate::client::{AdbClient, AdbDevice};
138 pub use crate::errors::{AdbError, AdbResult, AdbResultExt};
139 pub use crate::utils::{get_free_port, start_adb_server};
140
141 // Re-export commonly used external types
142 #[cfg(feature = "tokio_async")]
143 pub use futures_util::StreamExt;
144
145 #[cfg(feature = "blocking")]
146 pub use std::net::TcpStream;
147
148 #[cfg(feature = "tokio_async")]
149 pub use tokio::net::TcpStream;
150}
151
152// Convenient type aliases
153pub type Result<T> = std::result::Result<T, AdbError>;
154
155// Version and metadata
156pub const VERSION: &str = env!("CARGO_PKG_VERSION");
157pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
158pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
159
160// Library information
161pub mod info {
162 //! Library metadata and version information
163
164 /// Get library version
165 pub fn version() -> &'static str {
166 crate::VERSION
167 }
168
169 /// Get library description
170 pub fn description() -> &'static str {
171 crate::DESCRIPTION
172 }
173
174 /// Get library authors
175 pub fn authors() -> &'static str {
176 crate::AUTHORS
177 }
178
179 /// Print library information
180 pub fn print_info() {
181 println!("ADB Utils v{}", version());
182 println!("Description: {}", description());
183 println!("Authors: {}", authors());
184 }
185}
186
187// Utilities module with public helpers
188pub mod util {
189 //! Utility functions for ADB operations
190
191 pub use crate::utils::*;
192
193 /// Check if ADB server is running
194 pub fn is_adb_server_running() -> bool {
195 use std::net::TcpStream;
196 TcpStream::connect("127.0.0.1:5037").is_ok()
197 }
198
199 /// Start ADB server if not running
200 pub fn ensure_adb_server() -> crate::AdbResult<()> {
201 if !is_adb_server_running() {
202 start_adb_server();
203 // Wait a bit for server to start
204 std::thread::sleep(std::time::Duration::from_millis(500));
205 }
206 Ok(())
207 }
208
209 /// Get ADB server version (convenience function)
210 #[cfg(feature = "blocking")]
211 pub fn get_adb_server_version() -> crate::AdbResult<String> {
212 let mut client = crate::AdbClient::connect("127.0.0.1:5037")?;
213 client.server_version()
214 }
215
216 /// Get ADB server version (async convenience function)
217 #[cfg(feature = "tokio_async")]
218 pub async fn get_adb_server_version_async() -> crate::AdbResult<String> {
219 let mut client = crate::AdbClient::connect("127.0.0.1:5037").await?;
220 client.server_version().await
221 }
222}
223
224// Feature-specific modules
225#[cfg(feature = "blocking")]
226pub mod blocking {
227 //! Blocking/synchronous API
228 //!
229 //! This module contains the blocking versions of ADB operations.
230 //! Use this when you don't need async/await functionality.
231
232 #[allow(unused_imports)]
233 pub use crate::client::adb_client::blocking_impl::*;
234 #[allow(unused_imports)]
235 pub use crate::client::adb_device::blocking_impl::*;
236 pub use crate::protocols::blocking::AdbProtocol;
237}
238
239#[cfg(feature = "tokio_async")]
240pub mod r#async {
241 //! Asynchronous API
242 //!
243 //! This module contains the async versions of ADB operations.
244 //! Use this when you need async/await functionality with Tokio.
245
246 #[allow(unused_imports)]
247 pub use crate::client::adb_client::async_impl::*;
248 #[allow(unused_imports)]
249 pub use crate::client::adb_device::async_impl::*;
250 pub use crate::protocols::tokio_async::AdbProtocol;
251}
252
253// Builder pattern for common operations
254pub mod builder {
255 //! Builder patterns for complex operations
256
257 use crate::prelude::*;
258
259 /// Builder for ADB client configuration
260 pub struct AdbClientBuilder {
261 addr: Option<String>,
262 timeout: Option<std::time::Duration>,
263 }
264
265 impl AdbClientBuilder {
266 /// Create a new client builder
267 pub fn new() -> Self {
268 Self {
269 addr: None,
270 timeout: None,
271 }
272 }
273
274 /// Set ADB server address
275 pub fn addr<S: Into<String>>(mut self, addr: S) -> Self {
276 self.addr = Some(addr.into());
277 self
278 }
279
280 /// Set connection timeout
281 pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
282 self.timeout = Some(timeout);
283 self
284 }
285
286 /// Build the client (blocking version)
287 #[cfg(feature = "blocking")]
288 pub fn build(self) -> AdbResult<AdbClient> {
289 let addr = self.addr.unwrap_or_else(|| "127.0.0.1:5037".to_string());
290 AdbClient::connect(addr)
291 }
292
293 /// Build the client (async version)
294 #[cfg(feature = "tokio_async")]
295 pub async fn build_async(self) -> AdbResult<AdbClient> {
296 let addr = self.addr.unwrap_or_else(|| "127.0.0.1:5037".to_string());
297 AdbClient::connect(addr).await
298 }
299 }
300
301 impl Default for AdbClientBuilder {
302 fn default() -> Self {
303 Self::new()
304 }
305 }
306}
307
308// Testing utilities (only available in tests)
309#[cfg(test)]
310pub mod test_utils {
311 //! Testing utilities for ADB operations
312
313 use std::fmt::Debug;
314
315 use crate::prelude::*;
316
317 /// Setup test environment
318 pub fn setup_test_env() {
319 crate::utils::start_adb_server();
320 std::thread::sleep(std::time::Duration::from_millis(500));
321 }
322
323 /// Get test device (if available)
324 #[cfg(feature = "blocking")]
325 pub fn get_test_device() -> Option<AdbDevice<impl std::net::ToSocketAddrs + Clone + Debug>> {
326 let mut client = AdbClient::connect("127.0.0.1:5037").ok()?;
327 client.list_devices().ok()?.into_iter().next()
328 }
329
330 /// Get test device (async version)
331 #[cfg(feature = "tokio_async")]
332 pub async fn get_test_device_async(
333 ) -> Option<AdbDevice<impl tokio::net::ToSocketAddrs + Clone + Debug>> {
334 let mut client = AdbClient::connect("127.0.0.1:5037").await.ok()?;
335 client.list_devices().await.ok()?.into_iter().next()
336 }
337}
338
339// Macros for common operations
340#[macro_export]
341macro_rules! adb_shell {
342 ($device:expr, $($arg:expr),+) => {
343 $device.shell([$($arg),+])
344 };
345}
346
347#[macro_export]
348macro_rules! adb_expect_device {
349 ($client:expr) => {
350 $client
351 .list_devices()?
352 .into_iter()
353 .next()
354 .ok_or_else(|| $crate::AdbError::device_not_found("No devices found"))?
355 };
356}
357
358pub use anyhow;
359pub use log;
360
361// Conditional exports based on features
362#[cfg(feature = "tokio_async")]
363pub use tokio;
364
365#[cfg(feature = "blocking")]
366pub use std::net;
367
368// Documentation examples
369#[cfg(doctest)]
370doc_comment::doctest!("../README.md");
371
372// Feature compatibility checks
373#[cfg(all(feature = "blocking", feature = "tokio_async"))]
374compile_error!("Cannot use both 'blocking' and 'tokio_async' features simultaneously");
375
376#[cfg(not(any(feature = "blocking", feature = "tokio_async")))]
377compile_error!("Must enable either 'blocking' or 'tokio_async' feature");
378
379// Platform-specific optimizations
380#[cfg(target_os = "android")]
381compile_error!("This library is not intended to run on Android devices");
382
383// Export the main ADB namespace for convenience
384pub mod adb {
385 //! Main ADB namespace with all core functionality
386
387 pub use crate::beans::*;
388 pub use crate::client::*;
389 pub use crate::errors::*;
390 pub use crate::prelude::*;
391}