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
2 changes: 1 addition & 1 deletion .github/workflows/python-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
with:
files: |
target/wheels/pyadb_client*.whl
target/wheels/pyadb_client*.tar.gz
target/wheels/pyadb_client*.tar.gz
2 changes: 1 addition & 1 deletion .github/workflows/rust-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
python-version: "3.10"

- name: Build project
run: cargo build --release --all-features
run: cargo build --release --features rusb,mdns
6 changes: 3 additions & 3 deletions .github/workflows/rust-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4
- run: rustup component add clippy
- name: Run clippy
run: cargo clippy --all-features
run: cargo clippy --features rusb,mdns

fmt:
name: "fmt"
Expand All @@ -33,7 +33,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run doc
run: cargo doc --all-features --no-deps
run: cargo doc --features rusb,mdns --no-deps
env:
RUSTDOCFLAGS: "-D warnings"

Expand All @@ -43,4 +43,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --verbose --all-features
run: cargo test --verbose --features rusb,mdns
6 changes: 3 additions & 3 deletions .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}

- name: Build release
run: cargo build --all-features --release
run: cargo build -p adb_cli --release

- name: Rename binary
run: mv target/release/adb_cli target/release/adb_cli-linux
Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:
override: true

- name: Build release
run: cargo build --all-features --release
run: cargo build -p adb_cli --release

- name: Rename binary
run: mv target/release/adb_cli target/release/adb_cli-macos
Expand Down Expand Up @@ -98,7 +98,7 @@ jobs:
python-version: "3.10"

- name: Build release
run: cargo build --all-features --release
run: cargo build -p adb_cli --release

- name: Rename binary
run: Rename-Item -Path target/release/adb_cli.exe -NewName adb_cli-windows.exe
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ target
/.vscode
venv
/.mypy_cache
pyadb_client/pyadb_client.pyi
pyadb_client/pyadb_client.pyi
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["adb_cli", "adb_client", "pyadb_client"]
members = ["adb_cli", "adb_client", "examples/mdns", "pyadb_client"]
resolver = "2"

[workspace.package]
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ Provides a "real-world" usage example of this library.

Improved documentation available [here](./adb_cli/README.md).

## examples

Some examples are available in the `examples` directory:

- `examples/mdns`: mDNS device discovery example

## pyadb_client

Python wrapper using `adb_client` library to export classes usable directly from a Python environment.
Expand Down
2 changes: 1 addition & 1 deletion adb_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ rust-version.workspace = true
version.workspace = true

[dependencies]
adb_client = { version = "^2.1.17" }
adb_client = { version = "^2.1.17", features = ["mdns", "rusb"] }
anyhow = { version = "1.0.100" }
clap = { version = "4.5.51", features = ["derive"] }
env_logger = { version = "0.11.8" }
Expand Down
2 changes: 1 addition & 1 deletion adb_cli/src/handlers/emulator_commands.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use adb_client::ADBEmulatorDevice;
use adb_client::emulator::ADBEmulatorDevice;

use crate::models::{EmuCommand, EmulatorCommand};

Expand Down
5 changes: 4 additions & 1 deletion adb_cli/src/handlers/host_commands.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use adb_client::{ADBServer, DeviceShort, MDNSBackend, Result, WaitForDeviceState};
use adb_client::{
Result,
server::{ADBServer, DeviceShort, MDNSBackend, WaitForDeviceState},
};

use crate::models::{HostCommand, MdnsCommand, ServerCommand};

Expand Down
2 changes: 1 addition & 1 deletion adb_cli/src/handlers/local_commands.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{fs::File, io::Write};

use adb_client::ADBServerDevice;
use adb_client::server_device::ADBServerDevice;
use anyhow::{Result, anyhow};

use crate::models::LocalDeviceCommand;
Expand Down
17 changes: 10 additions & 7 deletions adb_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ mod handlers;
mod models;
mod utils;

use adb_client::{
ADBDeviceExt, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService,
};
use adb_client::ADBDeviceExt;
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::ADBRusbDevice;

