1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::io::{Cursor, Read, Write};
use std::path::Path;
use image::{ImageBuffer, ImageFormat, Rgba};
use crate::models::{ADBListItemType, AdbStatResponse, RemountInfo};
use crate::{ADBStatExtendedResponse, RebootType, Result};
/// Trait representing all features available on ADB devices.
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: &dyn AsRef<str>,
stdout: Option<&mut dyn Write>,
stderr: Option<&mut dyn Write>,
) -> Result<Option<u8>>;
/// Starts an interactive shell session on the device.
/// Input data is read from reader and write to writer.
fn shell(&mut self, reader: &mut dyn Read, writer: Box<dyn Write + Send>) -> Result<()>;
/// Runs command on the device.
/// Input data is read from reader and write to writer.
fn exec(
&mut self,
command: &str,
reader: &mut dyn Read,
writer: Box<dyn Write + Send>,
) -> Result<()>;
/// Display the stat information for a remote file using STAT protocol command.
fn stat(&mut self, remote_path: &dyn AsRef<str>) -> Result<AdbStatResponse>;
/// Display the stat information for a remote file using `stat` shell command.
/// This is an extended version of `stat` that returns more detailed information.
/// Returns `Ok(None)` if the file does not exist on the device.
fn stat_extended(
&mut self,
remote_path: &dyn AsRef<str>,
) -> Result<Option<ADBStatExtendedResponse>> {
let mut stdout = Vec::new();
self.shell_command(
&format!("stat {}", remote_path.as_ref()),
Some(&mut stdout),
None,
)?;
// all parsing magic happens here...
ADBStatExtendedResponse::try_from(&stdout)
}
/// Pull the remote file pointed to by `source` and write its contents into `output`
fn pull(&mut self, source: &dyn AsRef<str>, output: &mut dyn Write) -> Result<()>;
/// Push `stream` to `path` on the device.
fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef<str>) -> Result<()>;
/// List the items in a directory on the device
fn list(&mut self, path: &dyn AsRef<str>) -> Result<Vec<ADBListItemType>>;
/// Reboot the device using given reboot type
fn reboot(&mut self, reboot_type: RebootType) -> Result<()>;
/// Remount the device partitions as read-write
fn remount(&mut self) -> Result<Vec<RemountInfo>>;
/// Restart adb daemon with root permissions
fn root(&mut self) -> Result<()>;
/// Run `activity` from `package` on device. Return the command output.
fn run_activity(
&mut self,
package: &dyn AsRef<str>,
activity: &dyn AsRef<str>,
) -> Result<Vec<u8>> {
let mut output = Vec::new();
let _status = self.shell_command(
&format!(
"am start {}/{}.{}",
package.as_ref(),
package.as_ref(),
activity.as_ref()
),
Some(&mut output),
None,
)?;
Ok(output)
}
/// Install an APK pointed to by `apk_path` on device.
fn install(&mut self, apk_path: &dyn AsRef<Path>, user: Option<&str>) -> Result<()>;
/// Uninstall the package `package` from device.
fn uninstall(&mut self, package: &dyn AsRef<str>, user: Option<&str>) -> Result<()>;
/// Enable dm-verity on the device
fn enable_verity(&mut self) -> Result<()>;
/// Disable dm-verity on the device
fn disable_verity(&mut self) -> Result<()>;
/// Inner method requesting framebuffer from an Android device
fn framebuffer_inner(&mut self) -> Result<ImageBuffer<Rgba<u8>, Vec<u8>>>;
/// Dump framebuffer of this device into given path.
///
/// Output data format is currently only `PNG`.
fn framebuffer(&mut self, path: &dyn AsRef<Path>) -> Result<()> {
// Big help from AOSP source code (<https://android.googlesource.com/platform/system/adb/+/refs/heads/main/framebuffer_service.cpp>)
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) -> Result<Vec<u8>> {
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<dyn ADBDeviceExt>
where
Self: Sized + 'static,
{
Box::new(self)
}
}