diff --git a/.github/workflows/python-build.yml b/.github/workflows/python-build.yml index 1cca6ce..673556c 100644 --- a/.github/workflows/python-build.yml +++ b/.github/workflows/python-build.yml @@ -1,8 +1,10 @@ name: Python - Build packages & Release on: - push: {} - pull_request: {} + push: + branches: + - main + pull_request: release: types: [created] diff --git a/.github/workflows/rust-build.yml b/.github/workflows/rust-build.yml index 1dcb6d6..1d84561 100644 --- a/.github/workflows/rust-build.yml +++ b/.github/workflows/rust-build.yml @@ -1,6 +1,10 @@ name: Rust - Build -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/rust-quality.yml b/.github/workflows/rust-quality.yml index adaddb5..bfc5450 100644 --- a/.github/workflows/rust-quality.yml +++ b/.github/workflows/rust-quality.yml @@ -1,6 +1,10 @@ name: Rust - Quality -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: env: CARGO_TERM_COLOR: always diff --git a/adb_cli/Cargo.toml b/adb_cli/Cargo.toml index 69f4a33..c2d5748 100644 --- a/adb_cli/Cargo.toml +++ b/adb_cli/Cargo.toml @@ -14,7 +14,7 @@ adb_client = { version = "^2.0.0" } anyhow = { version = "1.0.94" } clap = { version = "4.5.23", features = ["derive"] } env_logger = { version = "0.11.5" } -log = { version = "0.4.22" } +log = { version = "0.4.26" } [target.'cfg(unix)'.dependencies] termios = { version = "0.3.3" } diff --git a/adb_cli/src/main.rs b/adb_cli/src/main.rs index 92c4e11..1eb2434 100644 --- a/adb_cli/src/main.rs +++ b/adb_cli/src/main.rs @@ -7,12 +7,15 @@ mod handlers; mod models; mod utils; -use adb_client::{ADBDeviceExt, ADBServer, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService}; +use adb_client::{ + ADBDeviceExt, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService, +}; use adb_termios::ADBTermios; use anyhow::Result; use clap::Parser; use handlers::{handle_emulator_commands, handle_host_commands, handle_local_commands}; use models::{DeviceCommands, LocalCommand, MainCommand, Opts}; +use std::collections::HashMap; use std::fs::File; use std::io::Write; use std::path::Path; @@ -30,11 +33,15 @@ fn main() -> Result<()> { MainCommand::Host(server_command) => return Ok(handle_host_commands(server_command)?), MainCommand::Emu(emulator_command) => return handle_emulator_commands(emulator_command), MainCommand::Local(server_command) => { - let mut adb_server = ADBServer::new(server_command.address); + // Must start server to communicate with device, but only if this is a local one. + let server_address_ip = server_command.address.ip(); + if server_address_ip.is_loopback() || server_address_ip.is_unspecified() { + ADBServer::start(&HashMap::default()); + } let device = match server_command.serial { - Some(serial) => adb_server.get_device_by_name(&serial)?, - None => adb_server.get_device()?, + Some(serial) => ADBServerDevice::new(serial, Some(server_command.address)), + None => ADBServerDevice::autodetect(Some(server_command.address)), }; match server_command.command { diff --git a/adb_client/Cargo.toml b/adb_client/Cargo.toml index d2460e2..d42edf5 100644 --- a/adb_client/Cargo.toml +++ b/adb_client/Cargo.toml @@ -13,11 +13,11 @@ version.workspace = true base64 = { version = "0.22.1" } bincode = { version = "1.3.3" } byteorder = { version = "1.5.0" } -chrono = { version = "0.4.39" } +chrono = { version = "0.4.40" } homedir = { version = "0.3.4" } image = { version = "0.25.5" } lazy_static = { version = "1.5.0" } -log = { version = "0.4.22" } +log = { version = "0.4.26" } mdns-sd = { version = "0.13.2" } num-bigint = { version = "0.8.4", package = "num-bigint-dig" } num-traits = { version = "0.2.19" } diff --git a/adb_client/src/emulator_device/adb_emulator_device.rs b/adb_client/src/emulator_device/adb_emulator_device.rs index 159f7a2..f5d2881 100644 --- a/adb_client/src/emulator_device/adb_emulator_device.rs +++ b/adb_client/src/emulator_device/adb_emulator_device.rs @@ -65,10 +65,15 @@ impl TryFrom for ADBEmulatorDevice { type Error = RustADBError; fn try_from(value: ADBServerDevice) -> std::result::Result { - ADBEmulatorDevice::new( - value.identifier.clone(), - Some(*value.transport.get_socketaddr().ip()), - ) + match &value.identifier { + Some(device_identifier) => ADBEmulatorDevice::new( + device_identifier.clone(), + Some(*value.transport.get_socketaddr().ip()), + ), + None => Err(RustADBError::DeviceNotFound( + "cannot connect to an emulator device without knowing its identifier".to_string(), + )), + } } } diff --git a/adb_client/src/server/adb_server.rs b/adb_client/src/server/adb_server.rs index 353dc11..927f688 100644 --- a/adb_client/src/server/adb_server.rs +++ b/adb_client/src/server/adb_server.rs @@ -27,6 +27,26 @@ impl ADBServer { } } + /// Start an instance of `adb-server` + pub fn start(envs: &HashMap) { + // ADB Server is local, we start it if not already running + let mut command = Command::new("adb"); + command.arg("start-server"); + for (env_k, env_v) in envs.iter() { + command.env(env_k, env_v); + } + + let child = command.spawn(); + match child { + Ok(mut child) => { + if let Err(e) = child.wait() { + log::error!("error while starting adb server: {e}") + } + } + Err(e) => log::error!("error while starting adb server: {e}"), + } + } + /// Returns the current selected transport pub(crate) fn get_transport(&mut self) -> Result<&mut TCPServerTransport> { self.transport @@ -52,22 +72,7 @@ impl ADBServer { }; if is_local_ip { - // ADB Server is local, we start it if not already running - let mut command = Command::new("adb"); - command.arg("start-server"); - for (env_k, env_v) in self.envs.iter() { - command.env(env_k, env_v); - } - - let child = command.spawn(); - match child { - Ok(mut child) => { - if let Err(e) = child.wait() { - log::error!("error while starting adb server: {e}") - } - } - Err(e) => log::error!("error while starting adb server: {e}"), - } + Self::start(&self.envs); } transport.connect()?; diff --git a/adb_client/src/server_device/adb_server_device.rs b/adb_client/src/server_device/adb_server_device.rs index afd2a17..b96d6eb 100644 --- a/adb_client/src/server_device/adb_server_device.rs +++ b/adb_client/src/server_device/adb_server_device.rs @@ -1,26 +1,32 @@ -use crate::{ADBTransport, Result, TCPServerTransport}; +use crate::{models::AdbServerCommand, ADBTransport, Result, TCPServerTransport}; use std::net::SocketAddrV4; /// Represents a device connected to the ADB server. #[derive(Debug)] pub struct ADBServerDevice { /// Unique device identifier. - pub identifier: String, + pub identifier: Option, /// Internal [TCPServerTransport] pub(crate) transport: TCPServerTransport, } impl ADBServerDevice { - /// Instantiates a new [ADBServerDevice] - pub fn new(identifier: String, socket_addr: Option) -> Self { - let transport = if let Some(addr) = socket_addr { - TCPServerTransport::new(addr) - } else { - TCPServerTransport::default() - }; + /// Instantiates a new [ADBServerDevice], knowing its ADB identifier (as returned by `adb devices` command). + pub fn new(identifier: String, server_addr: Option) -> Self { + let transport = TCPServerTransport::new_or_default(server_addr); Self { - identifier, + identifier: Some(identifier), + transport, + } + } + + /// Instantiates a new [ADBServerDevice], assuming only one is currently connected. + pub fn autodetect(server_addr: Option) -> Self { + let transport = TCPServerTransport::new_or_default(server_addr); + + Self { + identifier: None, transport, } } @@ -31,6 +37,19 @@ impl ADBServerDevice { Ok(&mut self.transport) } + + /// Set device connection to use serial transport + pub(crate) fn set_serial_transport(&mut self) -> Result<()> { + let identifier = self.identifier.clone(); + let transport = self.connect()?; + if let Some(serial) = identifier { + transport.send_adb_request(AdbServerCommand::TransportSerial(serial))?; + } else { + transport.send_adb_request(AdbServerCommand::TransportAny)?; + } + + Ok(()) + } } impl Drop for ADBServerDevice { diff --git a/adb_client/src/server_device/adb_server_device_commands.rs b/adb_client/src/server_device/adb_server_device_commands.rs index d87ab51..3d654bf 100644 --- a/adb_client/src/server_device/adb_server_device_commands.rs +++ b/adb_client/src/server_device/adb_server_device_commands.rs @@ -20,9 +20,8 @@ impl ADBDeviceExt for ADBServerDevice { return Err(RustADBError::ADBShellNotSupported); } - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; + self.transport .send_adb_request(AdbServerCommand::ShellCommand(command.join(" ")))?; @@ -59,9 +58,7 @@ impl ADBDeviceExt for ADBServerDevice { return Err(RustADBError::ADBShellNotSupported); } - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport.send_adb_request(AdbServerCommand::Shell)?; let mut read_stream = self.transport.get_raw_connection()?.try_clone()?; diff --git a/adb_client/src/server_device/commands/forward.rs b/adb_client/src/server_device/commands/forward.rs index 263cc44..98ee8d1 100644 --- a/adb_client/src/server_device/commands/forward.rs +++ b/adb_client/src/server_device/commands/forward.rs @@ -3,9 +3,7 @@ use crate::{models::AdbServerCommand, ADBServerDevice, Result}; impl ADBServerDevice { /// Forward socket connection pub fn forward(&mut self, remote: String, local: String) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial.clone()))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::Forward(remote, local), false) @@ -14,9 +12,7 @@ impl ADBServerDevice { /// Remove all previously applied forward rules pub fn forward_remove_all(&mut self) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial.clone()))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::ForwardRemoveAll, false) diff --git a/adb_client/src/server_device/commands/framebuffer.rs b/adb_client/src/server_device/commands/framebuffer.rs index ef942d4..3d7b926 100644 --- a/adb_client/src/server_device/commands/framebuffer.rs +++ b/adb_client/src/server_device/commands/framebuffer.rs @@ -11,9 +11,7 @@ use crate::{ impl ADBServerDevice { /// Inner method requesting framebuffer from Android device pub(crate) fn framebuffer_inner(&mut self) -> Result, Vec>> { - let serial: String = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .send_adb_request(AdbServerCommand::FrameBuffer)?; diff --git a/adb_client/src/server_device/commands/host_features.rs b/adb_client/src/server_device/commands/host_features.rs index 5f5ae4b..0bdaaea 100644 --- a/adb_client/src/server_device/commands/host_features.rs +++ b/adb_client/src/server_device/commands/host_features.rs @@ -6,9 +6,7 @@ use crate::{ impl ADBServerDevice { /// Lists available ADB server features. pub fn host_features(&mut self) -> Result> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; let features = self .transport diff --git a/adb_client/src/server_device/commands/install.rs b/adb_client/src/server_device/commands/install.rs index dace45a..0a26e6c 100644 --- a/adb_client/src/server_device/commands/install.rs +++ b/adb_client/src/server_device/commands/install.rs @@ -13,9 +13,7 @@ impl ADBServerDevice { let file_size = apk_file.metadata()?.len(); - let serial: String = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .send_adb_request(AdbServerCommand::Install(file_size))?; diff --git a/adb_client/src/server_device/commands/list.rs b/adb_client/src/server_device/commands/list.rs index f6053e9..856806a 100644 --- a/adb_client/src/server_device/commands/list.rs +++ b/adb_client/src/server_device/commands/list.rs @@ -11,9 +11,7 @@ use std::{ impl ADBServerDevice { /// Lists files in path on the device. pub fn list>(&mut self, path: A) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; // Set device in SYNC mode self.transport.send_adb_request(AdbServerCommand::Sync)?; diff --git a/adb_client/src/server_device/commands/reboot.rs b/adb_client/src/server_device/commands/reboot.rs index 0bf274d..cb79d71 100644 --- a/adb_client/src/server_device/commands/reboot.rs +++ b/adb_client/src/server_device/commands/reboot.rs @@ -6,9 +6,7 @@ use crate::{ impl ADBServerDevice { /// Reboots the device pub fn reboot(&mut self, reboot_type: RebootType) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::Reboot(reboot_type), false) diff --git a/adb_client/src/server_device/commands/reconnect.rs b/adb_client/src/server_device/commands/reconnect.rs index 8f2a3d5..5047a42 100644 --- a/adb_client/src/server_device/commands/reconnect.rs +++ b/adb_client/src/server_device/commands/reconnect.rs @@ -3,9 +3,7 @@ use crate::{models::AdbServerCommand, ADBServerDevice, Result}; impl ADBServerDevice { /// Reconnect device pub fn reconnect(&mut self) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::Reconnect, false) diff --git a/adb_client/src/server_device/commands/recv.rs b/adb_client/src/server_device/commands/recv.rs index 1f6899c..35862f2 100644 --- a/adb_client/src/server_device/commands/recv.rs +++ b/adb_client/src/server_device/commands/recv.rs @@ -71,9 +71,7 @@ impl Read for ADBRecvCommandReader { impl ADBServerDevice { /// Receives path to stream from the device. pub fn pull(&mut self, path: &dyn AsRef, stream: &mut dyn Write) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; // Set device in SYNC mode self.transport.send_adb_request(AdbServerCommand::Sync)?; diff --git a/adb_client/src/server_device/commands/reverse.rs b/adb_client/src/server_device/commands/reverse.rs index 326d2f5..282b552 100644 --- a/adb_client/src/server_device/commands/reverse.rs +++ b/adb_client/src/server_device/commands/reverse.rs @@ -3,9 +3,7 @@ use crate::{models::AdbServerCommand, ADBServerDevice, Result}; impl ADBServerDevice { /// Reverse socket connection pub fn reverse(&mut self, remote: String, local: String) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::Reverse(remote, local), false) @@ -14,9 +12,7 @@ impl ADBServerDevice { /// Remove all reverse rules pub fn reverse_remove_all(&mut self) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial.clone()))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::ReverseRemoveAll, false) diff --git a/adb_client/src/server_device/commands/send.rs b/adb_client/src/server_device/commands/send.rs index d22093d..2cb020e 100644 --- a/adb_client/src/server_device/commands/send.rs +++ b/adb_client/src/server_device/commands/send.rs @@ -45,9 +45,7 @@ impl ADBServerDevice { /// Send stream to path on the device. pub fn push>(&mut self, stream: R, path: A) -> Result<()> { log::info!("Sending data to {}", path.as_ref()); - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; // Set device in SYNC mode self.transport.send_adb_request(AdbServerCommand::Sync)?; diff --git a/adb_client/src/server_device/commands/stat.rs b/adb_client/src/server_device/commands/stat.rs index c504409..3edd7dc 100644 --- a/adb_client/src/server_device/commands/stat.rs +++ b/adb_client/src/server_device/commands/stat.rs @@ -39,9 +39,7 @@ impl ADBServerDevice { /// Stat file given as path on the device. pub fn stat>(&mut self, path: A) -> Result { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; // Set device in SYNC mode self.transport.send_adb_request(AdbServerCommand::Sync)?; diff --git a/adb_client/src/server_device/commands/tcpip.rs b/adb_client/src/server_device/commands/tcpip.rs index 0d3da56..af8f7f4 100644 --- a/adb_client/src/server_device/commands/tcpip.rs +++ b/adb_client/src/server_device/commands/tcpip.rs @@ -3,9 +3,7 @@ use crate::{models::AdbServerCommand, ADBServerDevice, Result}; impl ADBServerDevice { /// Set adb daemon to tcp/ip mode pub fn tcpip(&mut self, port: u16) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::TcpIp(port), false) diff --git a/adb_client/src/server_device/commands/uninstall.rs b/adb_client/src/server_device/commands/uninstall.rs index 9e32ba4..25ef3a5 100644 --- a/adb_client/src/server_device/commands/uninstall.rs +++ b/adb_client/src/server_device/commands/uninstall.rs @@ -5,9 +5,7 @@ use crate::{models::AdbServerCommand, server_device::ADBServerDevice, Result}; impl ADBServerDevice { /// Uninstall a package from device pub fn uninstall(&mut self, package_name: &str) -> Result<()> { - let serial: String = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; + self.set_serial_transport()?; self.transport .send_adb_request(AdbServerCommand::Uninstall(package_name.to_string()))?; diff --git a/adb_client/src/server_device/commands/usb.rs b/adb_client/src/server_device/commands/usb.rs index 7f55d0a..eb89460 100644 --- a/adb_client/src/server_device/commands/usb.rs +++ b/adb_client/src/server_device/commands/usb.rs @@ -3,10 +3,7 @@ use crate::{models::AdbServerCommand, ADBServerDevice, Result}; impl ADBServerDevice { /// Set adb daemon to usb mode pub fn usb(&mut self) -> Result<()> { - let serial = self.identifier.clone(); - self.connect()? - .send_adb_request(AdbServerCommand::TransportSerial(serial))?; - + self.set_serial_transport()?; self.transport .proxy_connection(AdbServerCommand::Usb, false) .map(|_| ()) diff --git a/adb_client/src/transports/tcp_server_transport.rs b/adb_client/src/transports/tcp_server_transport.rs index 9200bfd..ddd8574 100644 --- a/adb_client/src/transports/tcp_server_transport.rs +++ b/adb_client/src/transports/tcp_server_transport.rs @@ -33,6 +33,14 @@ impl TCPServerTransport { } } + /// Instantiate a new instance of [TCPServerTransport] using given address, or default if not specified. + pub fn new_or_default(socket_addr: Option) -> Self { + match socket_addr { + Some(s) => Self::new(s), + None => Self::default(), + } + } + /// Get underlying [SocketAddrV4] pub fn get_socketaddr(&self) -> SocketAddrV4 { self.socket_addr diff --git a/pyadb_client/src/adb_server_device.rs b/pyadb_client/src/adb_server_device.rs index 0bf3c6a..e6fd207 100644 --- a/pyadb_client/src/adb_server_device.rs +++ b/pyadb_client/src/adb_server_device.rs @@ -14,7 +14,7 @@ pub struct PyADBServerDevice(pub ADBServerDevice); impl PyADBServerDevice { #[getter] /// Device identifier - pub fn identifier(&self) -> String { + pub fn identifier(&self) -> Option { self.0.identifier.clone() }