1use crate::connection::{
2 AdbClientConnection, AdbClientStream, AdbRequest, AdbRequestEncoder, AdbResponseDecoder,
3 AdbResponseDecoderImpl,
4};
5use crate::shell::{AdbShellProtocol, AdbShellResponseId};
6use crate::util::{AdbError, Result};
7use std::fmt::Display;
8use std::path::Path;
9use tokio::net::{TcpStream, UnixStream};
10use tokio_stream::StreamExt;
11use tokio_util::codec::{FramedRead, FramedWrite};
12
13#[derive(Debug, Clone)]
15pub enum Device {
16 Default,
18 Usb,
20 TcpIp,
22 Serial(String),
24}
25
26impl Display for Device {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 Device::Default => write!(f, "host:transport-any"),
30 Device::Usb => write!(f, "host:transport-usb"),
31 Device::TcpIp => write!(f, "host:transport-local"),
32 Device::Serial(serial) => write!(f, "host:transport:{}", serial),
33 }
34 }
35}
36
37pub trait ToDevice {
39 fn to_device(&self) -> Device;
41}
42
43impl Into<AdbRequest> for Device {
44 fn into(self) -> AdbRequest {
45 AdbRequest::new(&self.to_string())
46 }
47}
48
49impl ToDevice for Device {
50 fn to_device(&self) -> Device {
51 self.clone()
52 }
53}
54
55impl ToDevice for &str {
56 fn to_device(&self) -> Device {
57 Device::Serial(self.to_string())
58 }
59}
60
61impl ToDevice for &String {
62 fn to_device(&self) -> Device {
63 Device::Serial(self.to_string())
64 }
65}
66
67#[derive(Debug, Clone)]
69pub enum AdbClientSocketUrl {
70 UNIX(String),
72 TCP(String),
74}
75
76impl AdbClientSocketUrl {
77 pub async fn connect(self) -> Result<AdbClient> {
79 let socket = match self {
80 AdbClientSocketUrl::UNIX(path) => AdbClientStream::Unix(UnixStream::connect(path).await?),
81 AdbClientSocketUrl::TCP(address) => AdbClientStream::Tcp(TcpStream::connect(address).await?),
82 };
83
84 Ok(AdbClient::new(socket))
85 }
86}
87
88#[derive(Debug)]
102pub struct AdbClient {
103 connection: AdbClientConnection,
104}
105
106impl AdbClient {
107 pub fn new(stream: AdbClientStream) -> Self {
109 Self {
110 connection: AdbClientConnection::new(stream),
111 }
112 }
113
114 pub async fn get_host_version(&mut self) -> Result<String> {
116 self.connection
117 .send(AdbRequest::new("host:version"))
118 .await?;
119
120 self.connection.next().await
121 }
122
123 pub async fn get_device_list(&mut self) -> Result<Vec<DeviceListItem>> {
125 self.connection
126 .send(AdbRequest::new("host:devices"))
127 .await?;
128 let devices = self.connection.next().await?;
129
130 let devices = devices
131 .trim()
132 .split('\n')
133 .filter_map(|line| {
134 let mut split = line.split("\t");
135 let id = match split.next() {
136 Some(id) => id,
137 None => return None,
138 };
139 let device_type = match split.next() {
140 Some(id) => id,
141 None => return None,
142 };
143
144 Some(DeviceListItem {
145 id: id.into(),
146 device_type: device_type.into(),
147 })
148 })
149 .collect();
150
151 Ok(devices)
152 }
153
154 pub async fn tcpip(mut self, device: impl ToDevice, port: u16) -> Result<String> {
156 self.connection.send(device.to_device().into()).await?;
157 self.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
158 self.connection.next().await?;
159
160 let request = AdbRequest::new(&format!("tcpip:{}", port));
161 self.connection.send(request).await?;
162 self.connection.reader.decoder_mut().decoder_impl =
163 AdbResponseDecoderImpl::StatusPayloadNewline;
164 let message = self.connection.next().await?;
165 Ok(message)
166 }
167
168 pub async fn connect_to_device(
170 mut self,
171 device: impl ToDevice,
172 remote: Remote,
173 ) -> Result<AdbClientStream> {
174 self.connection.send(device.to_device().into()).await?;
175 self.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
176 self.connection.next().await?;
177
178 let request = AdbRequest::new(remote.to_string().as_str());
179 self.connection.send(request).await?;
180 self.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
181 self.connection.next().await?;
182
183 let reader = self.connection.reader.into_inner();
184 let writer = self.connection.writer.into_inner();
185
186 Ok(reader.reunite(writer)?)
187 }
188
189 pub async fn connect_device_to_server(&mut self, connection_string: &str) -> Result<()> {
191 let request = AdbRequest::new(&format!("host:connect:{}", connection_string));
192 self.connection.send(request).await?;
193
194 let response = self.connection.next().await?;
195 if response.starts_with("already connected to") || response.starts_with("connected to") {
196 Ok(())
197 } else {
198 Err(AdbError::FailedResponseStatus(response))
199 }
200 }
201
202 pub async fn forward_server(
204 &mut self,
205 device: impl ToDevice,
206 local: &str,
207 remote: &str,
208 ) -> Result<()> {
209 self.connection.send(device.to_device().into()).await?;
210 self.connection.next().await?;
211
212 let request = AdbRequest::new(&format!("forward:tcp:{};{}", local, remote));
213 self.connection.send(request).await?;
214 self.connection.next().await?;
215
216 return Ok(());
217 }
218
219 pub async fn shell(mut self, device: impl ToDevice, command: &str) -> Result<String> {
221 self.connection.send(device.to_device().into()).await?;
222 self.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
223 self.connection.next().await?;
224
225 let request = AdbRequest::new(&format!("shell,v2,TERM=xterm-256color,raw:{}", command));
226 self.connection.send(request).await?;
227 self.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
228 self.connection.next().await?;
229
230 let reader = self.connection.reader.into_inner();
231 let mut reader = FramedRead::new(reader, AdbShellProtocol::new());
232
233 let mut response = Vec::<u8>::new();
234 loop {
235 let packet = match reader.next().await {
236 Some(Ok(package)) => package,
237 Some(Err(e)) => return Err(e.into()),
238 None => return Err(AdbError::FailedResponseStatus("No response".into())),
239 };
240
241 match packet.id {
242 AdbShellResponseId::Stderr => {
243 print!("{}", std::str::from_utf8(&packet.payload)?);
244 response.extend_from_slice(&packet.payload);
245 }
246 AdbShellResponseId::Stdout => {
247 print!("{}", std::str::from_utf8(&packet.payload)?);
248 response.extend_from_slice(&packet.payload);
249 }
250 AdbShellResponseId::Exit => {
251 break;
252 }
253 _ => {}
254 }
255 }
256
257 let real_response = std::str::from_utf8(&response)?;
258 Ok(real_response.into())
259 }
260}
261
262#[derive(Debug)]
264pub enum Remote {
265 Tcp(u16),
267 Unix(String),
269 LocalAbstract(String),
271 Jwp(u16),
273}
274
275impl Display for Remote {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 match self {
278 Remote::Tcp(port) => write!(f, "tcp:{}", port),
279 Remote::LocalAbstract(name) => write!(f, "localabstract:{}", name),
280 Remote::Unix(path) => write!(f, "local:{}", path),
281 Remote::Jwp(pid) => write!(f, "jdwp:{}", pid),
282 }
283 }
284}
285
286#[derive(Debug, Clone)]
288pub struct DeviceListItem {
289 pub id: String,
291 pub device_type: String,
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[tokio::test]
300 async fn test_failure() -> Result<()> {
301 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
302 adb_client
303 .connection
304 .send(AdbRequest::new("host:abcd"))
305 .await?;
306 adb_client.connection.reader.decoder_mut().decoder_impl = AdbResponseDecoderImpl::Status;
307 let response = adb_client.connection.next().await;
308
309 assert_eq!(
310 "FAILED response status: unknown host service".to_string(),
311 response.err().unwrap().to_string()
312 );
313
314 Ok(())
315 }
316
317 #[tokio::test]
318 async fn test_get_host_version_command() -> Result<()> {
319 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
320
321 let version: String = adb_client.get_host_version().await?;
322
323 assert_eq!(version, "0029");
324 Ok(())
325 }
326
327 #[tokio::test]
328 async fn test_get_devices_command() -> Result<()> {
329 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
330
331 let devices = adb_client.get_device_list().await?;
332
333 assert_eq!(devices.len(), 1);
334 Ok(())
335 }
336
337 #[ignore]
338 #[tokio::test]
339 async fn test_tcpip_command() -> Result<()> {
340 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
341 let response: String = adb_client.tcpip("08261JECB10524", 5555).await?;
342
343 assert_eq!(response, "restarting in TCP mode port: 5555");
344 Ok(())
345 }
346
347 #[tokio::test]
348 async fn test_get_prop_command() -> Result<()> {
349 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
350 let manufaturer: String = adb_client
351 .shell("08261JECB10524", "getprop ro.product.manufacturer")
352 .await?;
353
354 let mut adb_client = AdbClientSocketUrl::TCP("127.0.0.1:5037".to_owned()).connect().await?;
355 let model: String = adb_client
356 .shell("08261JECB10524", "getprop ro.product.model")
357 .await?;
358
359 println!("manufaturer: {:?}", &manufaturer);
360 println!("model: {:?}", &model);
361
362 Ok(())
363 }
364}