Skip to content

Commit

Permalink
feat: USB shell command, WIP for other commands
Browse files Browse the repository at this point in the history
  • Loading branch information
cocool97 committed Oct 16, 2024
1 parent b21fe23 commit 8d12e8b
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 158 deletions.
3 changes: 2 additions & 1 deletion adb_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod adb_termios;
mod commands;
mod models;

use adb_client::{ADBEmulatorDevice, ADBServer, ADBUSBDevice, DeviceShort};
use adb_client::{ADBDeviceExt, ADBEmulatorDevice, ADBServer, ADBUSBDevice, DeviceShort};
use anyhow::{anyhow, Result};
use clap::Parser;
use commands::{EmuCommand, HostCommand, LocalCommand};
Expand Down Expand Up @@ -171,6 +171,7 @@ fn main() -> Result<()> {
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())?;
}
}

Expand Down
5 changes: 2 additions & 3 deletions adb_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ homedir = { version = "0.3.3" }
image = { version = "0.25.2" }
lazy_static = { version = "1.5.0" }
log = { version = "0.4.22" }
rand = { version = "0.8.5" }
num-bigint = { version = "0.6", package = "num-bigint-dig" }
regex = { version = "1.10.6", features = ["perf", "std", "unicode"] }
rsa = { version = "0.9.6", features = ["sha1"] }
rsa = { version = "0.3.0" }
rusb = { version = "0.9.4", features = ["vendored"] }
sha1 = "0.10.6"
thiserror = { version = "1.0.64" }
13 changes: 13 additions & 0 deletions adb_client/src/adb_device_ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::io::Write;

use crate::Result;