#[cfg(any(target_os = "linux", target_os = "macos"))]
use adb_termios::ADBTermios;
Expand Down Expand Up @@ -63,12 +66,12 @@ fn main() -> Result<()> {
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)?,
Some(pk) => ADBRusbDevice::new_with_custom_private_key(vid, pid, pk)?,
None => ADBRusbDevice::new(vid, pid)?,
},
(None, None) => match usb_command.path_to_private_key {
Some(pk) => ADBUSBDevice::autodetect_with_custom_private_key(pk)?,
None => ADBUSBDevice::autodetect()?,
Some(pk) => ADBRusbDevice::autodetect_with_custom_private_key(pk)?,
None => ADBRusbDevice::autodetect()?,
},
_ => {
anyhow::bail!(
Expand Down
2 changes: 1 addition & 1 deletion adb_cli/src/models/host.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::net::SocketAddrV4;

use adb_client::{RustADBError, WaitForDeviceTransport};
use adb_client::{RustADBError, server::WaitForDeviceTransport};
use clap::Parser;

fn parse_wait_for_device_device_transport(
Expand Down
46 changes: 36 additions & 10 deletions adb_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,57 @@ repository.workspace = true
rust-version.workspace = true
version.workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = []
mdns = ["dep:mdns-sd"]
rusb = ["dep:rsa", "dep:rusb"]
webusb = ["dep:webusb-web", "dep:rsa"]

[dependencies]
base64 = { version = "0.22.1" }
bincode = { version = "2.0.1", features = ["serde"] }
byteorder = { version = "1.5.0" }
chrono = { version = "0.4.42", default-features = false, features = ["std"] }
image = { version = "0.25.8", default-features = false }
log = { version = "0.4.28" }
mdns-sd = { version = "0.17.0", default-features = false, features = [
"logging",
] }
num-bigint = { version = "0.8.5", package = "num-bigint-dig" }
num-bigint = { version = "0.8.4", package = "num-bigint-dig" }
num-traits = { version = "0.2.19" }
quick-protobuf = { version = "0.8.1" }
rand = { version = "0.9.2" }
rcgen = { version = "0.14.5" }
rand = { version = "0.8.5" }
rcgen = { version = "0.13.2", default-features = false, features = [
"pem",
"ring"
] }
regex = { version = "1.12.2", features = ["perf", "std", "unicode"] }
rsa = { version = "0.9.8" }
rusb = { version = "0.9.4", features = ["vendored"] }
rustls = { version = "0.23.35" }
rustls-pki-types = { version = "1.13.0" }
rustls = { version = "0.23.33", default-features = false, features = ["logging", "ring", "std", "tls12"] }
rustls-pki-types = { version = "1.12.0", features = ["web"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_repr = { version = "0.1.20" }
sha1 = { version = "0.10.6", features = ["oid"] }
thiserror = { version = "2.0.17" }

#########
# MDNS dependencies
mdns-sd = { version = "0.17.0", default-features = false, features = [
"logging",
], optional = true }
#########
#########
# USB-only dependencies
rsa = { version = "0.9.7", optional = true }
rusb = { version = "0.9.4", features = ["vendored"], optional = true }
#########
#########
# webusb dependencies
webusb-web = { version = "0.4.1", optional = true }
getrandom = { version = "0.2.16", features = ["js"], optional = true }
ring = { version = "0.17.14", features = ["wasm32_unknown_unknown_js"], optional = true }


[dev-dependencies]
anyhow = { version = "1.0.100" }
criterion = { version = "0.7.0" } # Used for benchmarks
Expand Down
103 changes: 21 additions & 82 deletions adb_client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,97 +16,36 @@ Add `adb_client` crate as a dependency by simply adding it to your `Cargo.toml`:
adb_client = "*"
```

## Benchmarks

Benchmarks run on `v2.0.6`, on a **Samsung S10 SM-G973F** device and an **Intel i7-1265U** CPU laptop

### `ADBServerDevice` push vs `adb push`

`ADBServerDevice` performs all operations by using adb server as a bridge.

|File size|Sample size|`ADBServerDevice`|`adb`|Difference|
|:-------:|:---------:|:----------:|:---:|:-----:|
|10 MB|100|350,79 ms|356,30 ms|<div style="color:green">-1,57 %</div>|
|500 MB|50|15,60 s|15,64 s|<div style="color:green">-0,25 %</div>|
|1 GB|20|31,09 s|31,12 s|<div style="color:green">-0,10 %</div>|

## Examples

### Get available ADB devices

```rust no_run
use adb_client::ADBServer;
use std::net::{SocketAddrV4, Ipv4Addr};

// A custom server address can be provided
let server_ip = Ipv4Addr::new(127, 0, 0, 1);
let server_port = 5037;

let mut server = ADBServer::new(SocketAddrV4::new(server_ip, server_port));
server.devices();
```

### Using ADB server as bridge
## Crate features

#### Launch a command on device
| Feature | Description | Default? |
| :-----: | :---------------------------------------------: | :------: |
| `mdns` | Enables mDNS device discovery on local network. | No |
| `rusb` | Enables interactions with USB devices. | No |

```rust no_run
use adb_client::{ADBServer, ADBDeviceExt};
To deactivate some features you can use the `default-features = false` option in your `Cargo.toml` file and manually specify the features you want to activate:

let mut server = ADBServer::default();
let mut device = server.get_device().expect("cannot get device");
device.shell_command(&["df", "-h"], &mut std::io::stdout());
```

#### Push a file to the device

```rust no_run
use adb_client::ADBServer;
use std::net::Ipv4Addr;
use std::fs::File;
use std::path::Path;

let mut server = ADBServer::default();
let mut device = server.get_device().expect("cannot get device");
let mut input = File::open(Path::new("/tmp/f")).expect("Cannot open file");
device.push(&mut input, "/data/local/tmp");
```toml
[dependencies]
adb_client = { version = "*" }
```

### Interact directly with end devices

#### (USB) Launch a command on device

```rust no_run
use adb_client::{ADBUSBDevice, ADBDeviceExt};
## Examples

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"], &mut std::io::stdout());
```
Usage examples can be found in the `examples/` directory of this repository.

#### (USB) Push a file to the device
Some example are also provided in the various `README.md` files of modules.

```rust no_run
use adb_client::{ADBUSBDevice, ADBDeviceExt};
use std::fs::File;
use std::path::Path;
## Benchmarks

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");
```
Benchmarks run on `v2.0.6`, on a **Samsung S10 SM-G973F** device and an **Intel i7-1265U** CPU laptop

#### (TCP) Get a shell from device
### `ADBServerDevice` push vs `adb push`

```rust no_run
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
use adb_client::{ADBTcpDevice, ADBDeviceExt};
`ADBServerDevice` performs all operations by using adb server as a bridge.

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(&mut std::io::stdin(), Box::new(std::io::stdout()));
```
| File size | Sample size | `ADBServerDevice` | `adb` | Difference |
| :-------: | :---------: | :---------------: | :-------: | :------------------------------------: |
| 10 MB | 100 | 350,79 ms | 356,30 ms | <div style="color:green">-1,57 %</div> |
| 500 MB | 50 | 15,60 s | 15,64 s | <div style="color:green">-0,25 %</div> |
| 1 GB | 20 | 31,09 s | 31,12 s | <div style="color:green">-0,10 %</div> |
5 changes: 4 additions & 1 deletion adb_client/src/adb_device_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ 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`]
/// Trait representing all features available on an ADB device, currently used by:
/// - [`crate::server_device::ADBServerDevice`]
/// - [`crate::usb::ADBRusbDevice`]
/// - [`crate::tcp::ADBTcpDevice`]
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: &[&str], output: &mut dyn Write) -> Result<()>;
Expand Down
1 change: 0 additions & 1 deletion adb_client/src/constants.rs

This file was deleted.

Loading
Loading