Skip to main content

android/adb/
mod.rs

1//! Client for the adb server's smart-socket protocol (design D3).
2//!
3//! The driver talks to the local adb server on port 5037 directly instead of
4//! spawning the `adb` binary, which costs 16 to 22 ms more per operation
5//! (spike S6). Each request opens its own server connection, so no state is
6//! shared between calls and a failed request never affects the next one.
7//!
8//! - [`AdbServer::devices`] keeps every connection state, including
9//!   unauthorized, offline and `no permissions`, and [`AdbServer::targets`]
10//!   adds what the driver reports about each target.
11//! - [`Device::shell`] uses shell protocol v2, which keeps the exit status and a
12//!   separate stderr.
13//! - [`Device::push`] sends sync `SEND` in 64 KiB chunks, each header written
14//!   together with its data.
15//! - [`Device::forward`] and [`Device::reverse`] read through the second status,
16//!   so a refusal by the server or by adbd surfaces as [`Error::Fail`].
17//! - [`Device::open_service`] opens a device service such as
18//!   `localabstract:<name>` without installing a rule; a missing listener fails
19//!   the open with `closed`. This is how the driver reaches the agent.
20//!
21//! The client is blocking. Every connection has a connect deadline and read and
22//! write deadlines (10 s by default), and each call takes a few milliseconds, so
23//! async callers run it on a blocking thread.
24
25mod devices;
26mod error;
27mod wire;
28
29use std::fs::File;
30use std::io::{self, ErrorKind, Read, Write};
31use std::net::{Ipv4Addr, SocketAddr, TcpStream};
32use std::path::Path;
33use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
34
35use wire::{SYNC_MAX_PATH, Status, shell_id};
36
37pub use devices::{DeviceEntry, PROP_QUERY, State, Target, parse_devices};
38pub use error::Error;
39pub use wire::{Rule, SYNC_MAX_CHUNK, ShellOutput, ShellPacket};
40
41/// Result of an adb request.
42pub type Result<T> = std::result::Result<T, Error>;
43
44/// Port of the adb server when [`SERVER_PORT_VAR`] is unset.
45pub const DEFAULT_SERVER_PORT: u16 = 5037;
46
47/// Environment variable naming the adb server's port, as the `adb` binary reads it.
48pub const SERVER_PORT_VAR: &str = "ANDROID_ADB_SERVER_PORT";
49
50/// Deadline for connecting to the server.
51pub const CONNECT_TIMEOUT: Duration = Duration::from_secs(2);
52
53/// Default deadline for each read and write on a server connection.
54pub const DEFAULT_IO_TIMEOUT: Duration = Duration::from_secs(10);
55
56/// The port in a [`SERVER_PORT_VAR`] value; the default port when the value is
57/// absent, empty or not a port number.
58pub fn server_port(value: Option<&str>) -> u16 {
59    value
60        .and_then(|v| v.trim().parse().ok())
61        .unwrap_or(DEFAULT_SERVER_PORT)
62}
63
64/// Wraps an I/O error met while serving `request`.
65fn io_error(request: &str) -> impl FnOnce(io::Error) -> Error + '_ {
66    move |source| Error::Io {
67        request: request.to_owned(),
68        source,
69    }
70}
71
72/// The encoded form of `service`, refused when it is too long to send.
73fn encoded(service: &str) -> Result<Vec<u8>> {
74    wire::encode_request(service).ok_or_else(|| Error::Invalid {
75        request: service.chars().take(80).collect(),
76        detail: format!(
77            "{} bytes is longer than the {}-byte limit of a request",
78            service.len(),
79            wire::MAX_REQUEST_LEN
80        ),
81    })
82}
83
84/// Sends one encoded request and reads its first status.
85fn send_request(s: &mut TcpStream, service: &str, bytes: &[u8]) -> Result<()> {
86    s.write_all(bytes).map_err(io_error(service))?;
87    expect_okay(s, service)
88}
89
90/// Reads a status and turns `FAIL` into [`Error::Fail`].
91fn expect_okay(s: &mut TcpStream, request: &str) -> Result<()> {
92    match wire::read_status(s).map_err(io_error(request))? {
93        Status::Okay => Ok(()),
94        Status::Fail(message) => Err(Error::Fail {
95            request: request.to_owned(),
96            message,
97        }),
98    }
99}
100
101/// Everything the peer sends until it closes the connection.
102fn read_rest(s: &mut TcpStream, request: &str) -> Result<Vec<u8>> {
103    let mut rest = Vec::new();
104    s.read_to_end(&mut rest).map_err(io_error(request))?;
105    Ok(rest)
106}
107
108/// The port in the hex block a server sends after binding a TCP listener, or
109/// `None` when nothing followed the statuses.
110fn bound_port(rest: &[u8], request: &str) -> Result<Option<u16>> {
111    if rest.is_empty() {
112        return Ok(None);
113    }
114    let protocol = |detail: String| Error::Protocol {
115        request: request.to_owned(),
116        detail,
117    };
118    let body = wire::read_hex_block(&mut &rest[..])
119        .map_err(|e| protocol(format!("unreadable port after the status: {e}")))?;
120    let text = String::from_utf8_lossy(&body);
121    text.trim()
122        .parse()
123        .map(Some)
124        .map_err(|_| protocol(format!("bound port {text:?} is not a port number")))
125}
126
127/// Fills `buf` from `r` unless the input ends first; returns the bytes read.
128fn read_full(r: &mut impl Read, buf: &mut [u8]) -> io::Result<usize> {
129    let mut filled = 0;
130    while filled < buf.len() {
131        match r.read(&mut buf[filled..]) {
132            Ok(0) => break,
133            Ok(n) => filled += n,
134            Err(e) if e.kind() == ErrorKind::Interrupted => {}
135            Err(e) => return Err(e),
136        }
137    }
138    Ok(filled)
139}
140
141/// Where a push reads its bytes from.
142enum Source<'a> {
143    Bytes(&'a [u8]),
144    File(&'a Path, File),
145}
146
147/// How adbd connects a shell command's standard streams.
148#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
149pub enum Stdio {
150    /// Pipes, which keep binary output intact and stderr separate. C programs
151    /// such as `getevent` then buffer their output in blocks.
152    #[default]
153    Raw,
154    /// A pseudo-terminal: programs flush every line, stderr is merged into
155    /// stdout and line ends arrive as `\r\n`.
156    Pty,
157}
158
159/// An adb server, reached over TCP on the loopback interface.
160#[derive(Debug, Clone)]
161pub struct AdbServer {
162    addr: SocketAddr,
163    io_timeout: Duration,
164}
165
166impl AdbServer {
167    pub fn new(addr: SocketAddr) -> Self {
168        Self {
169            addr,
170            io_timeout: DEFAULT_IO_TIMEOUT,
171        }
172    }
173
174    /// The server on 127.0.0.1 at the port [`SERVER_PORT_VAR`] names, else 5037.
175    pub fn from_env() -> Self {
176        let port = server_port(std::env::var(SERVER_PORT_VAR).ok().as_deref());
177        Self::new(SocketAddr::from((Ipv4Addr::LOCALHOST, port)))
178    }
179
180    /// Sets the deadline for each read and write on a server connection.
181    pub fn with_io_timeout(mut self, timeout: Duration) -> Self {
182        self.io_timeout = timeout;
183        self
184    }
185
186    pub fn addr(&self) -> SocketAddr {
187        self.addr
188    }
189
190    /// Every target the server knows, in every state (`host:devices-l`).
191    pub fn devices(&self) -> Result<Vec<DeviceEntry>> {
192        let request = "host:devices-l";
193        let mut s = self.request(request)?;
194        let listing = wire::read_hex_block(&mut s).map_err(io_error(request))?;
195        Ok(parse_devices(&String::from_utf8_lossy(&listing)))
196    }
197
198    /// [`Self::devices`] with each online target's API level, model and emulator
199    /// flag read through one shell command. A target whose properties cannot be
200    /// read is still listed, without them.
201    pub fn targets(&self) -> Result<Vec<Target>> {
202        Ok(self
203            .devices()?
204            .into_iter()
205            .map(|entry| {
206                let props = (entry.state == State::Device)
207                    .then(|| self.device(&entry.serial).shell(PROP_QUERY).ok())
208                    .flatten()
209                    .filter(ShellOutput::success)
210                    .map(|out| out.stdout_text());
211                Target::new(entry, props.as_deref())
212            })
213            .collect())
214    }
215
216    /// A new connection with this server's deadlines.
217    fn connect(&self) -> Result<TcpStream> {
218        let s = TcpStream::connect_timeout(&self.addr, CONNECT_TIMEOUT).map_err(|source| {
219            Error::ServerUnavailable {
220                addr: self.addr,
221                source,
222            }
223        })?;
224        let request = "connect";
225        s.set_nodelay(true).map_err(io_error(request))?;
226        s.set_read_timeout(Some(self.io_timeout))
227            .map_err(io_error(request))?;
228        s.set_write_timeout(Some(self.io_timeout))
229            .map_err(io_error(request))?;
230        Ok(s)
231    }
232
233    /// A new connection that has sent `service` and read an `OKAY` for it.
234    fn request(&self, service: &str) -> Result<TcpStream> {
235        let bytes = encoded(service)?;
236        let mut s = self.connect()?;
237        send_request(&mut s, service, &bytes)?;
238        Ok(s)
239    }
240
241    /// The device with this serial; nothing is sent until a request is made.
242    pub fn device(&self, serial: &str) -> Device {
243        Device {
244            server: self.clone(),
245            serial: serial.to_owned(),
246        }
247    }
248}
249
250/// One device on an [`AdbServer`], named by its serial.
251#[derive(Debug, Clone)]
252pub struct Device {
253    server: AdbServer,
254    serial: String,
255}
256
257impl Device {
258    pub fn serial(&self) -> &str {
259        &self.serial
260    }
261
262    /// Runs `command` with shell protocol v2 and collects its output. Standard
263    /// input is closed at once, so a command that reads it sees end of file.
264    pub fn shell(&self, command: &str) -> Result<ShellOutput> {
265        let mut stream = self.shell_stream(command)?;
266        // A command that already exited may have closed the stream; its output
267        // is still readable, so a failed close is not an error.
268        let _ = stream.close_stdin();
269        stream.finish()
270    }
271
272    /// Runs `command` as [`Self::shell`] does, bounded by `deadline` rather
273    /// than by the server's timeout for each read: the output is read with
274    /// the time left to `deadline`, so that a command that prints nothing
275    /// for longer than that timeout, as `am start -W` while it waits for the
276    /// app's first frame, completes within it (design D1 of
277    /// android-pass-fixes). A command that has not ended by `deadline`, or a
278    /// deadline already past, which runs nothing, fails with a timeout
279    /// ([`Error::is_timeout`]) whose message names the deadline; opening the
280    /// stream keeps the server's timeout.
281    pub fn shell_until(&self, command: &str, deadline: Instant) -> Result<ShellOutput> {
282        let begun = Instant::now();
283        let request = format!("shell,v2,raw:{command}");
284        let past = |request: String| Error::Io {
285            request,
286            source: io::Error::new(
287                ErrorKind::TimedOut,
288                format!(
289                    "the command had not ended by its deadline, {} ms after it began",
290                    deadline.saturating_duration_since(begun).as_millis()
291                ),
292            ),
293        };
294        if deadline <= begun {
295            return Err(past(request));
296        }
297        let mut stream = self.shell_stream(command)?;
298        // A command that already exited may have closed the stream; its output
299        // is still readable, so a failed close is not an error.
300        let _ = stream.close_stdin();
301        let mut output = ShellOutput::default();
302        loop {
303            let left = deadline.saturating_duration_since(Instant::now());
304            if left.is_zero() {
305                return Err(past(request));
306            }
307            stream.set_read_timeout(Some(left))?;
308            match stream.read_packet() {
309                Ok(Some(ShellPacket::Stdout(data))) => output.stdout.extend_from_slice(&data),
310                Ok(Some(ShellPacket::Stderr(data))) => output.stderr.extend_from_slice(&data),
311                Ok(Some(ShellPacket::Exit(status))) => {
312                    output.exit = Some(status);
313                    return Ok(output);
314                }
315                Ok(None) => return Ok(output),
316                // The read waited for all the time left, perhaps within a
317                // packet, so the stream is read no further.
318                Err(error) if error.is_timeout() => return Err(past(request)),
319                Err(error) => return Err(error),
320            }
321        }
322    }
323
324    /// Starts `command` with shell protocol v2 and hands back the stream, for
325    /// output that must be read as it arrives. Closing the stream makes adbd
326    /// send SIGHUP to the command.
327    pub fn shell_stream(&self, command: &str) -> Result<ShellStream> {
328        self.shell_stream_with(command, Stdio::Raw)
329    }
330
331    /// [`Self::shell_stream`] with the command's streams connected as `stdio`
332    /// says.
333    pub fn shell_stream_with(&self, command: &str, stdio: Stdio) -> Result<ShellStream> {
334        let streams = match stdio {
335            Stdio::Raw => "raw",
336            Stdio::Pty => "pty",
337        };
338        let request = format!("shell,v2,{streams}:{command}");
339        let stream = self.service(&request)?;
340        Ok(ShellStream { stream, request })
341    }
342
343    /// Copies the local file at `local` to `remote` with permission bits `mode`.
344    ///
345    /// adbd copies the owner's bits to group and other, so 0o644 arrives as
346    /// 0666 and 0o755 as 0777; restrict the file afterwards if that matters.
347    pub fn push(&self, local: &Path, remote: &str, mode: u32) -> Result<()> {
348        let file = File::open(local).map_err(|source| Error::Local {
349            path: local.to_owned(),
350            source,
351        })?;
352        self.send(Source::File(local, file), remote, mode)
353    }
354
355    /// Writes `data` to `remote` with permission bits `mode`, which adbd widens
356    /// as [`Self::push`] describes.
357    pub fn push_bytes(&self, data: &[u8], remote: &str, mode: u32) -> Result<()> {
358        self.send(Source::Bytes(data), remote, mode)
359    }
360
361    /// Sync `SEND`: the header goes out with the first chunk, each later
362    /// `DATA` header with its chunk, then `DONE` and adbd's status.
363    fn send(&self, source: Source<'_>, remote: &str, mode: u32) -> Result<()> {
364        let request = format!("push {remote}");
365        if remote.len() > SYNC_MAX_PATH {
366            return Err(Error::Invalid {
367                request,
368                detail: format!("remote paths are at most {SYNC_MAX_PATH} bytes"),
369            });
370        }
371        let mut s = self.service("sync:")?;
372        let mut buf = wire::sync_request(b"SEND", wire::send_arg(remote, mode).as_bytes());
373        let mut send_chunk = |buf: &mut Vec<u8>, chunk: &[u8]| {
374            wire::push_data_chunk(buf, chunk);
375            let sent = write_or_sync_fail(&mut s, buf, &request);
376            buf.clear();
377            sent
378        };
379        match source {
380            Source::Bytes(data) => {
381                for chunk in data.chunks(wire::SYNC_MAX_CHUNK) {
382                    send_chunk(&mut buf, chunk)?;
383                }
384            }
385            Source::File(path, mut file) => {
386                let mut chunk = vec![0; wire::SYNC_MAX_CHUNK];
387                loop {
388                    let n = read_full(&mut file, &mut chunk).map_err(|source| Error::Local {
389                        path: path.to_owned(),
390                        source,
391                    })?;
392                    if n == 0 {
393                        break;
394                    }
395                    send_chunk(&mut buf, &chunk[..n])?;
396                }
397            }
398        }
399        let mtime = SystemTime::now()
400            .duration_since(UNIX_EPOCH)
401            .map_or(0, |d| d.as_secs() as u32);
402        wire::push_done(&mut buf, mtime);
403        write_or_sync_fail(&mut s, &buf, &request)?;
404        match wire::read_sync_status(&mut s).map_err(io_error(&request))? {
405            Ok(()) => {
406                // The transfer is complete; a failed goodbye changes nothing.
407                let _ = s.write_all(b"QUIT\0\0\0\0");
408                Ok(())
409            }
410            Err(message) => Err(Error::Fail { request, message }),
411        }
412    }
413
414    /// Installs `adb forward <host> <device>`. Returns the host port when the
415    /// host side is a TCP socket; `tcp:0` lets the server pick a free one.
416    pub fn forward(&self, host: &str, device: &str) -> Result<Option<u16>> {
417        let request = self.host_request(&format!("forward:{host};{device}"));
418        let mut s = self.server.request(&request)?;
419        expect_okay(&mut s, &request)?;
420        // After binding a TCP listener the server sends its port.
421        let rest = read_rest(&mut s, &request)?;
422        bound_port(&rest, &request)
423    }
424
425    /// Forwards a free host TCP port, chosen by the server, to `device`.
426    pub fn forward_tcp(&self, device: &str) -> Result<u16> {
427        let request = self.host_request(&format!("forward:tcp:0;{device}"));
428        self.forward("tcp:0", device)?
429            .ok_or_else(|| Error::Protocol {
430                request,
431                detail: "the server bound no TCP port".into(),
432            })
433    }
434
435    /// Removes the forward rule whose host side is `host`.
436    pub fn remove_forward(&self, host: &str) -> Result<()> {
437        let request = self.host_request(&format!("killforward:{host}"));
438        let mut s = self.server.request(&request)?;
439        expect_okay(&mut s, &request)
440    }
441
442    /// This device's forward rules.
443    pub fn forwards(&self) -> Result<Vec<Rule>> {
444        let request = self.host_request("list-forward");
445        let mut s = self.server.request(&request)?;
446        let listing = wire::read_hex_block(&mut s).map_err(io_error(&request))?;
447        Ok(wire::parse_forward_listing(
448            &String::from_utf8_lossy(&listing),
449            &self.serial,
450        ))
451    }
452
453    /// Installs `adb reverse <device> <host>`: adbd listens on `device` and
454    /// relays each connection to `host`.
455    ///
456    /// Remove a reverse rule only after the connections through it have closed
457    /// and nothing on the device will dial it again: when a device-side
458    /// connection arrives for a rule the server has already dropped, the adb
459    /// server aborts (spike S6).
460    pub fn reverse(&self, device: &str, host: &str) -> Result<()> {
461        self.adbd_request(&format!("reverse:forward:{device};{host}"))
462    }
463
464    /// Removes the reverse rule whose device side is `device`.
465    pub fn remove_reverse(&self, device: &str) -> Result<()> {
466        self.adbd_request(&format!("reverse:killforward:{device}"))
467    }
468
469    /// adbd's reverse rules on this device.
470    pub fn reverses(&self) -> Result<Vec<Rule>> {
471        let request = "reverse:list-forward";
472        // adbd answers with the listing alone, without a status of its own.
473        let mut s = self.service(request)?;
474        let listing = wire::read_hex_block(&mut s).map_err(io_error(request))?;
475        Ok(wire::parse_reverse_listing(&String::from_utf8_lossy(
476            &listing,
477        )))
478    }
479
480    /// Opens a device service such as `localabstract:<name>` or `tcp:<port>` as
481    /// a byte stream, with no forward rule. A service nothing listens on fails
482    /// with [`Error::Fail`] and the message `closed`. The stream is returned
483    /// without read or write deadlines; the caller sets its own.
484    pub fn open_service(&self, service: &str) -> Result<TcpStream> {
485        let s = self.service(service)?;
486        s.set_read_timeout(None).map_err(io_error(service))?;
487        s.set_write_timeout(None).map_err(io_error(service))?;
488        Ok(s)
489    }
490
491    /// [`Self::open_service`] for the abstract Unix socket `name`.
492    pub fn open_abstract(&self, name: &str) -> Result<TcpStream> {
493        self.open_service(&format!("localabstract:{name}"))
494    }
495
496    /// A host request scoped to this serial, such as `forward:...`.
497    fn host_request(&self, request: &str) -> String {
498        format!("host-serial:{}:{request}", self.serial)
499    }
500
501    /// A connection switched to this device's transport that has opened
502    /// `service`, keeping the server's deadlines. Both requests are encoded
503    /// before connecting, so an oversized one never reaches the server.
504    fn service(&self, service: &str) -> Result<TcpStream> {
505        let transport = format!("host:transport:{}", self.serial);
506        let switch = encoded(&transport)?;
507        let open = encoded(service)?;
508        let mut s = self.server.connect()?;
509        send_request(&mut s, &transport, &switch)?;
510        send_request(&mut s, service, &open)?;
511        Ok(s)
512    }
513
514    /// A request adbd answers with a status of its own after the server's
515    /// `OKAY`, such as `reverse:forward:...`.
516    fn adbd_request(&self, request: &str) -> Result<()> {
517        let mut s = self.service(request)?;
518        expect_okay(&mut s, request)
519    }
520}
521
522/// Writes `bytes` of a sync transfer. adbd reports a file it cannot create with
523/// `FAIL` and closes the connection, so a failed write returns that message
524/// when it can be read.
525fn write_or_sync_fail(s: &mut TcpStream, bytes: &[u8], request: &str) -> Result<()> {
526    let Err(write_error) = s.write_all(bytes) else {
527        return Ok(());
528    };
529    match wire::read_sync_status(s) {
530        Ok(Err(message)) => Err(Error::Fail {
531            request: request.to_owned(),
532            message,
533        }),
534        _ => Err(io_error(request)(write_error)),
535    }
536}
537
538/// A running shell v2 command whose packets are read as they arrive.
539#[derive(Debug)]
540pub struct ShellStream {
541    stream: TcpStream,
542    request: String,
543}
544
545impl ShellStream {
546    /// The next packet, or `None` once the command has ended and the stream closed.
547    pub fn read_packet(&mut self) -> Result<Option<ShellPacket>> {
548        wire::read_shell_packet(&mut self.stream).map_err(io_error(&self.request))
549    }
550
551    /// Writes `data` to the command's standard input.
552    pub fn write_stdin(&mut self, data: &[u8]) -> Result<()> {
553        self.stream
554            .write_all(&wire::shell_packet(shell_id::STDIN, data))
555            .map_err(io_error(&self.request))
556    }
557
558    /// Closes the command's standard input.
559    pub fn close_stdin(&mut self) -> Result<()> {
560        self.stream
561            .write_all(&wire::shell_packet(shell_id::CLOSE_STDIN, b""))
562            .map_err(io_error(&self.request))
563    }
564
565    /// Replaces the deadline for each read; `None` waits indefinitely.
566    pub fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
567        self.stream
568            .set_read_timeout(timeout)
569            .map_err(io_error(&self.request))
570    }
571
572    /// Reads the remaining packets and returns everything the command wrote
573    /// from now on, with its exit status.
574    pub fn finish(mut self) -> Result<ShellOutput> {
575        wire::read_shell_output(&mut self.stream).map_err(io_error(&self.request))
576    }
577}
578
579#[cfg(test)]
580mod tests {
581    use super::wire::{shell_id, shell_packet};
582    use super::*;
583    use std::net::TcpListener;
584    use std::thread::{self, JoinHandle};
585
586    type Script = Box<dyn FnOnce(&mut TcpStream) + Send>;
587
588    /// Stands in for the adb server: serves one scripted exchange per accepted
589    /// connection, in order. A failed expectation inside a script fails the test
590    /// at [`FakeServer::finish`].
591    struct FakeServer {
592        addr: SocketAddr,
593        handle: Option<JoinHandle<()>>,
594    }
595
596    impl FakeServer {
597        fn start(scripts: Vec<Script>) -> Self {
598            let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
599            listener.set_nonblocking(true).unwrap();
600            let addr = listener.local_addr().unwrap();
601            let handle = thread::spawn(move || {
602                for (i, script) in scripts.into_iter().enumerate() {
603                    let deadline = Instant::now() + Duration::from_secs(5);
604                    let mut s = loop {
605                        match listener.accept() {
606                            Ok((s, _)) => break s,
607                            Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
608                                assert!(Instant::now() < deadline, "no connection for script {i}");
609                                thread::sleep(Duration::from_millis(2));
610                            }
611                            Err(e) => panic!("accept: {e}"),
612                        }
613                    };
614                    s.set_nonblocking(false).unwrap();
615                    s.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
616                    script(&mut s);
617                }
618            });
619            Self {
620                addr,
621                handle: Some(handle),
622            }
623        }
624
625        fn server(&self) -> AdbServer {
626            AdbServer::new(self.addr).with_io_timeout(Duration::from_secs(2))
627        }
628
629        /// Waits until every script has run.
630        fn finish(mut self) {
631            if let Err(panic) = self.handle.take().unwrap().join() {
632                std::panic::resume_unwind(panic);
633            }
634        }
635    }
636
637    /// Reads one smart-socket request and checks its service name.
638    fn expect_request(s: &mut TcpStream, want: &str) {
639        let body = wire::read_hex_block(s).unwrap();
640        assert_eq!(String::from_utf8_lossy(&body), want);
641    }
642
643    fn expect_bytes(s: &mut TcpStream, want: &[u8]) {
644        let mut got = vec![0; want.len()];
645        s.read_exact(&mut got).unwrap();
646        assert_eq!(got, want);
647    }
648
649    fn reply(s: &mut TcpStream, bytes: &[u8]) {
650        s.write_all(bytes).unwrap();
651    }
652
653    fn fail(message: &str) -> Vec<u8> {
654        format!("FAIL{:04x}{message}", message.len()).into_bytes()
655    }
656
657    fn block(body: &str) -> Vec<u8> {
658        format!("{:04x}{body}", body.len()).into_bytes()
659    }
660
661    /// Answers `host:transport:<serial>` with OKAY.
662    fn switch_to(s: &mut TcpStream, serial: &str) {
663        expect_request(s, &format!("host:transport:{serial}"));
664        reply(s, b"OKAY");
665    }
666
667    const LISTING: &str = "emulator-5554 device product:sdk_gphone64_arm64 model:sdk_gphone64_arm64 device:emu64a transport_id:1\n\
668        R58M123ABC unauthorized usb:1-1 transport_id:2\n\
669        emulator-5556 offline transport_id:3\n\
670        0123456789ABCDEF no permissions (missing udev rules? user is in the plugdev group); see [http://developer.android.com/tools/device.html] usb:1-2 transport_id:4\n";
671
672    fn serve_listing(s: &mut TcpStream) {
673        expect_request(s, "host:devices-l");
674        reply(s, b"OKAY");
675        reply(s, &block(LISTING));
676    }
677
678    #[test]
679    fn the_server_port_comes_from_the_environment_value() {
680        assert_eq!(server_port(None), DEFAULT_SERVER_PORT);
681        assert_eq!(server_port(Some("")), DEFAULT_SERVER_PORT);
682        assert_eq!(server_port(Some("5038")), 5038);
683        assert_eq!(server_port(Some(" 5039 ")), 5039);
684        assert_eq!(server_port(Some("not a port")), DEFAULT_SERVER_PORT);
685        assert_eq!(server_port(Some("70000")), DEFAULT_SERVER_PORT);
686    }
687
688    #[test]
689    fn devices_keep_every_state() {
690        let fake = FakeServer::start(vec![Box::new(serve_listing)]);
691        let entries = fake.server().devices().unwrap();
692        fake.finish();
693        let states: Vec<_> = entries.iter().map(|e| e.state.clone()).collect();
694        assert_eq!(
695            states,
696            [
697                State::Device,
698                State::Unauthorized,
699                State::Offline,
700                State::NoPermissions(
701                    "no permissions (missing udev rules? user is in the plugdev group); see [http://developer.android.com/tools/device.html]".into()
702                ),
703            ]
704        );
705    }
706
707    /// Spec scenario "Unauthorized device" (android-driver, Target discovery).
708    #[test]
709    fn an_unauthorized_device_is_listed_with_instructions() {
710        let fake = FakeServer::start(vec![
711            Box::new(serve_listing),
712            // Only the online target is asked for its properties.
713            Box::new(|s| {
714                switch_to(s, "emulator-5554");
715                expect_request(s, &format!("shell,v2,raw:{PROP_QUERY}"));
716                reply(s, b"OKAY");
717                expect_bytes(s, &shell_packet(shell_id::CLOSE_STDIN, b""));
718                reply(
719                    s,
720                    &shell_packet(shell_id::STDOUT, b"36\n1\n\nsdk_gphone64_arm64\n"),
721                );
722                reply(s, &shell_packet(shell_id::EXIT, &[0]));
723            }),
724        ]);
725        let targets = fake.server().targets().unwrap();
726        fake.finish();
727
728        let serials: Vec<_> = targets.iter().map(|t| t.serial.as_str()).collect();
729        assert_eq!(
730            serials,
731            [
732                "emulator-5554",
733                "R58M123ABC",
734                "emulator-5556",
735                "0123456789ABCDEF"
736            ]
737        );
738        let online = &targets[0];
739        assert_eq!(online.api_level, Some(36));
740        assert!(online.emulator);
741        assert_eq!(online.advice(), None);
742
743        let unauthorized = &targets[1];
744        assert_eq!(unauthorized.state, State::Unauthorized);
745        assert_eq!(unauthorized.api_level, None);
746        assert!(!unauthorized.emulator);
747        let advice = unauthorized
748            .advice()
749            .expect("advice for an unauthorized target");
750        assert!(advice.contains("Allow USB debugging"), "{advice}");
751        assert!(advice.contains("on the device"), "{advice}");
752
753        assert_eq!(targets[2].state, State::Offline);
754        assert!(targets[2].advice().is_some());
755        assert!(targets[3].advice().unwrap().contains("udev"));
756    }
757
758    #[test]
759    fn a_target_whose_properties_cannot_be_read_stays_listed() {
760        let fake = FakeServer::start(vec![
761            Box::new(|s| {
762                expect_request(s, "host:devices-l");
763                reply(s, b"OKAY");
764                reply(s, &block("emulator-5554 device transport_id:1\n"));
765            }),
766            Box::new(|s| {
767                expect_request(s, "host:transport:emulator-5554");
768                reply(s, &fail("device offline"));
769            }),
770        ]);
771        let targets = fake.server().targets().unwrap();
772        fake.finish();
773        assert_eq!(targets.len(), 1);
774        assert_eq!(targets[0].state, State::Device);
775        assert_eq!(targets[0].api_level, None);
776        assert!(targets[0].emulator);
777    }
778
779    #[test]
780    fn shell_closes_stdin_and_splits_stdout_stderr_and_exit() {
781        let fake = FakeServer::start(vec![Box::new(|s| {
782            switch_to(s, "emulator-5554");
783            expect_request(s, "shell,v2,raw:echo out; echo err >&2; exit 3");
784            reply(s, b"OKAY");
785            expect_bytes(s, &shell_packet(shell_id::CLOSE_STDIN, b""));
786            reply(s, &shell_packet(shell_id::STDOUT, b"out\n"));
787            reply(s, &shell_packet(shell_id::STDERR, b"err\n"));
788            reply(s, &shell_packet(shell_id::EXIT, &[3]));
789        })]);
790        let out = fake
791            .server()
792            .device("emulator-5554")
793            .shell("echo out; echo err >&2; exit 3")
794            .unwrap();
795        fake.finish();
796        assert_eq!(out.stdout, b"out\n");
797        assert_eq!(out.stderr, b"err\n");
798        assert_eq!(out.exit, Some(3));
799    }
800
801    /// Serves `am start -W` as adbd does for a cold launch: its `Starting:`
802    /// line at once, then nothing for `silent`, then, when `answers`, the
803    /// launch's result and its exit; writes past the client's end are
804    /// ignored.
805    fn slow_launch(silent: Duration, answers: bool) -> Script {
806        Box::new(move |s| {
807            switch_to(s, "emulator-5554");
808            expect_request(s, "shell,v2,raw:am start -W -n app/.Main");
809            reply(s, b"OKAY");
810            expect_bytes(s, &shell_packet(shell_id::CLOSE_STDIN, b""));
811            reply(
812                s,
813                &shell_packet(shell_id::STDOUT, b"Starting: Intent { cmp=app/.Main }\n"),
814            );
815            thread::sleep(silent);
816            if answers {
817                let result = b"Status: ok\nLaunchState: COLD\nTotalTime: 600\nComplete\n";
818                let _ = s.write_all(&shell_packet(shell_id::STDOUT, result));
819                let _ = s.write_all(&shell_packet(shell_id::EXIT, &[0]));
820            }
821        })
822    }
823
824    /// Design D1 of android-pass-fixes: a command that prints nothing for
825    /// longer than the server's read timeout, as `am start -W` while it
826    /// waits for the app's first frame, completes when it answers within
827    /// its own deadline.
828    #[test]
829    fn a_shell_command_silent_past_the_read_timeout_completes_within_its_deadline() {
830        let fake = FakeServer::start(vec![slow_launch(Duration::from_millis(600), true)]);
831        let device = AdbServer::new(fake.addr)
832            .with_io_timeout(Duration::from_millis(200))
833            .device("emulator-5554");
834        let out = device
835            .shell_until(
836                "am start -W -n app/.Main",
837                Instant::now() + Duration::from_secs(3),
838            )
839            .unwrap();
840        fake.finish();
841        assert!(out.stdout_text().contains("Status: ok"), "{out:?}");
842        assert_eq!(out.exit, Some(0));
843    }
844
845    /// Design D1 of android-pass-fixes: a command still silent at its
846    /// deadline fails then with a timeout that names the deadline, not with
847    /// the socket's error, which macOS gives as os error 35 for a read
848    /// timeout.
849    #[test]
850    fn a_shell_command_still_silent_at_its_deadline_fails_with_a_timeout_at_the_deadline() {
851        let fake = FakeServer::start(vec![slow_launch(Duration::from_millis(1500), false)]);
852        let device = AdbServer::new(fake.addr)
853            .with_io_timeout(Duration::from_millis(200))
854            .device("emulator-5554");
855        let started = Instant::now();
856        let err = device
857            .shell_until(
858                "am start -W -n app/.Main",
859                started + Duration::from_millis(700),
860            )
861            .unwrap_err();
862        let elapsed = started.elapsed();
863        fake.finish();
864        assert!(err.is_timeout(), "{err:?}");
865        assert!(
866            (Duration::from_millis(650)..Duration::from_millis(1200)).contains(&elapsed),
867            "failed after {elapsed:?}: {err}"
868        );
869        let message = err.to_string();
870        assert!(
871            message.contains("deadline") && !message.contains("os error"),
872            "{message}"
873        );
874    }
875
876    #[test]
877    fn a_shell_stream_hands_over_packets_as_they_arrive() {
878        let fake = FakeServer::start(vec![Box::new(|s| {
879            switch_to(s, "emulator-5554");
880            expect_request(s, "shell,v2,raw:getevent -l");
881            reply(s, b"OKAY");
882            reply(s, &shell_packet(shell_id::STDOUT, b"add device 1\n"));
883            expect_bytes(s, &shell_packet(shell_id::STDIN, b"x"));
884            reply(s, &shell_packet(shell_id::STDERR, b"late\n"));
885            reply(s, &shell_packet(shell_id::EXIT, &[0]));
886        })]);
887        let mut stream = fake
888            .server()
889            .device("emulator-5554")
890            .shell_stream("getevent -l")
891            .unwrap();
892        assert_eq!(
893            stream.read_packet().unwrap(),
894            Some(ShellPacket::Stdout(b"add device 1\n".to_vec()))
895        );
896        stream.write_stdin(b"x").unwrap();
897        let rest = stream.finish().unwrap();
898        fake.finish();
899        assert_eq!(rest.stderr, b"late\n");
900        assert_eq!(rest.exit, Some(0));
901    }
902
903    #[test]
904    fn a_pty_stream_asks_adbd_for_a_terminal() {
905        let fake = FakeServer::start(vec![Box::new(|s| {
906            switch_to(s, "emulator-5554");
907            expect_request(s, "shell,v2,pty:getevent -l");
908            reply(s, b"OKAY");
909            reply(s, &shell_packet(shell_id::EXIT, &[0]));
910        })]);
911        let stream = fake
912            .server()
913            .device("emulator-5554")
914            .shell_stream_with("getevent -l", Stdio::Pty)
915            .unwrap();
916        assert_eq!(stream.finish().unwrap().exit, Some(0));
917        fake.finish();
918    }
919
920    #[test]
921    fn push_sends_send_data_done_and_quit() {
922        let data: Vec<u8> = (0..70_000u32).map(|i| (i % 251) as u8).collect();
923        let expected = data.clone();
924        let fake = FakeServer::start(vec![Box::new(move |s| {
925            switch_to(s, "emulator-5554");
926            expect_request(s, "sync:");
927            reply(s, b"OKAY");
928            let arg = b"/data/local/tmp/agent.jar,33188";
929            expect_bytes(s, &wire::sync_request(b"SEND", arg));
930            let mut received = Vec::new();
931            for len in [SYNC_MAX_CHUNK, expected.len() - SYNC_MAX_CHUNK] {
932                let mut header = [0u8; 8];
933                s.read_exact(&mut header).unwrap();
934                assert_eq!(&header[..4], b"DATA");
935                assert_eq!(
936                    u32::from_le_bytes(header[4..].try_into().unwrap()) as usize,
937                    len
938                );
939                let mut chunk = vec![0; len];
940                s.read_exact(&mut chunk).unwrap();
941                received.extend(chunk);
942            }
943            assert_eq!(received, expected);
944            let mut done = [0u8; 8];
945            s.read_exact(&mut done).unwrap();
946            assert_eq!(&done[..4], b"DONE");
947            reply(s, b"OKAY\0\0\0\0");
948            expect_bytes(s, b"QUIT\0\0\0\0");
949        })]);
950        fake.server()
951            .device("emulator-5554")
952            .push_bytes(&data, "/data/local/tmp/agent.jar", 0o644)
953            .unwrap();
954        fake.finish();
955    }
956
957    #[test]
958    fn a_push_adbd_refuses_reports_its_message() {
959        let fake = FakeServer::start(vec![Box::new(|s| {
960            switch_to(s, "emulator-5554");
961            expect_request(s, "sync:");
962            reply(s, b"OKAY");
963            expect_bytes(s, &wire::sync_request(b"SEND", b"/system/x,33188"));
964            let mut rest = [0u8; 8 + 1 + 8];
965            s.read_exact(&mut rest).unwrap();
966            let message = "couldn't create file: Read-only file system";
967            reply(
968                s,
969                &[
970                    b"FAIL".as_slice(),
971                    &(message.len() as u32).to_le_bytes(),
972                    message.as_bytes(),
973                ]
974                .concat(),
975            );
976        })]);
977        let err = fake
978            .server()
979            .device("emulator-5554")
980            .push_bytes(b"x", "/system/x", 0o644)
981            .unwrap_err();
982        fake.finish();
983        assert_eq!(
984            err.fail_message(),
985            Some("couldn't create file: Read-only file system"),
986            "{err}"
987        );
988    }
989
990    #[test]
991    fn forward_reads_both_statuses_and_the_bound_port() {
992        let fake = FakeServer::start(vec![Box::new(|s| {
993            expect_request(
994                s,
995                "host-serial:emulator-5554:forward:tcp:0;localabstract:mobile-agent",
996            );
997            reply(s, b"OKAYOKAY");
998            reply(s, &block("40123"));
999        })]);
1000        let port = fake
1001            .server()
1002            .device("emulator-5554")
1003            .forward_tcp("localabstract:mobile-agent")
1004            .unwrap();
1005        fake.finish();
1006        assert_eq!(port, 40123);
1007    }
1008
1009    #[test]
1010    fn a_forward_without_a_tcp_host_side_has_no_port() {
1011        let fake = FakeServer::start(vec![Box::new(|s| {
1012            expect_request(
1013                s,
1014                "host-serial:emulator-5554:forward:localabstract:host-side;localabstract:agent",
1015            );
1016            reply(s, b"OKAYOKAY");
1017        })]);
1018        let port = fake
1019            .server()
1020            .device("emulator-5554")
1021            .forward("localabstract:host-side", "localabstract:agent")
1022            .unwrap();
1023        fake.finish();
1024        assert_eq!(port, None);
1025    }
1026
1027    #[test]
1028    fn a_forward_the_server_refuses_reports_its_message() {
1029        let fake = FakeServer::start(vec![Box::new(|s| {
1030            expect_request(s, "host-serial:emulator-5554:forward:tcp:1;tcp:2");
1031            reply(s, &fail("cannot bind listener: Permission denied"));
1032        })]);
1033        let err = fake
1034            .server()
1035            .device("emulator-5554")
1036            .forward("tcp:1", "tcp:2")
1037            .unwrap_err();
1038        fake.finish();
1039        assert_eq!(
1040            err.fail_message(),
1041            Some("cannot bind listener: Permission denied")
1042        );
1043    }
1044
1045    #[test]
1046    fn reverse_reads_adbds_own_status() {
1047        let fake = FakeServer::start(vec![Box::new(|s| {
1048            switch_to(s, "emulator-5554");
1049            expect_request(s, "reverse:forward:tcp:70000;tcp:1");
1050            reply(s, b"OKAY");
1051            reply(s, &fail("cannot bind listener: bad port number '70000'"));
1052        })]);
1053        let err = fake
1054            .server()
1055            .device("emulator-5554")
1056            .reverse("tcp:70000", "tcp:1")
1057            .unwrap_err();
1058        fake.finish();
1059        assert_eq!(
1060            err.fail_message(),
1061            Some("cannot bind listener: bad port number '70000'")
1062        );
1063    }
1064
1065    #[test]
1066    fn rules_are_listed_and_removed_with_serial_scoped_requests() {
1067        let fake = FakeServer::start(vec![
1068            Box::new(|s| {
1069                expect_request(s, "host-serial:emulator-5554:list-forward");
1070                reply(s, b"OKAY");
1071                reply(
1072                    s,
1073                    &block("emulator-5554 tcp:40123 localabstract:a\nemulator-5556 tcp:1 tcp:2\n"),
1074                );
1075            }),
1076            Box::new(|s| {
1077                expect_request(s, "host-serial:emulator-5554:killforward:tcp:40123");
1078                reply(s, b"OKAYOKAY");
1079            }),
1080            Box::new(|s| {
1081                switch_to(s, "emulator-5554");
1082                expect_request(s, "reverse:list-forward");
1083                reply(s, b"OKAY");
1084                reply(s, &block("host-16 localabstract:b tcp:5000\n"));
1085            }),
1086            Box::new(|s| {
1087                switch_to(s, "emulator-5554");
1088                expect_request(s, "reverse:killforward:localabstract:b");
1089                reply(s, b"OKAYOKAY");
1090            }),
1091        ]);
1092        let device = fake.server().device("emulator-5554");
1093        assert_eq!(
1094            device.forwards().unwrap(),
1095            [Rule {
1096                host: "tcp:40123".into(),
1097                device: "localabstract:a".into()
1098            }]
1099        );
1100        device.remove_forward("tcp:40123").unwrap();
1101        assert_eq!(
1102            device.reverses().unwrap(),
1103            [Rule {
1104                host: "tcp:5000".into(),
1105                device: "localabstract:b".into()
1106            }]
1107        );
1108        device.remove_reverse("localabstract:b").unwrap();
1109        fake.finish();
1110    }
1111
1112    #[test]
1113    fn a_service_stream_opens_through_the_transport() {
1114        let fake = FakeServer::start(vec![Box::new(|s| {
1115            switch_to(s, "emulator-5554");
1116            expect_request(s, "localabstract:mobile-agent");
1117            reply(s, b"OKAY");
1118            reply(s, b"hello");
1119        })]);
1120        let mut stream = fake
1121            .server()
1122            .device("emulator-5554")
1123            .open_abstract("mobile-agent")
1124            .unwrap();
1125        let mut hello = [0u8; 5];
1126        stream.read_exact(&mut hello).unwrap();
1127        fake.finish();
1128        assert_eq!(&hello, b"hello");
1129        assert_eq!(stream.read_timeout().unwrap(), None);
1130    }
1131
1132    #[test]
1133    fn a_service_stream_to_a_missing_socket_fails_with_closed() {
1134        let fake = FakeServer::start(vec![Box::new(|s| {
1135            switch_to(s, "emulator-5554");
1136            expect_request(s, "localabstract:nobody");
1137            reply(s, &fail("closed"));
1138        })]);
1139        let err = fake
1140            .server()
1141            .device("emulator-5554")
1142            .open_abstract("nobody")
1143            .unwrap_err();
1144        fake.finish();
1145        assert_eq!(err.fail_message(), Some("closed"), "{err}");
1146    }
1147
1148    #[test]
1149    fn no_server_is_an_actionable_error() {
1150        let addr = {
1151            let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
1152            listener.local_addr().unwrap()
1153        };
1154        let err = AdbServer::new(addr).devices().unwrap_err();
1155        assert!(matches!(err, Error::ServerUnavailable { .. }), "{err:?}");
1156        assert!(err.to_string().contains("adb start-server"), "{err}");
1157    }
1158
1159    #[test]
1160    fn a_silent_server_fails_at_the_io_deadline() {
1161        let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
1162        let addr = listener.local_addr().unwrap();
1163        let (done, wait) = std::sync::mpsc::channel::<()>();
1164        let holder = thread::spawn(move || {
1165            // Accepts, then holds the connection open without answering.
1166            let (s, _) = listener.accept().unwrap();
1167            let _ = wait.recv_timeout(Duration::from_secs(5));
1168            drop(s);
1169        });
1170        let started = Instant::now();
1171        let err = AdbServer::new(addr)
1172            .with_io_timeout(Duration::from_millis(200))
1173            .devices()
1174            .unwrap_err();
1175        let elapsed = started.elapsed();
1176        done.send(()).unwrap();
1177        holder.join().unwrap();
1178        assert!(err.is_timeout(), "{err:?}");
1179        assert!(elapsed < Duration::from_secs(1), "took {elapsed:?}");
1180    }
1181
1182    #[test]
1183    fn an_oversized_request_is_refused_before_connecting() {
1184        let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 9));
1185        let command = "x".repeat(wire::MAX_REQUEST_LEN);
1186        let err = AdbServer::new(addr)
1187            .device("emulator-5554")
1188            .shell(&command)
1189            .unwrap_err();
1190        assert!(matches!(err, Error::Invalid { .. }), "{err:?}");
1191    }
1192}