/// Trait representing all features available on both [`ADBServerDevice`] and [`ADBUSBDevice`]
pub trait ADBDeviceExt {
/// Runs 'command' in a shell on the device, and write its output and error streams into [`output`].
fn shell_command<S: ToString, W: Write>(
&mut self,
command: impl IntoIterator<Item = S>,
output: W,
) -> Result<()>;
}
15 changes: 6 additions & 9 deletions adb_client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,13 @@ pub enum RustADBError {
/// CRC32 of the received message is invalid
#[error("Invalid CRC32. Expected {0} got {1}")]
InvalidCRC32(u32, u32),
/// An error occurred with RSA private key
/// Error while decoding base64 data
#[error(transparent)]
RSAError(#[from] rsa::Error),
/// An error occurred with RSA PKCS#1
Base64DecodeError(#[from] base64::DecodeError),
/// Error while encoding base64 data
#[error(transparent)]
RSAPKCS1Error(#[from] rsa::pkcs1::Error),
/// An error occurred with RSA PKCS#8
Base64EncodeError(#[from] base64::EncodeSliceError),
/// An error occurred with RSA engine
#[error(transparent)]
RSAPKCS8Error(#[from] rsa::pkcs8::Error),
/// An error occurred with RSA signature
#[error(transparent)]
RSASignatureError(#[from] rsa::signature::Error),
RSAError(#[from] rsa::errors::Error),
}
2 changes: 2 additions & 0 deletions adb_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![forbid(missing_docs)]
#![doc = include_str!("../README.md")]

mod adb_device_ext;
mod constants;
mod emulator;
mod error;
Expand All @@ -13,6 +14,7 @@ mod transports;
mod usb;
mod utils;

pub use adb_device_ext::ADBDeviceExt;
pub use error::{Result, RustADBError};
pub use models::{AdbVersion, DeviceLong, DeviceShort, DeviceState, RebootType};
pub use server::*;
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
@@ -0,0 +1,54 @@
use std::io::{Read, Write};

use crate::{
models::{AdbServerCommand, HostFeatures},
ADBDeviceExt, ADBServerDevice, Result, RustADBError,
};

impl ADBDeviceExt for ADBServerDevice {
fn shell_command<S: ToString, W: Write>(
&mut self,
command: impl IntoIterator<Item = S>,
mut output: 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::ShellCommand(
command
.into_iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(" "),
))?;

const BUFFER_SIZE: usize = 4096;
loop {
let mut buffer = [0; BUFFER_SIZE];
match self
.get_transport_mut()
.get_raw_connection()?
.read(&mut buffer)
{
Ok(size) => {
if size == 0 {
return Ok(());
} else {
output.write_all(&buffer[..size])?;
}
}
Err(e) => {
return Err(RustADBError::IOError(e));
}
}
}
}
}
2 changes: 1 addition & 1 deletion adb_client/src/server/device_commands/logcat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::{self, Write};

use crate::{ADBServerDevice, Result};
use crate::{ADBDeviceExt, ADBServerDevice, Result};

struct LogFilter<W: Write> {
writer: W,
Expand Down
47 changes: 0 additions & 47 deletions adb_client/src/server/device_commands/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,6 @@ use crate::{
const BUFFER_SIZE: usize = 512;

impl ADBServerDevice {
/// Runs 'command' in a shell on the device, and write its output and error streams into [`output`].
pub fn shell_command<S: ToString, W: Write>(
&mut self,
command: impl IntoIterator<Item = S>,
mut output: 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::ShellCommand(
command
.into_iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(" "),
))?;

const BUFFER_SIZE: usize = 4096;
loop {
let mut buffer = [0; BUFFER_SIZE];
match self
.get_transport_mut()
.get_raw_connection()?
.read(&mut buffer)
{
Ok(size) => {
if size == 0 {
return Ok(());
} else {
output.write_all(&buffer[..size])?;
}
}
Err(e) => {
return Err(RustADBError::IOError(e));
}
}
}
}

/// 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.
Expand Down
1 change: 1 addition & 0 deletions adb_client/src/server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod adb_emulator_device;
mod adb_server;
mod adb_server_device;
mod adb_server_device_commands;
mod device_commands;
mod server_commands;

Expand Down
44 changes: 27 additions & 17 deletions adb_client/src/transports/usb_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ struct Endpoint {
address: u8,
}

const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(2);
const DEFAULT_WRITE_TIMEOUT: Duration = Duration::from_secs(2);

/// Transport running on USB
#[derive(Debug)]
pub struct USBTransport {
Expand Down Expand Up @@ -48,8 +51,17 @@ impl USBTransport {
Ok(())
}

/// Write data to underlying connection
/// Write data to underlying connection, with default timeout
pub(crate) fn write_message(&mut self, message: ADBUsbMessage) -> Result<()> {
self.write_message_with_timeout(message, DEFAULT_WRITE_TIMEOUT)
}

/// Write data to underlying connection
pub(crate) fn write_message_with_timeout(
&mut self,
message: ADBUsbMessage,
timeout: Duration,
) -> Result<()> {
let endpoint = self.find_writable_endpoint()?;
let handle = self.get_raw_connection()?;

Expand All @@ -58,26 +70,25 @@ impl USBTransport {
}

Self::configure_endpoint(handle, &endpoint)?;
let max_timeout = Duration::from_secs(1);

// TODO: loop
let message_bytes = &message.to_bytes();
let written = handle.write_bulk(endpoint.address, message_bytes, max_timeout)?;
println!("written {written}");

println!("writing payload...");
let written = handle.write_bulk(endpoint.address, message_bytes, timeout)?;

// TODO: loop
let payload = message.into_payload();
let written = handle.write_bulk(endpoint.address, &payload, max_timeout)?;

println!("written {written}");
let written = handle.write_bulk(endpoint.address, &payload, timeout)?;

Ok(())
}

/// Read data from underlying connection
/// Read data from underlying connection with default timeout
pub(crate) fn read_message(&mut self) -> Result<ADBUsbMessage> {
self.read_message_with_timeout(DEFAULT_READ_TIMEOUT)
}

/// Read data from underlying connection with given timeout
pub(crate) fn read_message_with_timeout(&mut self, timeout: Duration) -> Result<ADBUsbMessage> {
let endpoint = self.find_readable_endpoint()?;
let handle = self.get_raw_connection()?;

Expand All @@ -86,22 +97,21 @@ impl USBTransport {
}

Self::configure_endpoint(handle, &endpoint)?;
let max_timeout = Duration::from_secs(2);

let mut data = [0; 24];
// TODO: loop
let read = handle.read_bulk(endpoint.address, &mut data, max_timeout)?;
let read = handle.read_bulk(endpoint.address, &mut data, timeout)?;

let mut message = ADBUsbMessage::try_from(data)?;

if message.data_length != 0 {
let mut msg_data = vec![0_u8; message.data_length as usize];
if message.data_length() != 0 {
let mut msg_data = vec![0_u8; message.data_length() as usize];
// TODO: loop
let read = handle.read_bulk(endpoint.address, &mut msg_data, max_timeout)?;
message.payload = msg_data;
let read = handle.read_bulk(endpoint.address, &mut msg_data, timeout)?;
message.with_payload(msg_data);
}

println!("read {read} - {message:?}");
log::trace!("read {message:?}");

Ok(message)
}
Expand Down
Loading

0 comments on commit 8d12e8b

Please sign in to comment.