diff --git a/adb_cli/src/commands/emu.rs b/adb_cli/src/commands/emu.rs deleted file mode 100644 index 4f8b89b..0000000 --- a/adb_cli/src/commands/emu.rs +++ /dev/null @@ -1,12 +0,0 @@ -use clap::Parser; - -#[derive(Parser, Debug)] -pub enum EmuCommand { - /// Send a SMS with given phone number and given content - Sms { - phone_number: String, - content: String, - }, - /// Rotate device screen from 90° - Rotate, -} diff --git a/adb_cli/src/commands/mod.rs b/adb_cli/src/commands/mod.rs deleted file mode 100644 index 5de234f..0000000 --- a/adb_cli/src/commands/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod emu; -mod host; -mod local; -mod tcp; -mod usb; - -pub use emu::EmuCommand; -pub use host::{HostCommand, MdnsCommand}; -pub use local::LocalCommand; -pub use tcp::TcpCommand; -pub use usb::{DeviceCommands, UsbCommand}; diff --git a/adb_cli/src/commands/usb.rs b/adb_cli/src/commands/usb.rs deleted file mode 100644 index 0be4304..0000000 --- a/adb_cli/src/commands/usb.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::num::ParseIntError; -use std::path::PathBuf; - -use clap::Parser; - -use crate::models::RebootTypeCommand; - -fn parse_hex_id(id: &str) -> Result { - u16::from_str_radix(id, 16) -} - -#[derive(Parser, Debug)] -pub struct UsbCommand { - /// Hexadecimal vendor id of this USB device - #[clap(short = 'v', long = "vendor-id", value_parser=parse_hex_id, value_name="VID")] - pub vendor_id: Option, - /// Hexadecimal product id of this USB device - #[clap(short = 'p', long = "product-id", value_parser=parse_hex_id, value_name="PID")] - pub product_id: Option, - /// Path to a custom private key to use for authentication - #[clap(short = 'k', long = "private-key")] - pub path_to_private_key: Option, - #[clap(subcommand)] - pub commands: DeviceCommands, -} - -#[derive(Parser, Debug)] -pub enum DeviceCommands { - /// Spawn an interactive shell or run a list of commands on the device - Shell { commands: Vec }, - /// Pull a file from device - Pull { source: String, destination: String }, - /// Push a file on device - Push { filename: String, path: String }, - /// Stat a file on device - Stat { path: String }, - /// Run an activity on device specified by the intent - Run { - /// The package whose activity is to be invoked - #[clap(short = 'p', long = "package")] - package: String, - /// The activity to be invoked itself, Usually it is MainActivity - #[clap(short = 'a', long = "activity")] - activity: String, - }, - /// Reboot the device - Reboot { - #[clap(subcommand)] - reboot_type: RebootTypeCommand, - }, - /// Install an APK on device - Install { - /// Path to APK file. Extension must be ".apk" - path: PathBuf, - }, - /// Dump framebuffer of device - Framebuffer { - /// Framebuffer image destination path - path: String, - }, -} diff --git a/adb_cli/src/handlers/emulator_commands.rs b/adb_cli/src/handlers/emulator_commands.rs new file mode 100644 index 0000000..5855cd7 --- /dev/null +++ b/adb_cli/src/handlers/emulator_commands.rs @@ -0,0 +1,20 @@ +use adb_client::ADBEmulatorDevice; + +use crate::models::{EmuCommand, EmulatorCommand}; + +pub fn handle_emulator_commands(emulator_command: EmulatorCommand) -> anyhow::Result<()> { + let mut emulator = ADBEmulatorDevice::new(emulator_command.serial, None)?; + + match emulator_command.command { + EmuCommand::Sms { + phone_number, + content, + } => { + emulator.send_sms(&phone_number, &content)?; + log::info!("SMS sent to {phone_number}"); + } + EmuCommand::Rotate => emulator.rotate()?, + } + + Ok(()) +} diff --git a/adb_cli/src/handlers/host_commands.rs b/adb_cli/src/handlers/host_commands.rs new file mode 100644 index 0000000..411bfa1 --- /dev/null +++ b/adb_cli/src/handlers/host_commands.rs @@ -0,0 +1,78 @@ +use adb_client::{ADBServer, DeviceShort, MDNSBackend, Result}; + +use crate::models::{HostCommand, MdnsCommand, ServerCommand}; + +pub fn handle_host_commands(server_command: ServerCommand) -> Result<()> { + let mut adb_server = ADBServer::new(server_command.address); + + match server_command.command { + HostCommand::Version => { + let version = adb_server.version()?; + log::info!("Android Debug Bridge version {}", version); + log::info!("Package version {}-rust", std::env!("CARGO_PKG_VERSION")); + } + HostCommand::Kill => { + adb_server.kill()?; + } + HostCommand::Devices { long } => { + if long { + log::info!("List of devices attached (extended)"); + for device in adb_server.devices_long()? { + log::info!("{}", device); + } + } else { + log::info!("List of devices attached"); + for device in adb_server.devices()? { + log::info!("{}", device); + } + } + } + HostCommand::TrackDevices => { + let callback = |device: DeviceShort| { + log::info!("{}", device); + Ok(()) + }; + log::info!("Live list of devices attached"); + adb_server.track_devices(callback)?; + } + HostCommand::Pair { address, code } => { + adb_server.pair(address, code)?; + log::info!("Paired device {address}"); + } + HostCommand::Connect { address } => { + adb_server.connect_device(address)?; + log::info!("Connected to {address}"); + } + HostCommand::Disconnect { address } => { + adb_server.disconnect_device(address)?; + log::info!("Disconnected {address}"); + } + HostCommand::Mdns { subcommand } => match subcommand { + MdnsCommand::Check => { + let check = adb_server.mdns_check()?; + let server_status = adb_server.server_status()?; + match server_status.mdns_backend { + MDNSBackend::Unknown => log::info!("unknown mdns backend..."), + MDNSBackend::Bonjour => match check { + true => log::info!("mdns daemon version [Bonjour]"), + false => log::info!("ERROR: mdns daemon unavailable"), + }, + MDNSBackend::OpenScreen => { + log::info!("mdns daemon version [Openscreen discovery 0.0.0]") + } + } + } + MdnsCommand::Services => { + log::info!("List of discovered mdns services"); + for service in adb_server.mdns_services()? { + log::info!("{}", service); + } + } + }, + HostCommand::ServerStatus => { + log::info!("{}", adb_server.server_status()?); + } + } + + Ok(()) +} diff --git a/adb_cli/src/handlers/local_commands.rs b/adb_cli/src/handlers/local_commands.rs new file mode 100644 index 0000000..0eebde7 --- /dev/null +++ b/adb_cli/src/handlers/local_commands.rs @@ -0,0 +1,35 @@ +use std::{fs::File, io::Write}; + +use adb_client::ADBServerDevice; +use anyhow::{anyhow, Result}; + +use crate::models::LocalDeviceCommand; + +pub fn handle_local_commands( + mut device: ADBServerDevice, + local_device_commands: LocalDeviceCommand, +) -> Result<()> { + match local_device_commands { + LocalDeviceCommand::HostFeatures => { + let features = device + .host_features()? + .iter() + .map(|v| v.to_string()) + .reduce(|a, b| format!("{a},{b}")) + .ok_or(anyhow!("cannot list features"))?; + log::info!("Available host features: {features}"); + + Ok(()) + } + LocalDeviceCommand::List { path } => Ok(device.list(path)?), + LocalDeviceCommand::Logcat { path } => { + let writer: Box = if let Some(path) = path { + let f = File::create(path)?; + Box::new(f) + } else { + Box::new(std::io::stdout()) + }; + Ok(device.get_logs(writer)?) + } + } +} diff --git a/adb_cli/src/handlers/mod.rs b/adb_cli/src/handlers/mod.rs new file mode 100644 index 0000000..93ca961 --- /dev/null +++ b/adb_cli/src/handlers/mod.rs @@ -0,0 +1,7 @@ +mod emulator_commands; +mod host_commands; +mod local_commands; + +pub use emulator_commands::handle_emulator_commands; +pub use host_commands::handle_host_commands; +pub use local_commands::handle_local_commands; diff --git a/adb_cli/src/main.rs b/adb_cli/src/main.rs index 8674856..e3cd784 100644 --- a/adb_cli/src/main.rs +++ b/adb_cli/src/main.rs @@ -3,336 +3,68 @@ #[cfg(any(target_os = "linux", target_os = "macos"))] mod adb_termios; -mod commands; +mod handlers; mod models; +mod utils; -use adb_client::{ - ADBDeviceExt, ADBEmulatorDevice, ADBServer, ADBTcpDevice, ADBUSBDevice, DeviceShort, - MDNSBackend, MDNSDiscoveryService, -}; -use anyhow::{anyhow, Result}; +use adb_client::{ADBDeviceExt, ADBServer, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService}; +use adb_termios::ADBTermios; +use anyhow::Result; use clap::Parser; -use commands::{DeviceCommands, EmuCommand, HostCommand, LocalCommand, MdnsCommand}; -use models::{Command, Opts}; +use handlers::{handle_emulator_commands, handle_host_commands, handle_local_commands}; +use models::{DeviceCommands, LocalCommand, MainCommand, Opts}; use std::fs::File; use std::io::Write; use std::path::Path; +use utils::setup_logger; fn main() -> Result<()> { let opts = Opts::parse(); - // RUST_LOG variable has more priority then "--debug" flag - if std::env::var("RUST_LOG").is_err() { - let level = match opts.debug { - true => "trace", - false => "info", - }; + setup_logger(opts.debug); - std::env::set_var("RUST_LOG", level); - } + // Directly handling methods / commands that aren't linked to [`ADBDeviceExt`] trait. + // Other methods just have to create a concrete [`ADBDeviceExt`] instance, and return it. + // This instance will then be used to execute desired command. + let (mut device, commands) = match opts.command { + 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); - // Setting default log level as "info" if not set - if std::env::var("RUST_LOG").is_err() { - std::env::set_var("RUST_LOG", "info"); - } - env_logger::init(); - - match opts.command { - Command::Local(local) => { - let mut adb_server = ADBServer::new(opts.address); - - let mut device = match opts.serial { + let device = match server_command.serial { Some(serial) => adb_server.get_device_by_name(&serial)?, None => adb_server.get_device()?, }; - match local { - LocalCommand::Pull { path, filename } => { - let mut output = File::create(Path::new(&filename))?; - device.pull(&path, &mut output)?; - log::info!("Downloaded {path} as {filename}"); - } - LocalCommand::Push { filename, path } => { - let mut input = File::open(Path::new(&filename))?; - device.push(&mut input, &path)?; - log::info!("Uploaded {filename} to {path}"); - } - LocalCommand::List { path } => { - device.list(path)?; - } - LocalCommand::Stat { path } => { - let stat_response = device.stat(path)?; - println!("{}", stat_response); - } - LocalCommand::Shell { commands } => { - if commands.is_empty() { - // Need to duplicate some code here as ADBTermios [Drop] implementation resets terminal state. - // Using a scope here would call drop() too early.. - #[cfg(any(target_os = "linux", target_os = "macos"))] - { - let mut adb_termios = adb_termios::ADBTermios::new(std::io::stdin())?; - adb_termios.set_adb_termios()?; - device.shell(std::io::stdin(), std::io::stdout())?; - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - { - device.shell(std::io::stdin(), std::io::stdout())?; - } - } else { - device.shell_command(commands, std::io::stdout())?; - } - } - LocalCommand::Run { package, activity } => { - let output = device.run_activity(&package, &activity)?; - std::io::stdout().write_all(&output)?; - } - LocalCommand::HostFeatures => { - let features = device - .host_features()? - .iter() - .map(|v| v.to_string()) - .reduce(|a, b| format!("{a},{b}")) - .ok_or(anyhow!("cannot list features"))?; - log::info!("Available host features: {features}"); - } - LocalCommand::Reboot { reboot_type } => { - log::info!("Reboots device in mode {:?}", reboot_type); - device.reboot(reboot_type.into())? - } - LocalCommand::Framebuffer { path } => { - device.framebuffer(&path)?; - log::info!("Framebuffer dropped: {path}"); - } - LocalCommand::Logcat { path } => { - let writer: Box = if let Some(path) = path { - let f = File::create(path)?; - Box::new(f) - } else { - Box::new(std::io::stdout()) - }; - device.get_logs(writer)?; - } - LocalCommand::Install { path } => { - log::info!("Starting installation of APK {}...", path.display()); - device.install(path)?; + match server_command.command { + LocalCommand::DeviceCommands(device_commands) => (device.boxed(), device_commands), + LocalCommand::LocalDeviceCommand(local_device_command) => { + return handle_local_commands(device, local_device_command) } } } - Command::Host(host) => { - let mut adb_server = ADBServer::new(opts.address); - - match host { - HostCommand::Version => { - let version = adb_server.version()?; - log::info!("Android Debug Bridge version {}", version); - log::info!("Package version {}-rust", std::env!("CARGO_PKG_VERSION")); - } - HostCommand::Kill => { - adb_server.kill()?; - } - HostCommand::Devices { long } => { - if long { - log::info!("List of devices attached (extended)"); - for device in adb_server.devices_long()? { - log::info!("{}", device); - } - } else { - log::info!("List of devices attached"); - for device in adb_server.devices()? { - log::info!("{}", device); - } - } - } - HostCommand::TrackDevices => { - let callback = |device: DeviceShort| { - log::info!("{}", device); - Ok(()) - }; - log::info!("Live list of devices attached"); - adb_server.track_devices(callback)?; - } - HostCommand::Pair { address, code } => { - adb_server.pair(address, code)?; - log::info!("Paired device {address}"); - } - HostCommand::Connect { address } => { - adb_server.connect_device(address)?; - log::info!("Connected to {address}"); - } - HostCommand::Disconnect { address } => { - adb_server.disconnect_device(address)?; - log::info!("Disconnected {address}"); - } - HostCommand::Mdns { subcommand } => match subcommand { - MdnsCommand::Check => { - let check = adb_server.mdns_check()?; - let server_status = adb_server.server_status()?; - match server_status.mdns_backend { - MDNSBackend::Unknown => log::info!("unknown mdns backend..."), - MDNSBackend::Bonjour => match check { - true => log::info!("mdns daemon version [Bonjour]"), - false => log::info!("ERROR: mdns daemon unavailable"), - }, - MDNSBackend::OpenScreen => { - log::info!("mdns daemon version [Openscreen discovery 0.0.0]") - } - } - } - MdnsCommand::Services => { - log::info!("List of discovered mdns services"); - for service in adb_server.mdns_services()? { - log::info!("{}", service); - } - } - }, - HostCommand::ServerStatus => { - log::info!("{}", adb_server.server_status()?); - } - } - } - Command::Emu(emu) => { - let mut emulator = match opts.serial { - Some(serial) => ADBEmulatorDevice::new(serial, None)?, - None => return Err(anyhow!("Serial must be set to use emulators !")), - }; - - match emu { - EmuCommand::Sms { - phone_number, - content, - } => { - emulator.send_sms(&phone_number, &content)?; - log::info!("SMS sent to {phone_number}"); - } - EmuCommand::Rotate => emulator.rotate()?, - } - } - Command::Usb(usb) => { - let mut device = match (usb.vendor_id, usb.product_id) { - (Some(vid), Some(pid)) => match usb.path_to_private_key { + MainCommand::Usb(usb_command) => { + let device = match (usb_command.vendor_id, usb_command.product_id) { + (Some(vid), Some(pid)) => match usb_command.path_to_private_key { Some(pk) => ADBUSBDevice::new_with_custom_private_key(vid, pid, pk)?, None => ADBUSBDevice::new(vid, pid)?, }, - - (None, None) => match usb.path_to_private_key { + (None, None) => match usb_command.path_to_private_key { Some(pk) => ADBUSBDevice::autodetect_with_custom_private_key(pk)?, None => ADBUSBDevice::autodetect()?, }, - _ => { anyhow::bail!("please either supply values for both the --vendor-id and --product-id flags or none."); } }; - - match usb.commands { - DeviceCommands::Shell { commands } => { - if commands.is_empty() { - // Need to duplicate some code here as ADBTermios [Drop] implementation resets terminal state. - // Using a scope here would call drop() too early.. - #[cfg(any(target_os = "linux", target_os = "macos"))] - { - let mut adb_termios = adb_termios::ADBTermios::new(std::io::stdin())?; - adb_termios.set_adb_termios()?; - device.shell(std::io::stdin(), std::io::stdout())?; - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - { - device.shell(std::io::stdin(), std::io::stdout())?; - } - } else { - device.shell_command(commands, std::io::stdout())?; - } - } - DeviceCommands::Pull { - source, - destination, - } => { - let mut output = File::create(Path::new(&destination))?; - device.pull(&source, &mut output)?; - log::info!("Downloaded {source} as {destination}"); - } - DeviceCommands::Stat { path } => { - let stat_response = device.stat(&path)?; - println!("{}", stat_response); - } - DeviceCommands::Reboot { reboot_type } => { - log::info!("Reboots device in mode {:?}", reboot_type); - device.reboot(reboot_type.into())? - } - DeviceCommands::Push { filename, path } => { - let mut input = File::open(Path::new(&filename))?; - device.push(&mut input, &path)?; - log::info!("Uploaded {filename} to {path}"); - } - DeviceCommands::Run { package, activity } => { - let output = device.run_activity(&package, &activity)?; - std::io::stdout().write_all(&output)?; - } - DeviceCommands::Install { path } => { - log::info!("Starting installation of APK {}...", path.display()); - device.install(path)?; - } - DeviceCommands::Framebuffer { path } => device.framebuffer(path)?, - } + (device.boxed(), usb_command.commands) } - Command::Tcp(tcp) => { - let mut device = ADBTcpDevice::new(tcp.address)?; - - match tcp.commands { - DeviceCommands::Shell { commands } => { - if commands.is_empty() { - // Need to duplicate some code here as ADBTermios [Drop] implementation resets terminal state. - // Using a scope here would call drop() too early.. - #[cfg(any(target_os = "linux", target_os = "macos"))] - { - let mut adb_termios = adb_termios::ADBTermios::new(std::io::stdin())?; - adb_termios.set_adb_termios()?; - device.shell(std::io::stdin(), std::io::stdout())?; - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - { - device.shell(std::io::stdin(), std::io::stdout())?; - } - } else { - device.shell_command(commands, std::io::stdout())?; - } - } - DeviceCommands::Pull { - source, - destination, - } => { - let mut output = File::create(Path::new(&destination))?; - device.pull(&source, &mut output)?; - log::info!("Downloaded {source} as {destination}"); - } - DeviceCommands::Stat { path } => { - let stat_response = device.stat(&path)?; - println!("{}", stat_response); - } - DeviceCommands::Reboot { reboot_type } => { - log::info!("Reboots device in mode {:?}", reboot_type); - device.reboot(reboot_type.into())? - } - DeviceCommands::Push { filename, path } => { - let mut input = File::open(Path::new(&filename))?; - device.push(&mut input, &path)?; - log::info!("Uploaded {filename} to {path}"); - } - DeviceCommands::Run { package, activity } => { - let output = device.run_activity(&package, &activity)?; - std::io::stdout().write_all(&output)?; - } - DeviceCommands::Install { path } => { - log::info!("Starting installation of APK {}...", path.display()); - device.install(path)?; - } - DeviceCommands::Framebuffer { path } => device.framebuffer(path)?, - } + MainCommand::Tcp(tcp_command) => { + let device = ADBTcpDevice::new(tcp_command.address)?; + (device.boxed(), tcp_command.commands) } - Command::MdnsDiscovery => { + MainCommand::Mdns => { let mut service = MDNSDiscoveryService::new()?; let (tx, rx) = std::sync::mpsc::channel(); @@ -347,8 +79,61 @@ fn main() -> Result<()> { ) } - service.shutdown()?; + return Ok(service.shutdown()?); } + }; + + match commands { + DeviceCommands::Shell { commands } => { + if commands.is_empty() { + // Need to duplicate some code here as ADBTermios [Drop] implementation resets terminal state. + // Using a scope here would call drop() too early.. + #[cfg(any(target_os = "linux", target_os = "macos"))] + { + let mut adb_termios = ADBTermios::new(std::io::stdin())?; + adb_termios.set_adb_termios()?; + device.shell(&mut std::io::stdin(), Box::new(std::io::stdout()))?; + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + { + device.shell(std::io::stdin(), std::io::stdout())?; + } + } else { + let commands: Vec<&str> = commands.iter().map(|v| v.as_str()).collect(); + device.shell_command(&commands, &mut std::io::stdout())?; + } + } + DeviceCommands::Pull { + source, + destination, + } => { + let mut output = File::create(Path::new(&destination))?; + device.pull(&source, &mut output)?; + log::info!("Downloaded {source} as {destination}"); + } + DeviceCommands::Stat { path } => { + let stat_response = device.stat(&path)?; + println!("{}", stat_response); + } + DeviceCommands::Reboot { reboot_type } => { + log::info!("Reboots device in mode {:?}", reboot_type); + device.reboot(reboot_type.into())? + } + DeviceCommands::Push { filename, path } => { + let mut input = File::open(Path::new(&filename))?; + device.push(&mut input, &path)?; + log::info!("Uploaded {filename} to {path}"); + } + DeviceCommands::Run { package, activity } => { + let output = device.run_activity(&package, &activity)?; + std::io::stdout().write_all(&output)?; + } + DeviceCommands::Install { path } => { + log::info!("Starting installation of APK {}...", path.display()); + device.install(&path)?; + } + DeviceCommands::Framebuffer { path } => device.framebuffer(&path)?, } Ok(()) diff --git a/adb_cli/src/commands/local.rs b/adb_cli/src/models/device.rs similarity index 69% rename from adb_cli/src/commands/local.rs rename to adb_cli/src/models/device.rs index fc5fbda..b450486 100644 --- a/adb_cli/src/commands/local.rs +++ b/adb_cli/src/models/device.rs @@ -1,22 +1,19 @@ -use clap::Parser; use std::path::PathBuf; -use crate::models::RebootTypeCommand; +use clap::Parser; + +use super::RebootTypeCommand; #[derive(Parser, Debug)] -pub enum LocalCommand { - /// List available server features. - HostFeatures, - /// Push a file on device - Push { filename: String, path: String }, - /// Pull a file from device - Pull { path: String, filename: String }, - /// List a directory on device - List { path: String }, - /// Stat a file specified on device - Stat { path: String }, +pub enum DeviceCommands { /// Spawn an interactive shell or run a list of commands on the device Shell { commands: Vec }, + /// Pull a file from device + Pull { source: String, destination: String }, + /// Push a file on device + Push { filename: String, path: String }, + /// Stat a file on device + Stat { path: String }, /// Run an activity on device specified by the intent Run { /// The package whose activity is to be invoked @@ -31,16 +28,14 @@ pub enum LocalCommand { #[clap(subcommand)] reboot_type: RebootTypeCommand, }, - /// Dump framebuffer of device - Framebuffer { path: String }, - /// Get logs of device - Logcat { - /// Path to output file (created if not exists) - path: Option, - }, /// Install an APK on device Install { /// Path to APK file. Extension must be ".apk" path: PathBuf, }, + /// Dump framebuffer of device + Framebuffer { + /// Framebuffer image destination path + path: String, + }, } diff --git a/adb_cli/src/models/emu.rs b/adb_cli/src/models/emu.rs new file mode 100644 index 0000000..6149ec0 --- /dev/null +++ b/adb_cli/src/models/emu.rs @@ -0,0 +1,20 @@ +use clap::{Parser, Subcommand}; + +#[derive(Debug, Parser)] +pub struct EmulatorCommand { + #[clap(short = 's', long = "serial")] + pub serial: String, + #[clap(subcommand)] + pub command: EmuCommand, +} + +#[derive(Debug, Subcommand)] +pub enum EmuCommand { + /// Send a SMS with given phone number and given content + Sms { + phone_number: String, + content: String, + }, + /// Rotate device screen from 90° + Rotate, +} diff --git a/adb_cli/src/commands/host.rs b/adb_cli/src/models/host.rs similarity index 100% rename from adb_cli/src/commands/host.rs rename to adb_cli/src/models/host.rs diff --git a/adb_cli/src/models/local.rs b/adb_cli/src/models/local.rs new file mode 100644 index 0000000..188b610 --- /dev/null +++ b/adb_cli/src/models/local.rs @@ -0,0 +1,24 @@ +use clap::Parser; + +use super::DeviceCommands; + +#[derive(Parser, Debug)] +pub enum LocalCommand { + #[clap(flatten)] + DeviceCommands(DeviceCommands), + #[clap(flatten)] + LocalDeviceCommand(LocalDeviceCommand), +} + +#[derive(Parser, Debug)] +pub enum LocalDeviceCommand { + /// List available server features. + HostFeatures, + /// List a directory on device + List { path: String }, + /// Get logs of device + Logcat { + /// Path to output file (created if not exists) + path: Option, + }, +} diff --git a/adb_cli/src/models/mod.rs b/adb_cli/src/models/mod.rs index ddd72a3..ee38727 100644 --- a/adb_cli/src/models/mod.rs +++ b/adb_cli/src/models/mod.rs @@ -1,5 +1,17 @@ +mod device; +mod emu; +mod host; +mod local; mod opts; mod reboot_type; +mod tcp; +mod usb; -pub use opts::{Command, Opts}; +pub use device::DeviceCommands; +pub use emu::{EmuCommand, EmulatorCommand}; +pub use host::{HostCommand, MdnsCommand}; +pub use local::{LocalCommand, LocalDeviceCommand}; +pub use opts::{MainCommand, Opts, ServerCommand}; pub use reboot_type::RebootTypeCommand; +pub use tcp::TcpCommand; +pub use usb::UsbCommand; diff --git a/adb_cli/src/models/opts.rs b/adb_cli/src/models/opts.rs index 1b28670..41f1b0c 100644 --- a/adb_cli/src/models/opts.rs +++ b/adb_cli/src/models/opts.rs @@ -1,36 +1,41 @@ use std::net::SocketAddrV4; -use clap::Parser; +use clap::{Parser, Subcommand}; -use crate::commands::{EmuCommand, HostCommand, LocalCommand, TcpCommand, UsbCommand}; +use super::{EmulatorCommand, HostCommand, LocalCommand, TcpCommand, UsbCommand}; -#[derive(Parser, Debug)] +#[derive(Debug, Parser)] #[clap(about, version, author)] pub struct Opts { #[clap(long = "debug")] pub debug: bool, + #[clap(subcommand)] + pub command: MainCommand, +} + +#[derive(Debug, Parser)] +pub enum MainCommand { + /// Server related commands + Host(ServerCommand), + /// Device related commands using server + Local(ServerCommand), + /// Emulator related commands + Emu(EmulatorCommand), + /// USB device related commands + Usb(UsbCommand), + /// TCP device related commands + Tcp(TcpCommand), + /// MDNS discovery related commands + Mdns, +} + +#[derive(Debug, Parser)] +pub struct ServerCommand { #[clap(short = 'a', long = "address", default_value = "127.0.0.1:5037")] pub address: SocketAddrV4, /// Serial id of a specific device. Every request will be sent to this device. #[clap(short = 's', long = "serial")] pub serial: Option, #[clap(subcommand)] - pub command: Command, -} - -#[derive(Parser, Debug)] -pub enum Command { - #[clap(flatten)] - Local(LocalCommand), - #[clap(flatten)] - Host(HostCommand), - /// Emulator specific commands - #[clap(subcommand)] - Emu(EmuCommand), - /// Device commands via USB, no server needed - Usb(UsbCommand), - /// Device commands via TCP, no server needed - Tcp(TcpCommand), - /// Discover devices over MDNS without using adb-server - MdnsDiscovery, + pub command: T, } diff --git a/adb_cli/src/commands/tcp.rs b/adb_cli/src/models/tcp.rs similarity index 100% rename from adb_cli/src/commands/tcp.rs rename to adb_cli/src/models/tcp.rs diff --git a/adb_cli/src/models/usb.rs b/adb_cli/src/models/usb.rs new file mode 100644 index 0000000..76411b9 --- /dev/null +++ b/adb_cli/src/models/usb.rs @@ -0,0 +1,25 @@ +use std::num::ParseIntError; +use std::path::PathBuf; + +use clap::Parser; + +use super::DeviceCommands; + +fn parse_hex_id(id: &str) -> Result { + u16::from_str_radix(id, 16) +} + +#[derive(Parser, Debug)] +pub struct UsbCommand { + /// Hexadecimal vendor id of this USB device + #[clap(short = 'v', long = "vendor-id", value_parser=parse_hex_id, value_name="VID")] + pub vendor_id: Option, + /// Hexadecimal product id of this USB device + #[clap(short = 'p', long = "product-id", value_parser=parse_hex_id, value_name="PID")] + pub product_id: Option, + /// Path to a custom private key to use for authentication + #[clap(short = 'k', long = "private-key")] + pub path_to_private_key: Option, + #[clap(subcommand)] + pub commands: DeviceCommands, +} diff --git a/adb_cli/src/utils.rs b/adb_cli/src/utils.rs new file mode 100644 index 0000000..1a87d3b --- /dev/null +++ b/adb_cli/src/utils.rs @@ -0,0 +1,13 @@ +pub fn setup_logger(debug: bool) { + // RUST_LOG variable has more priority then "--debug" flag + if std::env::var("RUST_LOG").is_err() { + let level = match debug { + true => "trace", + false => "info", + }; + + std::env::set_var("RUST_LOG", level); + } + + env_logger::init(); +} diff --git a/adb_client/README.md b/adb_client/README.md index f22ed46..408e16f 100644 --- a/adb_client/README.md +++ b/adb_client/README.md @@ -54,7 +54,7 @@ use adb_client::{ADBServer, ADBDeviceExt}; let mut server = ADBServer::default(); let mut device = server.get_device().expect("cannot get device"); -device.shell_command(["df", "-h"],std::io::stdout()); +device.shell_command(&["df", "-h"], &mut std::io::stdout()); ``` #### Push a file to the device @@ -81,7 +81,7 @@ use adb_client::{ADBUSBDevice, ADBDeviceExt}; let vendor_id = 0x04e8; let product_id = 0x6860; let mut device = ADBUSBDevice::new(vendor_id, product_id).expect("cannot find device"); -device.shell_command(["df", "-h"],std::io::stdout()); +device.shell_command(&["df", "-h"], &mut std::io::stdout()); ``` #### (USB) Push a file to the device @@ -95,7 +95,7 @@ let vendor_id = 0x04e8; let product_id = 0x6860; let mut device = ADBUSBDevice::new(vendor_id, product_id).expect("cannot find device"); let mut input = File::open(Path::new("/tmp/f")).expect("Cannot open file"); -device.push(&mut input, "/data/local/tmp"); +device.push(&mut input, &"/data/local/tmp"); ``` #### (TCP) Get a shell from device @@ -107,5 +107,5 @@ use adb_client::{ADBTcpDevice, ADBDeviceExt}; let device_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 0, 10)); let device_port = 43210; let mut device = ADBTcpDevice::new(SocketAddr::new(device_ip, device_port)).expect("cannot find device"); -device.shell(std::io::stdin(), std::io::stdout()); +device.shell(&mut std::io::stdin(), Box::new(std::io::stdout())); ``` diff --git a/adb_client/src/adb_device_ext.rs b/adb_client/src/adb_device_ext.rs index 220af3f..220d36f 100644 --- a/adb_client/src/adb_device_ext.rs +++ b/adb_client/src/adb_device_ext.rs @@ -1,31 +1,28 @@ -use std::io::{Read, Seek, Write}; +use std::io::{Cursor, Read, Write}; use std::path::Path; +use image::{ImageBuffer, ImageFormat, Rgba}; + use crate::models::AdbStatResponse; use crate::{RebootType, Result}; /// Trait representing all features available on both [`crate::ADBServerDevice`] and [`crate::ADBUSBDevice`] pub trait ADBDeviceExt { /// Runs command in a shell on the device, and write its output and error streams into output. - fn shell_command( - &mut self, - command: impl IntoIterator, - output: W, - ) -> Result<()>; + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()>; /// Starts an interactive shell session on the device. /// Input data is read from reader and write to writer. - /// W has a 'static bound as it is internally used in a thread. - fn shell(&mut self, reader: R, writer: W) -> Result<()>; + fn shell(&mut self, reader: &mut dyn Read, writer: Box<(dyn Write + Send)>) -> Result<()>; /// Display the stat information for a remote file fn stat(&mut self, remote_path: &str) -> Result; /// Pull the remote file pointed to by `source` and write its contents into `output` - fn pull, W: Write>(&mut self, source: A, output: W) -> Result<()>; + fn pull(&mut self, source: &dyn AsRef, output: &mut dyn Write) -> Result<()>; /// Push `stream` to `path` on the device. - fn push>(&mut self, stream: R, path: A) -> Result<()>; + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()>; /// Reboot the device using given reboot type fn reboot(&mut self, reboot_type: RebootType) -> Result<()>; @@ -34,7 +31,7 @@ pub trait ADBDeviceExt { fn run_activity(&mut self, package: &str, activity: &str) -> Result> { let mut output = Vec::new(); self.shell_command( - ["am", "start", &format!("{package}/{package}.{activity}")], + &["am", "start", &format!("{package}/{package}.{activity}")], &mut output, )?; @@ -42,13 +39,35 @@ pub trait ADBDeviceExt { } /// Install an APK pointed to by `apk_path` on device. - fn install>(&mut self, apk_path: P) -> Result<()>; + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()>; + + /// Inner method requesting framebuffer from an Android device + fn framebuffer_inner(&mut self) -> Result, Vec>>; /// Dump framebuffer of this device into given path - fn framebuffer>(&mut self, path: P) -> Result<()>; + fn framebuffer(&mut self, path: &dyn AsRef) -> Result<()> { + // Big help from AOSP source code () + let img = self.framebuffer_inner()?; + Ok(img.save(path.as_ref())?) + } /// Dump framebuffer of this device and return corresponding bytes. /// /// Output data format is currently only `PNG`. - fn framebuffer_bytes(&mut self, writer: W) -> Result<()>; + fn framebuffer_bytes(&mut self) -> Result> { + let img = self.framebuffer_inner()?; + let mut vec = Cursor::new(Vec::new()); + img.write_to(&mut vec, ImageFormat::Png)?; + + Ok(vec.into_inner()) + } + + /// Return a boxed instance representing this trait + fn boxed(self) -> Box + where + Self: Sized, + Self: 'static, + { + Box::new(self) + } } diff --git a/adb_client/src/device/adb_message_device_commands.rs b/adb_client/src/device/adb_message_device_commands.rs index 7bcf472..4dc7bda 100644 --- a/adb_client/src/device/adb_message_device_commands.rs +++ b/adb_client/src/device/adb_message_device_commands.rs @@ -1,18 +1,17 @@ use crate::{models::AdbStatResponse, ADBDeviceExt, ADBMessageTransport, RebootType, Result}; -use std::io::{Read, Write}; +use std::{ + io::{Read, Write}, + path::Path, +}; use super::ADBMessageDevice; impl ADBDeviceExt for ADBMessageDevice { - fn shell_command( - &mut self, - command: impl IntoIterator, - output: W, - ) -> Result<()> { + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { self.shell_command(command, output) } - fn shell(&mut self, reader: R, writer: W) -> Result<()> { + fn shell(&mut self, reader: &mut dyn Read, writer: Box<(dyn Write + Send)>) -> Result<()> { self.shell(reader, writer) } @@ -20,11 +19,11 @@ impl ADBDeviceExt for ADBMessageDevice { self.stat(remote_path) } - fn pull, W: Write>(&mut self, source: A, output: W) -> Result<()> { + fn pull(&mut self, source: &dyn AsRef, output: &mut dyn Write) -> Result<()> { self.pull(source, output) } - fn push>(&mut self, stream: R, path: A) -> Result<()> { + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { self.push(stream, path) } @@ -32,15 +31,11 @@ impl ADBDeviceExt for ADBMessageDevice { self.reboot(reboot_type) } - fn install>(&mut self, apk_path: P) -> Result<()> { + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.install(apk_path) } - fn framebuffer>(&mut self, path: P) -> Result<()> { - self.framebuffer(path) - } - - fn framebuffer_bytes(&mut self, writer: W) -> Result<()> { - self.framebuffer_bytes(writer) + fn framebuffer_inner(&mut self) -> Result, Vec>> { + self.framebuffer_inner() } } diff --git a/adb_client/src/device/adb_tcp_device.rs b/adb_client/src/device/adb_tcp_device.rs index 577c23b..b1c622b 100644 --- a/adb_client/src/device/adb_tcp_device.rs +++ b/adb_client/src/device/adb_tcp_device.rs @@ -1,5 +1,6 @@ -use std::net::SocketAddr; +use std::io::Write; use std::path::Path; +use std::{io::Read, net::SocketAddr}; use super::adb_message_device::ADBMessageDevice; use super::models::MessageCommand; @@ -67,20 +68,12 @@ impl ADBTcpDevice { impl ADBDeviceExt for ADBTcpDevice { #[inline] - fn shell_command( - &mut self, - command: impl IntoIterator, - output: W, - ) -> Result<()> { + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { self.inner.shell_command(command, output) } #[inline] - fn shell( - &mut self, - reader: R, - writer: W, - ) -> Result<()> { + fn shell(&mut self, reader: &mut dyn Read, writer: Box<(dyn Write + Send)>) -> Result<()> { self.inner.shell(reader, writer) } @@ -90,12 +83,12 @@ impl ADBDeviceExt for ADBTcpDevice { } #[inline] - fn pull, W: std::io::Write>(&mut self, source: A, output: W) -> Result<()> { + fn pull(&mut self, source: &dyn AsRef, output: &mut dyn Write) -> Result<()> { self.inner.pull(source, output) } #[inline] - fn push>(&mut self, stream: R, path: A) -> Result<()> { + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { self.inner.push(stream, path) } @@ -105,18 +98,13 @@ impl ADBDeviceExt for ADBTcpDevice { } #[inline] - fn install>(&mut self, apk_path: P) -> Result<()> { + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.inner.install(apk_path) } #[inline] - fn framebuffer>(&mut self, path: P) -> Result<()> { - self.inner.framebuffer(path) - } - - #[inline] - fn framebuffer_bytes(&mut self, writer: W) -> Result<()> { - self.inner.framebuffer_bytes(writer) + fn framebuffer_inner(&mut self) -> Result, Vec>> { + self.inner.framebuffer_inner() } } diff --git a/adb_client/src/device/adb_usb_device.rs b/adb_client/src/device/adb_usb_device.rs index c2319b9..b2d72d3 100644 --- a/adb_client/src/device/adb_usb_device.rs +++ b/adb_client/src/device/adb_usb_device.rs @@ -2,6 +2,8 @@ use rusb::Device; use rusb::DeviceDescriptor; use rusb::UsbContext; use std::fs::read_to_string; +use std::io::Read; +use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::time::Duration; @@ -249,20 +251,12 @@ impl ADBUSBDevice { impl ADBDeviceExt for ADBUSBDevice { #[inline] - fn shell_command( - &mut self, - command: impl IntoIterator, - output: W, - ) -> Result<()> { + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { self.inner.shell_command(command, output) } #[inline] - fn shell( - &mut self, - reader: R, - writer: W, - ) -> Result<()> { + fn shell<'a>(&mut self, reader: &mut dyn Read, writer: Box<(dyn Write + Send)>) -> Result<()> { self.inner.shell(reader, writer) } @@ -272,12 +266,12 @@ impl ADBDeviceExt for ADBUSBDevice { } #[inline] - fn pull, W: std::io::Write>(&mut self, source: A, output: W) -> Result<()> { + fn pull(&mut self, source: &dyn AsRef, output: &mut dyn Write) -> Result<()> { self.inner.pull(source, output) } #[inline] - fn push>(&mut self, stream: R, path: A) -> Result<()> { + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { self.inner.push(stream, path) } @@ -287,18 +281,13 @@ impl ADBDeviceExt for ADBUSBDevice { } #[inline] - fn install>(&mut self, apk_path: P) -> Result<()> { + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.inner.install(apk_path) } #[inline] - fn framebuffer>(&mut self, path: P) -> Result<()> { - self.inner.framebuffer(path) - } - - #[inline] - fn framebuffer_bytes(&mut self, writer: W) -> Result<()> { - self.inner.framebuffer_bytes(writer) + fn framebuffer_inner(&mut self) -> Result, Vec>> { + self.inner.framebuffer_inner() } } diff --git a/adb_client/src/device/commands/framebuffer.rs b/adb_client/src/device/commands/framebuffer.rs index bbf4ce8..5b8e87f 100644 --- a/adb_client/src/device/commands/framebuffer.rs +++ b/adb_client/src/device/commands/framebuffer.rs @@ -1,7 +1,7 @@ -use std::io::{Cursor, Read, Write}; +use std::io::{Cursor, Read}; use byteorder::{LittleEndian, ReadBytesExt}; -use image::{ImageBuffer, ImageFormat, Rgba}; +use image::{ImageBuffer, Rgba}; use crate::{ device::{adb_message_device::ADBMessageDevice, MessageCommand}, @@ -10,17 +10,7 @@ use crate::{ }; impl ADBMessageDevice { - pub fn framebuffer>(&mut self, path: P) -> Result<()> { - let img = self.framebuffer_inner()?; - Ok(img.save(path.as_ref())?) - } - - pub fn framebuffer_bytes(&mut self, mut writer: W) -> Result<()> { - let img = self.framebuffer_inner()?; - Ok(img.write_to(&mut writer, ImageFormat::Png)?) - } - - fn framebuffer_inner(&mut self) -> Result, Vec>> { + pub(crate) fn framebuffer_inner(&mut self) -> Result, Vec>> { self.open_session(b"framebuffer:\0")?; let response = self.recv_and_reply_okay()?; diff --git a/adb_client/src/device/commands/install.rs b/adb_client/src/device/commands/install.rs index b2b53d1..14f7d84 100644 --- a/adb_client/src/device/commands/install.rs +++ b/adb_client/src/device/commands/install.rs @@ -1,4 +1,4 @@ -use std::fs::File; +use std::{fs::File, path::Path}; use rand::Rng; @@ -9,10 +9,10 @@ use crate::{ }; impl ADBMessageDevice { - pub(crate) fn install>(&mut self, apk_path: P) -> Result<()> { - let mut apk_file = File::open(&apk_path)?; + pub(crate) fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { + let mut apk_file = File::open(apk_path)?; - check_extension_is_apk(&apk_path)?; + check_extension_is_apk(apk_path)?; let file_size = apk_file.metadata()?.len(); diff --git a/adb_client/src/device/commands/shell.rs b/adb_client/src/device/commands/shell.rs index fce13b2..059f2bf 100644 --- a/adb_client/src/device/commands/shell.rs +++ b/adb_client/src/device/commands/shell.rs @@ -9,22 +9,8 @@ use crate::{ impl ADBMessageDevice { /// Runs 'command' in a shell on the device, and write its output and error streams into output. - pub(crate) fn shell_command( - &mut self, - command: impl IntoIterator, - mut output: W, - ) -> Result<()> { - let response = self.open_session( - format!( - "shell:{}\0", - command - .into_iter() - .map(|v| v.to_string()) - .collect::>() - .join(" "), - ) - .as_bytes(), - )?; + pub(crate) fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { + let response = self.open_session(format!("shell:{}\0", command.join(" "),).as_bytes())?; if response.header().command() != MessageCommand::Okay { return Err(RustADBError::ADBRequestFailed(format!( @@ -47,11 +33,10 @@ impl ADBMessageDevice { /// Starts an interactive shell session on the device. /// Input data is read from [reader] and write to [writer]. - /// [W] has a 'static bound as it is internally used in a thread. - pub(crate) fn shell( + pub(crate) fn shell( &mut self, - mut reader: R, - mut writer: W, + mut reader: &mut dyn Read, + mut writer: Box<(dyn Write + Send)>, ) -> Result<()> { self.open_session(b"shell:\0")?; 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 1edc60e..9571b40 100644 --- a/adb_client/src/server_device/adb_server_device_commands.rs +++ b/adb_client/src/server_device/adb_server_device_commands.rs @@ -12,11 +12,7 @@ use crate::{ use super::ADBServerDevice; impl ADBDeviceExt for ADBServerDevice { - fn shell_command( - &mut self, - command: impl IntoIterator, - mut output: W, - ) -> Result<()> { + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { let supported_features = self.host_features()?; if !supported_features.contains(&HostFeatures::ShellV2) && !supported_features.contains(&HostFeatures::Cmd) @@ -28,13 +24,7 @@ impl ADBDeviceExt for ADBServerDevice { self.connect()? .send_adb_request(AdbServerCommand::TransportSerial(serial))?; self.get_transport_mut() - .send_adb_request(AdbServerCommand::ShellCommand( - command - .into_iter() - .map(|v| v.to_string()) - .collect::>() - .join(" "), - ))?; + .send_adb_request(AdbServerCommand::ShellCommand(command.join(" ")))?; const BUFFER_SIZE: usize = 4096; loop { @@ -62,10 +52,10 @@ impl ADBDeviceExt for ADBServerDevice { self.stat(remote_path) } - fn shell( + fn shell( &mut self, - mut reader: R, - mut writer: W, + mut reader: &mut dyn Read, + mut writer: Box<(dyn Write + Send)>, ) -> Result<()> { let supported_features = self.host_features()?; if !supported_features.contains(&HostFeatures::ShellV2) @@ -115,7 +105,7 @@ impl ADBDeviceExt for ADBServerDevice { Ok(()) } - fn pull, W: Write>(&mut self, source: A, mut output: W) -> Result<()> { + fn pull(&mut self, source: &dyn AsRef, mut output: &mut dyn Write) -> Result<()> { self.pull(source, &mut output) } @@ -123,19 +113,15 @@ impl ADBDeviceExt for ADBServerDevice { self.reboot(reboot_type) } - fn push>(&mut self, stream: R, path: A) -> Result<()> { + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { self.push(stream, path) } - fn install>(&mut self, apk_path: P) -> Result<()> { + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.install(apk_path) } - fn framebuffer>(&mut self, path: P) -> Result<()> { - self.framebuffer(path) - } - - fn framebuffer_bytes(&mut self, writer: W) -> Result<()> { - self.framebuffer_bytes(writer) + fn framebuffer_inner(&mut self) -> Result, Vec>> { + self.framebuffer_inner() } } diff --git a/adb_client/src/server_device/commands/framebuffer.rs b/adb_client/src/server_device/commands/framebuffer.rs index d3b6035..b4863c8 100644 --- a/adb_client/src/server_device/commands/framebuffer.rs +++ b/adb_client/src/server_device/commands/framebuffer.rs @@ -1,10 +1,7 @@ -use std::{ - io::{Read, Seek, Write}, - path::Path, -}; +use std::io::Read; use byteorder::{LittleEndian, ReadBytesExt}; -use image::{ImageBuffer, ImageFormat, Rgba}; +use image::{ImageBuffer, Rgba}; use crate::{ models::{AdbServerCommand, FrameBufferInfoV1, FrameBufferInfoV2}, @@ -12,23 +9,8 @@ use crate::{ }; impl ADBServerDevice { - /// Dump framebuffer of this device into given ['path'] - /// Big help from source code () - pub(crate) fn framebuffer>(&mut self, path: P) -> Result<()> { - let img = self.framebuffer_inner()?; - Ok(img.save(path.as_ref())?) - } - - /// Dump framebuffer of this device and return corresponding bytes. - /// - /// Output data format is currently only `PNG`. - pub(crate) fn framebuffer_bytes(&mut self, mut writer: W) -> Result<()> { - let img = self.framebuffer_inner()?; - Ok(img.write_to(&mut writer, ImageFormat::Png)?) - } - /// Inner method requesting framebuffer from Android device - fn framebuffer_inner(&mut self) -> Result, Vec>> { + pub(crate) fn framebuffer_inner(&mut self) -> Result, Vec>> { let serial: String = self.identifier.clone(); self.connect()? .send_adb_request(AdbServerCommand::TransportSerial(serial))?; diff --git a/adb_client/src/server_device/commands/logcat.rs b/adb_client/src/server_device/commands/logcat.rs index e39683e..b2dc0d4 100644 --- a/adb_client/src/server_device/commands/logcat.rs +++ b/adb_client/src/server_device/commands/logcat.rs @@ -51,6 +51,6 @@ impl Write for LogFilter { impl ADBServerDevice { /// Get logs from device pub fn get_logs(&mut self, output: W) -> Result<()> { - self.shell_command(["exec logcat"], LogFilter::new(output)) + self.shell_command(&["exec logcat"], &mut LogFilter::new(output)) } } diff --git a/adb_client/src/server_device/commands/recv.rs b/adb_client/src/server_device/commands/recv.rs index 165e961..bff7df8 100644 --- a/adb_client/src/server_device/commands/recv.rs +++ b/adb_client/src/server_device/commands/recv.rs @@ -70,7 +70,7 @@ impl Read for ADBRecvCommandReader { impl ADBServerDevice { /// Receives path to stream from the device. - pub fn pull>(&mut self, path: A, stream: &mut dyn Write) -> Result<()> { + 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))?;