Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions adb_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use adb_client::mdns::MDNSDiscoveryService;
use adb_client::server::ADBServer;
use adb_client::server_device::ADBServerDevice;
use adb_client::tcp::ADBTcpDevice;
use adb_client::usb::{ADBDeviceInfo, ADBUSBDevice, find_all_connected_adb_devices};
use adb_client::usb::{ADBDeviceInfo, ADBUSBDevice, USBTransport, WiredUSBTransport};

#[cfg(any(target_os = "linux", target_os = "macos"))]
use adb_termios::ADBTermios;
Expand Down Expand Up @@ -153,7 +153,7 @@ fn inner_main() -> ADBCliResult<()> {
}
MainCommand::Usb(usb_command) => {
if usb_command.list_devices {
let devices = find_all_connected_adb_devices()?;
let devices = WiredUSBTransport::find_all_connected_adb_devices()?;

let mut writer = TabWriter::new(stdout()).alignment(tabwriter::Alignment::Center);
writeln!(writer, "Index\tVendor ID\tProduct ID\tDevice Description")?;
Expand Down
14 changes: 14 additions & 0 deletions adb_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rustdoc-args = ["--cfg", "docsrs"]
default = []
mdns = ["dep:mdns-sd"]
usb = ["dep:rusb"]
webusb = ["dep:webusb-web"]

[dependencies]
base64 = { version = "0.22.1" }
Expand Down Expand Up @@ -49,12 +50,25 @@ mdns-sd = { version = "0.19.1", default-features = false, features = [
"logging",
], optional = true }
#########

#########
# USB-only dependencies
rusb = { version = "0.9.4", features = ["vendored"], optional = true }
num_enum = { version = "0.7.6" }
#########

#########
# `webusb` feature-specific dependencies
# we need to enable wasm-specific dependency features
# getrandom is quite problematic here as we are internally depending on two different versions
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
getrandom_02 = { package = "getrandom", version = "0.2.17", features = ["js"] }
getrandom_03 = { package = "getrandom", version = "0.4.2", features = ["wasm_js"] }
ring = { version = "0.17.14", features = ["wasm32_unknown_unknown_js"] }
rustls-pki-types = { version = "1.14.1", features = ["web"] }
webusb-web = { version = "0.5.1", optional = true }
#########

[dev-dependencies]
anyhow = { version = "1.0.102" }
criterion = { version = "0.8.2" } # Used for benchmarks
Expand Down
13 changes: 9 additions & 4 deletions adb_client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ adb_client = "*"

## Crate features

| Feature | Description | Default? |
| :-----: | :---------------------------------------------: | :------: |
| `mdns` | Enables mDNS device discovery on local network. | No |
| `usb` | Enables interactions with USB devices. | No |
| Feature | Description | Default? |
| :------: | :---------------------------------------------: | :------: |
| `mdns` | Enables mDNS device discovery on local network. | No |
| `usb` | Enables interactions with USB devices. | No |
| `webusb` | Enables webusb support | No |

To deactivate some default features you can use the `default-features = false` option in your `Cargo.toml` file and manually specify the features you want to activate:

Expand All @@ -30,6 +31,10 @@ To deactivate some default features you can use the `default-features = false` o
adb_client = { version = "*", default-features = false, features = ["mdns", "usb"] }
```

## WASM support

TODO: RUSTFLAGS="--cfg=web_sys_unstable_apis"

## Examples

Usage examples can be found in the `examples/` directory of this repository.
Expand Down
5 changes: 3 additions & 2 deletions adb_client/src/message_devices/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// USB-related definitions
#[cfg(feature = "usb")]
#[cfg_attr(docsrs, doc(cfg(feature = "usb")))]
/// Enabled for both `usb` and `webusb` features
#[cfg(any(feature = "usb", feature = "webusb"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "usb", feature = "webusb"))))]
pub mod usb;

/// Device reachable over TCP related definition
Expand Down
10 changes: 10 additions & 0 deletions adb_client/src/message_devices/usb/adb_device_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// Represents an Android device connected via USB
#[derive(Clone, Debug)]
pub struct ADBDeviceInfo {
/// Vendor ID of the device
pub vendor_id: u16,
/// Product ID of the device
pub product_id: u16,
/// Textual description of the device
pub device_description: String,
}
98 changes: 69 additions & 29 deletions adb_client/src/message_devices/usb/adb_usb_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,65 @@ use crate::Result;
use crate::RustADBError;
use crate::message_devices::adb_message_device::ADBMessageDevice;
use crate::models::RemountInfo;
use crate::usb::ADBDeviceInfo;

#[cfg(feature = "usb")]
use crate::usb::wired::WiredUSBTransport;

#[cfg(feature = "webusb")]
use crate::usb::webusb::WebUSBTransport;

use crate::usb::usb_transport::USBTransport;
use crate::usb::utils;
use crate::utils::get_default_adb_key_path;

/// Represent a device reached and available over USB.
/// Represent a device reached and available over a USB transport.
#[derive(Debug)]
pub struct ADBUSBDevice {
inner: ADBMessageDevice<USBTransport>,
pub struct ADBUSBDevice<TRANSPORT: USBTransport> {
inner: ADBMessageDevice<TRANSPORT>,
vendor_id: u16,
product_id: u16,
}

impl ADBUSBDevice {
/// Instantiate a new [`ADBUSBDevice`]
pub fn new(vendor_id: u16, product_id: u16) -> Result<Self> {
Self::new_with_custom_private_key(vendor_id, product_id, get_default_adb_key_path()?)
impl<TRANSPORT: USBTransport> ADBUSBDevice<TRANSPORT> {
/// Returns the vendor ID of the device
#[must_use]
pub const fn vendor_id(&self) -> u16 {
self.vendor_id
}

/// Instantiate a new [`ADBUSBDevice`] using a custom private key path
pub fn new_with_custom_private_key<P: AsRef<Path>>(
vendor_id: u16,
product_id: u16,
private_key_path: P,
) -> Result<Self> {
Self::new_from_transport_inner(USBTransport::new(vendor_id, product_id)?, private_key_path)
/// Returns the product ID of the device
#[must_use]
pub const fn product_id(&self) -> u16 {
self.product_id
}

/// Find and return an USB-connected Android device with known interface class and subclass values.
///
/// Returns the first device found or None if no device is found.
/// If multiple devices are found, an error is returned.
pub fn get_single_connected_adb_device() -> Result<Option<ADBDeviceInfo>> {
let found_devices = TRANSPORT::find_all_connected_adb_devices()?;
match (found_devices.first(), found_devices.get(1)) {
(None, _) => Ok(None),
(Some(device_info), None) => {
log::debug!(
"Autodetect device {:04x}:{:04x} - {}",
device_info.vendor_id,
device_info.product_id,
device_info.device_description
);
Ok(Some(device_info.clone()))
}
(Some(device_1), Some(device_2)) => Err(RustADBError::DeviceNotFound(format!(
"Found two Android devices {:04x}:{:04x} and {:04x}:{:04x}",
device_1.vendor_id, device_1.product_id, device_2.vendor_id, device_2.product_id
))),
}
}

/// Instantiate a new [`ADBUSBDevice`] from a [`USBTransport`] and an optional private key path.
pub fn new_from_transport(
transport: USBTransport,
transport: TRANSPORT,
private_key_path: Option<PathBuf>,
) -> Result<Self> {
let private_key_path = match private_key_path {
Expand All @@ -50,29 +79,37 @@ impl ADBUSBDevice {
}

fn new_from_transport_inner<P: AsRef<Path>>(
transport: USBTransport,
transport: TRANSPORT,
private_key_path: P,
) -> Result<Self> {
let vendor_id = transport.vendor_id()?;
let product_id = transport.product_id()?;
let vendor_id = transport.vendor_id();
let product_id = transport.product_id();

Ok(Self {
inner: ADBMessageDevice::new(transport, private_key_path)?,
vendor_id,
product_id,
})
}
}

/// Returns the vendor ID of the device
#[must_use]
pub const fn vendor_id(&self) -> u16 {
self.vendor_id
#[cfg(feature = "usb")]
impl ADBUSBDevice<WiredUSBTransport> {
/// Instantiate a new [`ADBUSBDevice`]
pub fn new(vendor_id: u16, product_id: u16) -> Result<Self> {
Self::new_with_custom_private_key(vendor_id, product_id, get_default_adb_key_path()?)
}

/// Returns the product ID of the device
#[must_use]
pub const fn product_id(&self) -> u16 {
self.product_id
/// Instantiate a new [`ADBUSBDevice`] using a custom private key path
pub fn new_with_custom_private_key<P: AsRef<Path>>(
vendor_id: u16,
product_id: u16,
private_key_path: P,
) -> Result<Self> {
Self::new_from_transport_inner(
WiredUSBTransport::new(vendor_id, product_id)?,
private_key_path,
)
}

/// autodetect connected ADB devices and establish a connection with the first device found
Expand All @@ -82,7 +119,7 @@ impl ADBUSBDevice {

/// autodetect connected ADB devices and establish a connection with the first device found using a custom private key path
pub fn autodetect_with_custom_private_key(private_key_path: PathBuf) -> Result<Self> {
match utils::get_single_connected_adb_device()? {
match Self::get_single_connected_adb_device()? {
Some(device_info) => Self::new_with_custom_private_key(
device_info.vendor_id,
device_info.product_id,
Expand All @@ -95,7 +132,10 @@ impl ADBUSBDevice {
}
}

impl ADBDeviceExt for ADBUSBDevice {
#[cfg(feature = "webusb")]
impl ADBUSBDevice<WebUSBTransport> {}

impl<TRANSPORT: USBTransport> ADBDeviceExt for ADBUSBDevice<TRANSPORT> {
#[inline]
fn shell_command(
&mut self,
Expand Down
22 changes: 20 additions & 2 deletions adb_client/src/message_devices/usb/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
#![doc = include_str!("./README.md")]

mod adb_device_info;
mod adb_usb_device;
mod usb_transport;
mod utils;

#[cfg(feature = "webusb")]
#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))]
mod webusb;

#[cfg(feature = "usb")]
#[cfg_attr(docsrs, doc(cfg(feature = "usb")))]
mod wired;

pub use adb_device_info::ADBDeviceInfo;
pub use adb_usb_device::ADBUSBDevice;
pub use usb_transport::USBTransport;
pub use utils::{ADBDeviceInfo, find_all_connected_adb_devices};

#[cfg(feature = "webusb")]
#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))]
pub use webusb::WebUSBTransport;

#[cfg(feature = "usb")]
#[cfg_attr(docsrs, doc(cfg(feature = "usb")))]
pub use wired::WiredUSBTransport;
Loading
Loading