Skip to content

Commit

Permalink
feat: add USB interactive shell; feat: rework ADBUSBMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
cocool97 committed Oct 20, 2024
1 parent fc1fe74 commit 34d8688
Show file tree
Hide file tree
Showing 18 changed files with 355 additions and 179 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ codegen-units = 1
debug-assertions = false
lto = "thin"
opt-level = 'z'
strip = true
strip = true
2 changes: 1 addition & 1 deletion adb_cli/src/commands/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum LocalCommand {
/// Stat a file specified on device
Stat { path: String },
/// Spawn an interactive shell or run a list of commands on the device
Shell { command: Vec<String> },
Shell { commands: Vec<String> },
/// Reboot the device
Reboot {
#[clap(subcommand)]
Expand Down
2 changes: 1 addition & 1 deletion adb_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ mod usb;
pub use emu::EmuCommand;
pub use host::HostCommand;
pub use local::LocalCommand;
pub use usb::UsbCommand;
pub use usb::{UsbCommand, UsbCommands};
9 changes: 6 additions & 3 deletions adb_cli/src/commands/usb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ pub struct UsbCommand {
/// Path to a custom private key to use for authentication
#[clap(short = 'k', long = "private-key")]
pub path_to_private_key: Option<PathBuf>,
// #[clap(subcommand)]
// pub commands: UsbCommands
#[clap(subcommand)]
pub commands: UsbCommands,
}

#[derive(Parser, Debug)]
pub enum UsbCommands {}
pub enum UsbCommands {
/// Spawn an interactive shell or run a list of commands on the device
Shell { commands: Vec<String> },
}
32 changes: 26 additions & 6 deletions adb_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod models;
use adb_client::{ADBDeviceExt, ADBEmulatorDevice, ADBServer, ADBUSBDevice, DeviceShort};
use anyhow::{anyhow, Result};
use clap::Parser;
use commands::{EmuCommand, HostCommand, LocalCommand};
use commands::{EmuCommand, HostCommand, LocalCommand, UsbCommands};
use env_logger::Builder;
use log::LevelFilter;
use models::{Command, Opts};
Expand Down Expand Up @@ -56,8 +56,8 @@ fn main() -> Result<()> {
let stat_response = device.stat(path)?;
log::info!("{}", stat_response);
}
LocalCommand::Shell { command } => {
if command.is_empty() {
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"))]
Expand All @@ -72,7 +72,7 @@ fn main() -> Result<()> {
device.shell(std::io::stdin(), std::io::stdout())?;
}
} else {
device.shell_command(command, std::io::stdout())?;
device.shell_command(commands, std::io::stdout())?;
}
}
LocalCommand::HostFeatures => {
Expand Down Expand Up @@ -170,8 +170,28 @@ fn main() -> Result<()> {
Command::Usb(usb) => {
let mut device =
ADBUSBDevice::new(usb.vendor_id, usb.product_id, usb.path_to_private_key)?;
device.send_connect()?;
device.shell_command(["id"], std::io::stdout())?;

match usb.commands {
UsbCommands::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())?;
}
}
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion adb_client/src/adb_device_ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::Write;
use std::io::{Read, Write};

use crate::Result;

Expand All @@ -10,4 +10,9 @@ pub trait ADBDeviceExt {
command: impl IntoIterator<Item = S>,
output: W,
) -> 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<R: Read, W: Write + Send + 'static>(&mut self, reader: R, writer: W) -> Result<()>;
}
6 changes: 3 additions & 3 deletions adb_client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ pub enum RustADBError {
/// No descriptor found
#[error("No USB descriptor found")]
USBNoDescriptorFound,
/// CRC32 of the received message is invalid
#[error("Invalid CRC32. Expected {0} got {1}")]
InvalidCRC32(u32, u32),
/// Integrity of the received message cannot be validated
#[error("Invalid integrity. Expected CRC32 {0}, got {1}")]
InvalidIntegrity(u32, u32),
/// Error while decoding base64 data
#[error(transparent)]
Base64DecodeError(#[from] base64::DecodeError),
Expand Down
54 changes: 54 additions & 0 deletions adb_client/src/server/adb_server_device_commands.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io::{Read, Write};

use crate::{
constants::BUFFER_SIZE,
models::{AdbServerCommand, HostFeatures},
ADBDeviceExt, ADBServerDevice, Result, RustADBError,
};
Expand Down Expand Up @@ -51,4 +52,57 @@ impl ADBDeviceExt for ADBServerDevice {
}
}
}

fn shell<R: Read, W: Write + Send + 'static>(
&mut self,
mut reader: R,
mut writer: W,
) -> Result<()> {
let supported_features = self.host_features()?;
if !supported_features.contains(&HostFeatures::ShellV2)
&& !supported_features.contains(&HostFeatures::Cmd)
{
return Err(RustADBError::ADBShellNotSupported);
}

let serial = self.identifier.clone();
self.connect()?
.send_adb_request(AdbServerCommand::TransportSerial(serial))?;
self.get_transport_mut()
.send_adb_request(AdbServerCommand::Shell)?;

let mut read_stream = self.get_transport_mut().get_raw_connection()?.try_clone()?;

let mut write_stream = read_stream.try_clone()?;

// Reading thread, reads response from adb-server
std::thread::spawn(move || -> Result<()> {
loop {
let mut buffer = [0; BUFFER_SIZE];
match read_stream.read(&mut buffer) {
Ok(0) => {
read_stream.shutdown(std::net::Shutdown::Both)?;
return Ok(());
}
Ok(size) => {
writer.write_all(&buffer[..size])?;
writer.flush()?;
}
Err(e) => {
return Err(RustADBError::IOError(e));
}
}
}
});

// Read from given reader (that could be stdin e.g), and write content to server socket
if let Err(e) = std::io::copy(&mut reader, &mut write_stream) {
match e.kind() {
std::io::ErrorKind::BrokenPipe => return Ok(()),
_ => return Err(RustADBError::IOError(e)),
}
}

Ok(())
}
}
1 change: 0 additions & 1 deletion adb_client/src/server/device_commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ mod logcat;
mod reboot;
mod recv;
mod send;
mod shell;
mod stat;
mod transport;
66 changes: 0 additions & 66 deletions adb_client/src/server/device_commands/shell.rs

This file was deleted.

1 change: 0 additions & 1 deletion adb_client/src/server/server_commands/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ impl ADBServer {
}

/// Tracks new devices showing up.
// TODO: Change with Generator when feature stabilizes
pub fn track_devices(&mut self, callback: impl Fn(DeviceShort) -> Result<()>) -> Result<()> {
self.connect()?
.send_adb_request(AdbServerCommand::TrackDevices)?;
Expand Down
Loading

0 comments on commit 34d8688

Please sign in to comment.