1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker
15*5225e6b1SAndroid Build Coastguard Worker //! This library provides APIs for receiving, processing and replying to fastboot commands. To use
16*5225e6b1SAndroid Build Coastguard Worker //! the library:
17*5225e6b1SAndroid Build Coastguard Worker //!
18*5225e6b1SAndroid Build Coastguard Worker //! 1. Provide a transport backend by implementing the `Transport` trait.
19*5225e6b1SAndroid Build Coastguard Worker //!
20*5225e6b1SAndroid Build Coastguard Worker //! ```
21*5225e6b1SAndroid Build Coastguard Worker //!
22*5225e6b1SAndroid Build Coastguard Worker //! struct FastbootTransport {}
23*5225e6b1SAndroid Build Coastguard Worker //!
24*5225e6b1SAndroid Build Coastguard Worker //! impl Transport<MyErrorType> for TestTransport {
25*5225e6b1SAndroid Build Coastguard Worker //! fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError> {
26*5225e6b1SAndroid Build Coastguard Worker //! todo!();
27*5225e6b1SAndroid Build Coastguard Worker //! }
28*5225e6b1SAndroid Build Coastguard Worker //!
29*5225e6b1SAndroid Build Coastguard Worker //! fn send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError> {
30*5225e6b1SAndroid Build Coastguard Worker //! todo!();
31*5225e6b1SAndroid Build Coastguard Worker //! }
32*5225e6b1SAndroid Build Coastguard Worker //! }
33*5225e6b1SAndroid Build Coastguard Worker //! ```
34*5225e6b1SAndroid Build Coastguard Worker //!
35*5225e6b1SAndroid Build Coastguard Worker //! 2. Provide a fastboot command backend by implementing the `FastbootImplementation` trait.
36*5225e6b1SAndroid Build Coastguard Worker //! i.e.
37*5225e6b1SAndroid Build Coastguard Worker //!
38*5225e6b1SAndroid Build Coastguard Worker //! ```
39*5225e6b1SAndroid Build Coastguard Worker //!
40*5225e6b1SAndroid Build Coastguard Worker //! struct FastbootCommand {}
41*5225e6b1SAndroid Build Coastguard Worker //!
42*5225e6b1SAndroid Build Coastguard Worker //! impl FastbootImplementation for FastbootTest {
43*5225e6b1SAndroid Build Coastguard Worker //! fn get_var(
44*5225e6b1SAndroid Build Coastguard Worker //! &mut self,
45*5225e6b1SAndroid Build Coastguard Worker //! var: &str,
46*5225e6b1SAndroid Build Coastguard Worker //! args: Split<char>,
47*5225e6b1SAndroid Build Coastguard Worker //! out: &mut [u8],
48*5225e6b1SAndroid Build Coastguard Worker //! ) -> CommandResult<usize> {
49*5225e6b1SAndroid Build Coastguard Worker //! todo!();
50*5225e6b1SAndroid Build Coastguard Worker //! }
51*5225e6b1SAndroid Build Coastguard Worker //!
52*5225e6b1SAndroid Build Coastguard Worker //! ...
53*5225e6b1SAndroid Build Coastguard Worker //! }
54*5225e6b1SAndroid Build Coastguard Worker //!```
55*5225e6b1SAndroid Build Coastguard Worker //!
56*5225e6b1SAndroid Build Coastguard Worker //! 3. Construct a `Fastboot` object with a given download buffer. Pass the transport, command
57*5225e6b1SAndroid Build Coastguard Worker //! implementation and call the `run()` method:
58*5225e6b1SAndroid Build Coastguard Worker //!
59*5225e6b1SAndroid Build Coastguard Worker //! ```
60*5225e6b1SAndroid Build Coastguard Worker //! let mut fastboot_impl: FastbootCommand = ...;
61*5225e6b1SAndroid Build Coastguard Worker //! let mut transport: TestTransport = ...;
62*5225e6b1SAndroid Build Coastguard Worker //! let download_buffer: &mut [u8] = ...;
63*5225e6b1SAndroid Build Coastguard Worker //! let mut fastboot = Fastboot::new();
64*5225e6b1SAndroid Build Coastguard Worker //! let result = run(&mut transport, &mut fastboot_impl, &[]);
65*5225e6b1SAndroid Build Coastguard Worker //! ```
66*5225e6b1SAndroid Build Coastguard Worker
67*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(test), no_std)]
68*5225e6b1SAndroid Build Coastguard Worker #![allow(async_fn_in_trait)]
69*5225e6b1SAndroid Build Coastguard Worker
70*5225e6b1SAndroid Build Coastguard Worker use core::{
71*5225e6b1SAndroid Build Coastguard Worker cmp::min,
72*5225e6b1SAndroid Build Coastguard Worker ffi::CStr,
73*5225e6b1SAndroid Build Coastguard Worker fmt::{Debug, Display, Formatter, Write},
74*5225e6b1SAndroid Build Coastguard Worker str::{from_utf8, Split},
75*5225e6b1SAndroid Build Coastguard Worker };
76*5225e6b1SAndroid Build Coastguard Worker use gbl_async::{block_on, yield_now};
77*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
78*5225e6b1SAndroid Build Coastguard Worker
79*5225e6b1SAndroid Build Coastguard Worker /// Maximum packet size that can be accepted from the host.
80*5225e6b1SAndroid Build Coastguard Worker ///
81*5225e6b1SAndroid Build Coastguard Worker /// The transport layer may have its own size limits that reduce the packet size further.
82*5225e6b1SAndroid Build Coastguard Worker pub const MAX_COMMAND_SIZE: usize = 4096;
83*5225e6b1SAndroid Build Coastguard Worker /// Maximum packet size that will be sent to the host.
84*5225e6b1SAndroid Build Coastguard Worker ///
85*5225e6b1SAndroid Build Coastguard Worker /// The `fastboot` host tool originally had a 64-byte packet size max, but this was increased
86*5225e6b1SAndroid Build Coastguard Worker /// to 256 in 2020, so any reasonably recent host binary should be able to support 256.
87*5225e6b1SAndroid Build Coastguard Worker ///
88*5225e6b1SAndroid Build Coastguard Worker /// The transport layer may have its own size limits that reduce the packet size further.
89*5225e6b1SAndroid Build Coastguard Worker pub const MAX_RESPONSE_SIZE: usize = 256;
90*5225e6b1SAndroid Build Coastguard Worker
91*5225e6b1SAndroid Build Coastguard Worker /// Trait to provide the transport layer for a fastboot implementation.
92*5225e6b1SAndroid Build Coastguard Worker ///
93*5225e6b1SAndroid Build Coastguard Worker /// Fastboot supports these transports:
94*5225e6b1SAndroid Build Coastguard Worker /// * USB
95*5225e6b1SAndroid Build Coastguard Worker /// * TCP
96*5225e6b1SAndroid Build Coastguard Worker /// * UDP
97*5225e6b1SAndroid Build Coastguard Worker pub trait Transport {
98*5225e6b1SAndroid Build Coastguard Worker /// Fetches the next fastboot packet into `out`.
99*5225e6b1SAndroid Build Coastguard Worker ///
100*5225e6b1SAndroid Build Coastguard Worker /// Returns the actual size of the packet on success.
101*5225e6b1SAndroid Build Coastguard Worker ///
102*5225e6b1SAndroid Build Coastguard Worker /// TODO(b/322540167): In the future, we may want to support using `[MaybeUninit<u8>]` as the
103*5225e6b1SAndroid Build Coastguard Worker /// download buffer to avoid expensive initialization at the beginning. This would require an
104*5225e6b1SAndroid Build Coastguard Worker /// interface where the implementation provides the buffer for us to copy instead of us.
receive_packet(&mut self, out: &mut [u8]) -> Result<usize>105*5225e6b1SAndroid Build Coastguard Worker async fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize>;
106*5225e6b1SAndroid Build Coastguard Worker
107*5225e6b1SAndroid Build Coastguard Worker /// Sends a fastboot packet.
108*5225e6b1SAndroid Build Coastguard Worker ///
109*5225e6b1SAndroid Build Coastguard Worker /// The method assumes `packet` is sent or at least copied to queue after it returns, where
110*5225e6b1SAndroid Build Coastguard Worker /// the buffer can go out of scope without affecting anything.
send_packet(&mut self, packet: &[u8]) -> Result<()>111*5225e6b1SAndroid Build Coastguard Worker async fn send_packet(&mut self, packet: &[u8]) -> Result<()>;
112*5225e6b1SAndroid Build Coastguard Worker }
113*5225e6b1SAndroid Build Coastguard Worker
114*5225e6b1SAndroid Build Coastguard Worker /// For now, we hardcode the expected version, until we need to distinguish between multiple
115*5225e6b1SAndroid Build Coastguard Worker /// versions.
116*5225e6b1SAndroid Build Coastguard Worker const TCP_HANDSHAKE_MESSAGE: &[u8] = b"FB01";
117*5225e6b1SAndroid Build Coastguard Worker
118*5225e6b1SAndroid Build Coastguard Worker /// A trait representing a TCP stream reader/writer. Fastboot over TCP has additional handshake
119*5225e6b1SAndroid Build Coastguard Worker /// process and uses a length-prefixed wire message format. It is recommended that caller
120*5225e6b1SAndroid Build Coastguard Worker /// implements this trait instead of `Transport`, and uses the API `Fastboot::run_tcp_session()`
121*5225e6b1SAndroid Build Coastguard Worker /// to perform fastboot over TCP. It internally handles handshake and wire message parsing.
122*5225e6b1SAndroid Build Coastguard Worker pub trait TcpStream {
123*5225e6b1SAndroid Build Coastguard Worker /// Reads to `out` for exactly `out.len()` number bytes from the TCP connection.
read_exact(&mut self, out: &mut [u8]) -> Result<()>124*5225e6b1SAndroid Build Coastguard Worker async fn read_exact(&mut self, out: &mut [u8]) -> Result<()>;
125*5225e6b1SAndroid Build Coastguard Worker
126*5225e6b1SAndroid Build Coastguard Worker /// Sends exactly `data.len()` number bytes from `data` to the TCP connection.
write_exact(&mut self, data: &[u8]) -> Result<()>127*5225e6b1SAndroid Build Coastguard Worker async fn write_exact(&mut self, data: &[u8]) -> Result<()>;
128*5225e6b1SAndroid Build Coastguard Worker }
129*5225e6b1SAndroid Build Coastguard Worker
130*5225e6b1SAndroid Build Coastguard Worker /// Implements [Transport] on a [TcpStream].
131*5225e6b1SAndroid Build Coastguard Worker pub struct TcpTransport<'a, T: TcpStream>(&'a mut T);
132*5225e6b1SAndroid Build Coastguard Worker
133*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: TcpStream> TcpTransport<'a, T> {
134*5225e6b1SAndroid Build Coastguard Worker /// Creates an instance from a newly connected TcpStream and performs handshake.
new_and_handshake(tcp_stream: &'a mut T) -> Result<Self>135*5225e6b1SAndroid Build Coastguard Worker pub fn new_and_handshake(tcp_stream: &'a mut T) -> Result<Self> {
136*5225e6b1SAndroid Build Coastguard Worker let mut handshake = [0u8; 4];
137*5225e6b1SAndroid Build Coastguard Worker block_on(tcp_stream.write_exact(TCP_HANDSHAKE_MESSAGE))?;
138*5225e6b1SAndroid Build Coastguard Worker block_on(tcp_stream.read_exact(&mut handshake[..]))?;
139*5225e6b1SAndroid Build Coastguard Worker match handshake == *TCP_HANDSHAKE_MESSAGE {
140*5225e6b1SAndroid Build Coastguard Worker true => Ok(Self(tcp_stream)),
141*5225e6b1SAndroid Build Coastguard Worker _ => Err(Error::InvalidHandshake),
142*5225e6b1SAndroid Build Coastguard Worker }
143*5225e6b1SAndroid Build Coastguard Worker }
144*5225e6b1SAndroid Build Coastguard Worker }
145*5225e6b1SAndroid Build Coastguard Worker
146*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: TcpStream> Transport for TcpTransport<'a, T> {
receive_packet(&mut self, out: &mut [u8]) -> Result<usize>147*5225e6b1SAndroid Build Coastguard Worker async fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize> {
148*5225e6b1SAndroid Build Coastguard Worker let mut length_prefix = [0u8; 8];
149*5225e6b1SAndroid Build Coastguard Worker self.0.read_exact(&mut length_prefix[..]).await?;
150*5225e6b1SAndroid Build Coastguard Worker let packet_size: usize = u64::from_be_bytes(length_prefix).try_into()?;
151*5225e6b1SAndroid Build Coastguard Worker match out.len() < packet_size {
152*5225e6b1SAndroid Build Coastguard Worker true => Err(Error::InvalidInput),
153*5225e6b1SAndroid Build Coastguard Worker _ => {
154*5225e6b1SAndroid Build Coastguard Worker self.0.read_exact(&mut out[..packet_size]).await?;
155*5225e6b1SAndroid Build Coastguard Worker Ok(packet_size)
156*5225e6b1SAndroid Build Coastguard Worker }
157*5225e6b1SAndroid Build Coastguard Worker }
158*5225e6b1SAndroid Build Coastguard Worker }
159*5225e6b1SAndroid Build Coastguard Worker
send_packet(&mut self, packet: &[u8]) -> Result<()>160*5225e6b1SAndroid Build Coastguard Worker async fn send_packet(&mut self, packet: &[u8]) -> Result<()> {
161*5225e6b1SAndroid Build Coastguard Worker self.0.write_exact(&mut u64::try_from(packet.len())?.to_be_bytes()[..]).await?;
162*5225e6b1SAndroid Build Coastguard Worker self.0.write_exact(packet).await
163*5225e6b1SAndroid Build Coastguard Worker }
164*5225e6b1SAndroid Build Coastguard Worker }
165*5225e6b1SAndroid Build Coastguard Worker
166*5225e6b1SAndroid Build Coastguard Worker const COMMAND_ERROR_LENGTH: usize = MAX_RESPONSE_SIZE - 4;
167*5225e6b1SAndroid Build Coastguard Worker
168*5225e6b1SAndroid Build Coastguard Worker /// `CommandError` is the return error type for methods in trait `FastbootImplementation` when
169*5225e6b1SAndroid Build Coastguard Worker /// they fail. It will be converted into string and sent as fastboot error message "FAIL<string>".
170*5225e6b1SAndroid Build Coastguard Worker ///
171*5225e6b1SAndroid Build Coastguard Worker /// Any type that implements `Display` trait can be converted into it. However, because fastboot
172*5225e6b1SAndroid Build Coastguard Worker /// response message is limited to `MAX_RESPONSE_SIZE`. If the final displayed string length
173*5225e6b1SAndroid Build Coastguard Worker /// exceeds it, the rest of the content is ignored.
174*5225e6b1SAndroid Build Coastguard Worker pub struct CommandError(FormattedBytes<[u8; COMMAND_ERROR_LENGTH]>);
175*5225e6b1SAndroid Build Coastguard Worker
176*5225e6b1SAndroid Build Coastguard Worker impl CommandError {
177*5225e6b1SAndroid Build Coastguard Worker /// Converts to string.
to_str(&self) -> &str178*5225e6b1SAndroid Build Coastguard Worker pub fn to_str(&self) -> &str {
179*5225e6b1SAndroid Build Coastguard Worker from_utf8(&self.0 .0[..self.0 .1]).unwrap_or("")
180*5225e6b1SAndroid Build Coastguard Worker }
181*5225e6b1SAndroid Build Coastguard Worker
182*5225e6b1SAndroid Build Coastguard Worker /// Clones the error.
clone(&self) -> Self183*5225e6b1SAndroid Build Coastguard Worker pub fn clone(&self) -> Self {
184*5225e6b1SAndroid Build Coastguard Worker self.to_str().into()
185*5225e6b1SAndroid Build Coastguard Worker }
186*5225e6b1SAndroid Build Coastguard Worker }
187*5225e6b1SAndroid Build Coastguard Worker
188*5225e6b1SAndroid Build Coastguard Worker impl Debug for CommandError {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result189*5225e6b1SAndroid Build Coastguard Worker fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
190*5225e6b1SAndroid Build Coastguard Worker write!(f, "{}", self.to_str())
191*5225e6b1SAndroid Build Coastguard Worker }
192*5225e6b1SAndroid Build Coastguard Worker }
193*5225e6b1SAndroid Build Coastguard Worker
194*5225e6b1SAndroid Build Coastguard Worker impl<T: Display> From<T> for CommandError {
from(val: T) -> Self195*5225e6b1SAndroid Build Coastguard Worker fn from(val: T) -> Self {
196*5225e6b1SAndroid Build Coastguard Worker let mut res = CommandError(FormattedBytes([0u8; COMMAND_ERROR_LENGTH], 0));
197*5225e6b1SAndroid Build Coastguard Worker write!(res.0, "{}", val).unwrap();
198*5225e6b1SAndroid Build Coastguard Worker res
199*5225e6b1SAndroid Build Coastguard Worker }
200*5225e6b1SAndroid Build Coastguard Worker }
201*5225e6b1SAndroid Build Coastguard Worker
202*5225e6b1SAndroid Build Coastguard Worker /// Type alias for Result that wraps a CommandError
203*5225e6b1SAndroid Build Coastguard Worker pub type CommandResult<T> = core::result::Result<T, CommandError>;
204*5225e6b1SAndroid Build Coastguard Worker
205*5225e6b1SAndroid Build Coastguard Worker /// Fastboot reboot mode
206*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, PartialEq)]
207*5225e6b1SAndroid Build Coastguard Worker pub enum RebootMode {
208*5225e6b1SAndroid Build Coastguard Worker /// "fastboot reboot". Normal reboot.
209*5225e6b1SAndroid Build Coastguard Worker Normal,
210*5225e6b1SAndroid Build Coastguard Worker /// "fastboot reboot-bootloader". Reboot to bootloader.
211*5225e6b1SAndroid Build Coastguard Worker Bootloader,
212*5225e6b1SAndroid Build Coastguard Worker /// "fastboot reboot-fastboot". Reboot to userspace fastboot.
213*5225e6b1SAndroid Build Coastguard Worker Fastboot,
214*5225e6b1SAndroid Build Coastguard Worker /// "fastboot reboot-recovery". Reboot to recovery.
215*5225e6b1SAndroid Build Coastguard Worker Recovery,
216*5225e6b1SAndroid Build Coastguard Worker }
217*5225e6b1SAndroid Build Coastguard Worker
218*5225e6b1SAndroid Build Coastguard Worker /// Implementation for Fastboot command backends.
219*5225e6b1SAndroid Build Coastguard Worker pub trait FastbootImplementation {
220*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot getvar ...`
221*5225e6b1SAndroid Build Coastguard Worker ///
222*5225e6b1SAndroid Build Coastguard Worker /// Gets the value of a variable specified by name and configuration represented by list of
223*5225e6b1SAndroid Build Coastguard Worker /// additional arguments in `args`.
224*5225e6b1SAndroid Build Coastguard Worker ///
225*5225e6b1SAndroid Build Coastguard Worker /// Variable `max-download-size`, `version` are reserved by the library.
226*5225e6b1SAndroid Build Coastguard Worker ///
227*5225e6b1SAndroid Build Coastguard Worker /// # Args
228*5225e6b1SAndroid Build Coastguard Worker ///
229*5225e6b1SAndroid Build Coastguard Worker /// * `var`: Name of the variable.
230*5225e6b1SAndroid Build Coastguard Worker /// * `args`: Additional arguments.
231*5225e6b1SAndroid Build Coastguard Worker /// * `out`: Output buffer for storing the variable value.
232*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender`.
233*5225e6b1SAndroid Build Coastguard Worker ///
234*5225e6b1SAndroid Build Coastguard Worker /// TODO(b/322540167): Figure out other reserved variables.
get_var( &mut self, var: &CStr, args: impl Iterator<Item = &'_ CStr> + Clone, out: &mut [u8], responder: impl InfoSender, ) -> CommandResult<usize>235*5225e6b1SAndroid Build Coastguard Worker async fn get_var(
236*5225e6b1SAndroid Build Coastguard Worker &mut self,
237*5225e6b1SAndroid Build Coastguard Worker var: &CStr,
238*5225e6b1SAndroid Build Coastguard Worker args: impl Iterator<Item = &'_ CStr> + Clone,
239*5225e6b1SAndroid Build Coastguard Worker out: &mut [u8],
240*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender,
241*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<usize>;
242*5225e6b1SAndroid Build Coastguard Worker
243*5225e6b1SAndroid Build Coastguard Worker /// A helper API for getting the value of a fastboot variable and decoding it into string.
get_var_as_str<'s>( &mut self, var: &CStr, args: impl Iterator<Item = &'_ CStr> + Clone, responder: impl InfoSender, out: &'s mut [u8], ) -> CommandResult<&'s str>244*5225e6b1SAndroid Build Coastguard Worker async fn get_var_as_str<'s>(
245*5225e6b1SAndroid Build Coastguard Worker &mut self,
246*5225e6b1SAndroid Build Coastguard Worker var: &CStr,
247*5225e6b1SAndroid Build Coastguard Worker args: impl Iterator<Item = &'_ CStr> + Clone,
248*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender,
249*5225e6b1SAndroid Build Coastguard Worker out: &'s mut [u8],
250*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'s str> {
251*5225e6b1SAndroid Build Coastguard Worker let size = self.get_var(var, args, out, responder).await?;
252*5225e6b1SAndroid Build Coastguard Worker Ok(from_utf8(out.get(..size).ok_or("Invalid variable size")?)
253*5225e6b1SAndroid Build Coastguard Worker .map_err(|_| "Value is not string")?)
254*5225e6b1SAndroid Build Coastguard Worker }
255*5225e6b1SAndroid Build Coastguard Worker
256*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot getvar all`.
257*5225e6b1SAndroid Build Coastguard Worker ///
258*5225e6b1SAndroid Build Coastguard Worker /// Iterates all combinations of fastboot variable, configurations and values that need to be
259*5225e6b1SAndroid Build Coastguard Worker /// included in the response to `fastboot getvar all`.
260*5225e6b1SAndroid Build Coastguard Worker ///
261*5225e6b1SAndroid Build Coastguard Worker /// # Args
262*5225e6b1SAndroid Build Coastguard Worker ///
263*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An implementation VarInfoSender. Implementation should call
264*5225e6b1SAndroid Build Coastguard Worker /// `VarInfoSender::send` for all combinations of Fastboot variable/argument/value that needs
265*5225e6b1SAndroid Build Coastguard Worker /// to be included in the response to `fastboot getvarl all`:
266*5225e6b1SAndroid Build Coastguard Worker ///
267*5225e6b1SAndroid Build Coastguard Worker /// async fn get_var_all(&mut self, f: F, resp: impl VarInfoSender)
268*5225e6b1SAndroid Build Coastguard Worker /// -> CommandResult<()> {
269*5225e6b1SAndroid Build Coastguard Worker /// resp.send("partition-size", &["boot_a"], /* size of boot_a */).await?;
270*5225e6b1SAndroid Build Coastguard Worker /// resp.send("partition-size", &["boot_b"], /* size of boot_b */).await?;
271*5225e6b1SAndroid Build Coastguard Worker /// resp.send("partition-size", &["init_boot_a"], /* size of init_boot_a */).await?;
272*5225e6b1SAndroid Build Coastguard Worker /// resp.send("partition-size", &["init_boot_b"], /* size of init_boot_b */).await?;
273*5225e6b1SAndroid Build Coastguard Worker /// Ok(())
274*5225e6b1SAndroid Build Coastguard Worker /// }
275*5225e6b1SAndroid Build Coastguard Worker ///
276*5225e6b1SAndroid Build Coastguard Worker /// will generates the following outputs for `fastboot getvar all`:
277*5225e6b1SAndroid Build Coastguard Worker ///
278*5225e6b1SAndroid Build Coastguard Worker /// ...
279*5225e6b1SAndroid Build Coastguard Worker /// (bootloader) partition-size:boot_a: <size of boot_a>
280*5225e6b1SAndroid Build Coastguard Worker /// (bootloader) partition-size:boot_b: <size of boot_b>
281*5225e6b1SAndroid Build Coastguard Worker /// (bootloader) partition-size:init_boot_a: <size of init_boot_a>
282*5225e6b1SAndroid Build Coastguard Worker /// (bootloader) partition-size:init_boot_b: <size of init_boot_b>
283*5225e6b1SAndroid Build Coastguard Worker /// ...
284*5225e6b1SAndroid Build Coastguard Worker ///
285*5225e6b1SAndroid Build Coastguard Worker /// TODO(b/322540167): This and `get_var()` contain duplicated logic. Investigate if there can
286*5225e6b1SAndroid Build Coastguard Worker /// be better solutions for doing the combination traversal.
get_var_all(&mut self, responder: impl VarInfoSender) -> CommandResult<()>287*5225e6b1SAndroid Build Coastguard Worker async fn get_var_all(&mut self, responder: impl VarInfoSender) -> CommandResult<()>;
288*5225e6b1SAndroid Build Coastguard Worker
289*5225e6b1SAndroid Build Coastguard Worker /// Backend for getting download buffer
get_download_buffer(&mut self) -> &mut [u8]290*5225e6b1SAndroid Build Coastguard Worker async fn get_download_buffer(&mut self) -> &mut [u8];
291*5225e6b1SAndroid Build Coastguard Worker
292*5225e6b1SAndroid Build Coastguard Worker /// Called when a download is completed.
download_complete( &mut self, download_size: usize, responder: impl InfoSender, ) -> CommandResult<()>293*5225e6b1SAndroid Build Coastguard Worker async fn download_complete(
294*5225e6b1SAndroid Build Coastguard Worker &mut self,
295*5225e6b1SAndroid Build Coastguard Worker download_size: usize,
296*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender,
297*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()>;
298*5225e6b1SAndroid Build Coastguard Worker
299*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot flash ...`
300*5225e6b1SAndroid Build Coastguard Worker ///
301*5225e6b1SAndroid Build Coastguard Worker /// # Args
302*5225e6b1SAndroid Build Coastguard Worker ///
303*5225e6b1SAndroid Build Coastguard Worker /// * `part`: Name of the partition.
304*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender`.
flash(&mut self, part: &str, responder: impl InfoSender) -> CommandResult<()>305*5225e6b1SAndroid Build Coastguard Worker async fn flash(&mut self, part: &str, responder: impl InfoSender) -> CommandResult<()>;
306*5225e6b1SAndroid Build Coastguard Worker
307*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot erase ...`
308*5225e6b1SAndroid Build Coastguard Worker ///
309*5225e6b1SAndroid Build Coastguard Worker /// # Args
310*5225e6b1SAndroid Build Coastguard Worker ///
311*5225e6b1SAndroid Build Coastguard Worker /// * `part`: Name of the partition.
312*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender`.
erase(&mut self, part: &str, responder: impl InfoSender) -> CommandResult<()>313*5225e6b1SAndroid Build Coastguard Worker async fn erase(&mut self, part: &str, responder: impl InfoSender) -> CommandResult<()>;
314*5225e6b1SAndroid Build Coastguard Worker
315*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot get_staged ...`
316*5225e6b1SAndroid Build Coastguard Worker ///
317*5225e6b1SAndroid Build Coastguard Worker /// # Args
318*5225e6b1SAndroid Build Coastguard Worker ///
319*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `UploadBuilder + InfoSender` for initiating and uploading
320*5225e6b1SAndroid Build Coastguard Worker /// data. For example:
321*5225e6b1SAndroid Build Coastguard Worker ///
322*5225e6b1SAndroid Build Coastguard Worker /// ```
323*5225e6b1SAndroid Build Coastguard Worker /// async fn upload(
324*5225e6b1SAndroid Build Coastguard Worker /// &mut self,
325*5225e6b1SAndroid Build Coastguard Worker /// responder: impl UploadBuilder + InfoSender,
326*5225e6b1SAndroid Build Coastguard Worker /// ) -> CommandResult<()> {
327*5225e6b1SAndroid Build Coastguard Worker /// let data = ..;
328*5225e6b1SAndroid Build Coastguard Worker /// // Sends a total of 1024 bytes data.
329*5225e6b1SAndroid Build Coastguard Worker /// responder.send_info("About to upload...").await?;
330*5225e6b1SAndroid Build Coastguard Worker /// let mut uploader = responder.initiate_upload(1024).await?;
331*5225e6b1SAndroid Build Coastguard Worker /// // Can upload in multiple batches.
332*5225e6b1SAndroid Build Coastguard Worker /// uploader.upload(&data[..512]).await?;
333*5225e6b1SAndroid Build Coastguard Worker /// uploader.upload(&data[512..]).await?;
334*5225e6b1SAndroid Build Coastguard Worker /// Ok(())
335*5225e6b1SAndroid Build Coastguard Worker /// }
336*5225e6b1SAndroid Build Coastguard Worker /// ```
337*5225e6b1SAndroid Build Coastguard Worker ///
338*5225e6b1SAndroid Build Coastguard Worker /// If implementation fails to upload enough, or attempts to upload more than expected data
339*5225e6b1SAndroid Build Coastguard Worker /// with `Uploader::upload()`, an error will be returned.
upload(&mut self, responder: impl UploadBuilder + InfoSender) -> CommandResult<()>340*5225e6b1SAndroid Build Coastguard Worker async fn upload(&mut self, responder: impl UploadBuilder + InfoSender) -> CommandResult<()>;
341*5225e6b1SAndroid Build Coastguard Worker
342*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot fetch ...`
343*5225e6b1SAndroid Build Coastguard Worker ///
344*5225e6b1SAndroid Build Coastguard Worker /// # Args
345*5225e6b1SAndroid Build Coastguard Worker ///
346*5225e6b1SAndroid Build Coastguard Worker /// * `part`: The partition name.
347*5225e6b1SAndroid Build Coastguard Worker /// * `offset`: The offset into the partition for upload.
348*5225e6b1SAndroid Build Coastguard Worker /// * `size`: The number of bytes to upload.
349*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `UploadBuilder + InfoSender` for initiating and uploading data.
fetch( &mut self, part: &str, offset: u64, size: u64, responder: impl UploadBuilder + InfoSender, ) -> CommandResult<()>350*5225e6b1SAndroid Build Coastguard Worker async fn fetch(
351*5225e6b1SAndroid Build Coastguard Worker &mut self,
352*5225e6b1SAndroid Build Coastguard Worker part: &str,
353*5225e6b1SAndroid Build Coastguard Worker offset: u64,
354*5225e6b1SAndroid Build Coastguard Worker size: u64,
355*5225e6b1SAndroid Build Coastguard Worker responder: impl UploadBuilder + InfoSender,
356*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()>;
357*5225e6b1SAndroid Build Coastguard Worker
358*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot reboot/reboot-bootloader/reboot-fastboot/reboot-recovery`
359*5225e6b1SAndroid Build Coastguard Worker ///
360*5225e6b1SAndroid Build Coastguard Worker /// # Args
361*5225e6b1SAndroid Build Coastguard Worker ///
362*5225e6b1SAndroid Build Coastguard Worker /// * `mode`: An `RebootMode` specifying the reboot mode.
363*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender + OkaySender`. Implementation should call
364*5225e6b1SAndroid Build Coastguard Worker /// `responder.send_okay("")` right before reboot to notify the remote host that the
365*5225e6b1SAndroid Build Coastguard Worker /// operation is successful.
366*5225e6b1SAndroid Build Coastguard Worker ///
367*5225e6b1SAndroid Build Coastguard Worker /// # Returns
368*5225e6b1SAndroid Build Coastguard Worker ///
369*5225e6b1SAndroid Build Coastguard Worker /// * The method is not expected to return if reboot is successful.
370*5225e6b1SAndroid Build Coastguard Worker /// * Returns `Err(e)` on error.
reboot( &mut self, mode: RebootMode, responder: impl InfoSender + OkaySender, ) -> CommandError371*5225e6b1SAndroid Build Coastguard Worker async fn reboot(
372*5225e6b1SAndroid Build Coastguard Worker &mut self,
373*5225e6b1SAndroid Build Coastguard Worker mode: RebootMode,
374*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender + OkaySender,
375*5225e6b1SAndroid Build Coastguard Worker ) -> CommandError;
376*5225e6b1SAndroid Build Coastguard Worker
377*5225e6b1SAndroid Build Coastguard Worker /// Method for handling `fastboot continue` clean up.
378*5225e6b1SAndroid Build Coastguard Worker ///
379*5225e6b1SAndroid Build Coastguard Worker /// `run()` and `run_tcp_session()` exit after receiving `fastboot continue.` The method is for
380*5225e6b1SAndroid Build Coastguard Worker /// implementation to perform necessary clean up.
381*5225e6b1SAndroid Build Coastguard Worker ///
382*5225e6b1SAndroid Build Coastguard Worker /// # Args
383*5225e6b1SAndroid Build Coastguard Worker ///
384*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender`.
385*5225e6b1SAndroid Build Coastguard Worker async fn r#continue(&mut self, responder: impl InfoSender) -> CommandResult<()>;
386*5225e6b1SAndroid Build Coastguard Worker
387*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot set_active`.
set_active(&mut self, slot: &str, responder: impl InfoSender) -> CommandResult<()>388*5225e6b1SAndroid Build Coastguard Worker async fn set_active(&mut self, slot: &str, responder: impl InfoSender) -> CommandResult<()>;
389*5225e6b1SAndroid Build Coastguard Worker
390*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot boot`
391*5225e6b1SAndroid Build Coastguard Worker ///
392*5225e6b1SAndroid Build Coastguard Worker /// # Args
393*5225e6b1SAndroid Build Coastguard Worker ///
394*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender + OkaySender`. Implementation should call
395*5225e6b1SAndroid Build Coastguard Worker /// `responder.send_okay("")` right before boot to notify the remote host that the
396*5225e6b1SAndroid Build Coastguard Worker /// operation is successful.
397*5225e6b1SAndroid Build Coastguard Worker ///
398*5225e6b1SAndroid Build Coastguard Worker /// # Returns
399*5225e6b1SAndroid Build Coastguard Worker ///
400*5225e6b1SAndroid Build Coastguard Worker /// * The method is always return OK to let fastboot continue.
401*5225e6b1SAndroid Build Coastguard Worker /// * Returns `Err(e)` on error.
boot(&mut self, responder: impl InfoSender + OkaySender) -> CommandResult<()>402*5225e6b1SAndroid Build Coastguard Worker async fn boot(&mut self, responder: impl InfoSender + OkaySender) -> CommandResult<()>;
403*5225e6b1SAndroid Build Coastguard Worker
404*5225e6b1SAndroid Build Coastguard Worker /// Backend for `fastboot oem ...`.
405*5225e6b1SAndroid Build Coastguard Worker ///
406*5225e6b1SAndroid Build Coastguard Worker /// # Args
407*5225e6b1SAndroid Build Coastguard Worker ///
408*5225e6b1SAndroid Build Coastguard Worker /// * `cmd`: The OEM command string that comes after "oem ".
409*5225e6b1SAndroid Build Coastguard Worker /// * `responder`: An instance of `InfoSender`.
410*5225e6b1SAndroid Build Coastguard Worker /// * `res`: The responder buffer. Upon success, implementation can use the buffer to
411*5225e6b1SAndroid Build Coastguard Worker /// construct a valid UTF8 string which will be sent as "OKAY<string>"
412*5225e6b1SAndroid Build Coastguard Worker ///
413*5225e6b1SAndroid Build Coastguard Worker /// # Returns
414*5225e6b1SAndroid Build Coastguard Worker ///
415*5225e6b1SAndroid Build Coastguard Worker /// On success, returns the portion of `res` used by the construction of string message.
oem<'a>( &mut self, cmd: &str, responder: impl InfoSender, res: &'a mut [u8], ) -> CommandResult<&'a [u8]>416*5225e6b1SAndroid Build Coastguard Worker async fn oem<'a>(
417*5225e6b1SAndroid Build Coastguard Worker &mut self,
418*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
419*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender,
420*5225e6b1SAndroid Build Coastguard Worker res: &'a mut [u8],
421*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'a [u8]>;
422*5225e6b1SAndroid Build Coastguard Worker
423*5225e6b1SAndroid Build Coastguard Worker // TODO(b/322540167): Add methods for other commands.
424*5225e6b1SAndroid Build Coastguard Worker }
425*5225e6b1SAndroid Build Coastguard Worker
426*5225e6b1SAndroid Build Coastguard Worker /// An internal convenient macro helper for `fastboot_okay`, `fastboot_fail` and `fastboot_info`.
427*5225e6b1SAndroid Build Coastguard Worker macro_rules! fastboot_msg {
428*5225e6b1SAndroid Build Coastguard Worker ( $arr:expr, $msg_type:expr, $( $x:expr ),* $(,)? ) => {
429*5225e6b1SAndroid Build Coastguard Worker {
430*5225e6b1SAndroid Build Coastguard Worker let mut formatted_bytes = FormattedBytes::new(&mut $arr[..]);
431*5225e6b1SAndroid Build Coastguard Worker write!(formatted_bytes, $msg_type).unwrap();
432*5225e6b1SAndroid Build Coastguard Worker write!(formatted_bytes, $($x,)*).unwrap();
433*5225e6b1SAndroid Build Coastguard Worker let size = formatted_bytes.size();
434*5225e6b1SAndroid Build Coastguard Worker &mut $arr[..size]
435*5225e6b1SAndroid Build Coastguard Worker }
436*5225e6b1SAndroid Build Coastguard Worker };
437*5225e6b1SAndroid Build Coastguard Worker }
438*5225e6b1SAndroid Build Coastguard Worker
439*5225e6b1SAndroid Build Coastguard Worker /// An internal convenient macro that constructs a formatted fastboot OKAY message.
440*5225e6b1SAndroid Build Coastguard Worker macro_rules! fastboot_okay {
441*5225e6b1SAndroid Build Coastguard Worker ( $arr:expr, $( $x:expr ),* $(,)?) => { fastboot_msg!($arr, "OKAY", $($x,)*) };
442*5225e6b1SAndroid Build Coastguard Worker }
443*5225e6b1SAndroid Build Coastguard Worker
444*5225e6b1SAndroid Build Coastguard Worker /// An internal convenient macro that constructs a formatted fastboot FAIL message.
445*5225e6b1SAndroid Build Coastguard Worker macro_rules! fastboot_fail {
446*5225e6b1SAndroid Build Coastguard Worker ( $arr:expr, $( $x:expr ),* $(,)?) => { fastboot_msg!($arr, "FAIL", $($x,)*) };
447*5225e6b1SAndroid Build Coastguard Worker }
448*5225e6b1SAndroid Build Coastguard Worker
449*5225e6b1SAndroid Build Coastguard Worker /// `VarInfoSender` provide an interface for sending variable/args/value combination during the
450*5225e6b1SAndroid Build Coastguard Worker /// processing of `fastboot getvar all`
451*5225e6b1SAndroid Build Coastguard Worker pub trait VarInfoSender {
452*5225e6b1SAndroid Build Coastguard Worker /// Send a combination of variable name, arguments and value.
453*5225e6b1SAndroid Build Coastguard Worker ///
454*5225e6b1SAndroid Build Coastguard Worker /// The method sends a fastboot message "INFO<var>:<args>:<val>" to the host.
455*5225e6b1SAndroid Build Coastguard Worker ///
456*5225e6b1SAndroid Build Coastguard Worker /// # Args
457*5225e6b1SAndroid Build Coastguard Worker ///
458*5225e6b1SAndroid Build Coastguard Worker /// * `name`: Name of the fastboot variable.
459*5225e6b1SAndroid Build Coastguard Worker /// * `args`: An iterator to additional arguments.
460*5225e6b1SAndroid Build Coastguard Worker /// * `val`: Value of the variable.
send_var_info( &mut self, name: &str, args: impl IntoIterator<Item = &'_ str>, val: &str, ) -> Result<()>461*5225e6b1SAndroid Build Coastguard Worker async fn send_var_info(
462*5225e6b1SAndroid Build Coastguard Worker &mut self,
463*5225e6b1SAndroid Build Coastguard Worker name: &str,
464*5225e6b1SAndroid Build Coastguard Worker args: impl IntoIterator<Item = &'_ str>,
465*5225e6b1SAndroid Build Coastguard Worker val: &str,
466*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()>;
467*5225e6b1SAndroid Build Coastguard Worker }
468*5225e6b1SAndroid Build Coastguard Worker
469*5225e6b1SAndroid Build Coastguard Worker /// Provides an API for sending fastboot INFO messages.
470*5225e6b1SAndroid Build Coastguard Worker pub trait InfoSender {
471*5225e6b1SAndroid Build Coastguard Worker /// Sends formatted INFO message.
472*5225e6b1SAndroid Build Coastguard Worker ///
473*5225e6b1SAndroid Build Coastguard Worker /// # Args:
474*5225e6b1SAndroid Build Coastguard Worker ///
475*5225e6b1SAndroid Build Coastguard Worker /// * `cb`: A closure provided by the caller for constructing the formatted messagae.
send_formatted_info<F: FnOnce(&mut dyn Write)>(&mut self, cb: F) -> Result<()>476*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_info<F: FnOnce(&mut dyn Write)>(&mut self, cb: F) -> Result<()>;
477*5225e6b1SAndroid Build Coastguard Worker
478*5225e6b1SAndroid Build Coastguard Worker /// Sends a Fastboot "INFO<`msg`>" packet.
send_info(&mut self, msg: &str) -> Result<()>479*5225e6b1SAndroid Build Coastguard Worker async fn send_info(&mut self, msg: &str) -> Result<()> {
480*5225e6b1SAndroid Build Coastguard Worker self.send_formatted_info(|w| write!(w, "{}", msg).unwrap()).await
481*5225e6b1SAndroid Build Coastguard Worker }
482*5225e6b1SAndroid Build Coastguard Worker }
483*5225e6b1SAndroid Build Coastguard Worker
484*5225e6b1SAndroid Build Coastguard Worker /// Provides an API for sending fastboot OKAY messages.
485*5225e6b1SAndroid Build Coastguard Worker pub trait OkaySender {
486*5225e6b1SAndroid Build Coastguard Worker /// Sends formatted Okay message.
487*5225e6b1SAndroid Build Coastguard Worker ///
488*5225e6b1SAndroid Build Coastguard Worker /// # Args:
489*5225e6b1SAndroid Build Coastguard Worker ///
490*5225e6b1SAndroid Build Coastguard Worker /// * `cb`: A closure provided by the caller for constructing the formatted messagae.
send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, cb: F) -> Result<()>491*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, cb: F) -> Result<()>;
492*5225e6b1SAndroid Build Coastguard Worker
493*5225e6b1SAndroid Build Coastguard Worker /// Sends a fastboot OKAY<msg> packet. `Self` is consumed.
send_okay(self, msg: &str) -> Result<()> where Self: Sized,494*5225e6b1SAndroid Build Coastguard Worker async fn send_okay(self, msg: &str) -> Result<()>
495*5225e6b1SAndroid Build Coastguard Worker where
496*5225e6b1SAndroid Build Coastguard Worker Self: Sized,
497*5225e6b1SAndroid Build Coastguard Worker {
498*5225e6b1SAndroid Build Coastguard Worker self.send_formatted_okay(|w| write!(w, "{}", msg).unwrap()).await
499*5225e6b1SAndroid Build Coastguard Worker }
500*5225e6b1SAndroid Build Coastguard Worker }
501*5225e6b1SAndroid Build Coastguard Worker
502*5225e6b1SAndroid Build Coastguard Worker /// `UploadBuilder` provides API for initiating a fastboot upload.
503*5225e6b1SAndroid Build Coastguard Worker pub trait UploadBuilder {
504*5225e6b1SAndroid Build Coastguard Worker /// Starts the upload.
505*5225e6b1SAndroid Build Coastguard Worker ///
506*5225e6b1SAndroid Build Coastguard Worker /// In a real fastboot context, the method should send `DATA0xXXXXXXXX` to the remote host to
507*5225e6b1SAndroid Build Coastguard Worker /// start the download. An `Uploader` implementation should be returned for uploading payload.
initiate_upload(self, data_size: u64) -> Result<impl Uploader>508*5225e6b1SAndroid Build Coastguard Worker async fn initiate_upload(self, data_size: u64) -> Result<impl Uploader>;
509*5225e6b1SAndroid Build Coastguard Worker }
510*5225e6b1SAndroid Build Coastguard Worker
511*5225e6b1SAndroid Build Coastguard Worker /// `UploadBuilder` provides API for uploading payload.
512*5225e6b1SAndroid Build Coastguard Worker pub trait Uploader {
513*5225e6b1SAndroid Build Coastguard Worker /// Uploads data to the Fastboot host.
upload(&mut self, data: &[u8]) -> Result<()>514*5225e6b1SAndroid Build Coastguard Worker async fn upload(&mut self, data: &[u8]) -> Result<()>;
515*5225e6b1SAndroid Build Coastguard Worker }
516*5225e6b1SAndroid Build Coastguard Worker
517*5225e6b1SAndroid Build Coastguard Worker /// `Responder` implements APIs for fastboot backend to send fastboot messages and uploading data.
518*5225e6b1SAndroid Build Coastguard Worker struct Responder<'a, T: Transport> {
519*5225e6b1SAndroid Build Coastguard Worker buffer: [u8; MAX_RESPONSE_SIZE],
520*5225e6b1SAndroid Build Coastguard Worker transport: &'a mut T,
521*5225e6b1SAndroid Build Coastguard Worker transport_error: Result<()>,
522*5225e6b1SAndroid Build Coastguard Worker remaining_upload: u64,
523*5225e6b1SAndroid Build Coastguard Worker }
524*5225e6b1SAndroid Build Coastguard Worker
525*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: Transport> Responder<'a, T> {
new(transport: &'a mut T) -> Self526*5225e6b1SAndroid Build Coastguard Worker fn new(transport: &'a mut T) -> Self {
527*5225e6b1SAndroid Build Coastguard Worker Self {
528*5225e6b1SAndroid Build Coastguard Worker buffer: [0u8; MAX_RESPONSE_SIZE],
529*5225e6b1SAndroid Build Coastguard Worker transport,
530*5225e6b1SAndroid Build Coastguard Worker transport_error: Ok(()),
531*5225e6b1SAndroid Build Coastguard Worker remaining_upload: 0,
532*5225e6b1SAndroid Build Coastguard Worker }
533*5225e6b1SAndroid Build Coastguard Worker }
534*5225e6b1SAndroid Build Coastguard Worker
535*5225e6b1SAndroid Build Coastguard Worker /// A helper for sending a fastboot message in the buffer.
send_buffer(&mut self, size: usize) -> Result<()>536*5225e6b1SAndroid Build Coastguard Worker async fn send_buffer(&mut self, size: usize) -> Result<()> {
537*5225e6b1SAndroid Build Coastguard Worker self.transport_error?;
538*5225e6b1SAndroid Build Coastguard Worker assert!(size < self.buffer.len());
539*5225e6b1SAndroid Build Coastguard Worker self.transport_error = self.transport.send_packet(&self.buffer[..size]).await;
540*5225e6b1SAndroid Build Coastguard Worker Ok(self.transport_error?)
541*5225e6b1SAndroid Build Coastguard Worker }
542*5225e6b1SAndroid Build Coastguard Worker
543*5225e6b1SAndroid Build Coastguard Worker /// Helper for sending a formatted fastboot message.
544*5225e6b1SAndroid Build Coastguard Worker ///
545*5225e6b1SAndroid Build Coastguard Worker /// # Args:
546*5225e6b1SAndroid Build Coastguard Worker ///
547*5225e6b1SAndroid Build Coastguard Worker /// * `cb`: A closure provided by the caller for constructing the formatted messagae.
send_formatted_msg<F: FnOnce(&mut dyn Write)>( &mut self, msg_type: &str, cb: F, ) -> Result<()>548*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_msg<F: FnOnce(&mut dyn Write)>(
549*5225e6b1SAndroid Build Coastguard Worker &mut self,
550*5225e6b1SAndroid Build Coastguard Worker msg_type: &str,
551*5225e6b1SAndroid Build Coastguard Worker cb: F,
552*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
553*5225e6b1SAndroid Build Coastguard Worker let mut formatted_bytes = FormattedBytes::new(&mut self.buffer);
554*5225e6b1SAndroid Build Coastguard Worker write!(formatted_bytes, "{}", msg_type).unwrap();
555*5225e6b1SAndroid Build Coastguard Worker cb(&mut formatted_bytes);
556*5225e6b1SAndroid Build Coastguard Worker let size = formatted_bytes.size();
557*5225e6b1SAndroid Build Coastguard Worker self.send_buffer(size).await
558*5225e6b1SAndroid Build Coastguard Worker }
559*5225e6b1SAndroid Build Coastguard Worker
560*5225e6b1SAndroid Build Coastguard Worker /// Sends a fastboot DATA message.
send_data_message(&mut self, data_size: u64) -> Result<()>561*5225e6b1SAndroid Build Coastguard Worker async fn send_data_message(&mut self, data_size: u64) -> Result<()> {
562*5225e6b1SAndroid Build Coastguard Worker self.send_formatted_msg("DATA", |v| write!(v, "{:08x}", data_size).unwrap()).await
563*5225e6b1SAndroid Build Coastguard Worker }
564*5225e6b1SAndroid Build Coastguard Worker }
565*5225e6b1SAndroid Build Coastguard Worker
566*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: Transport> VarInfoSender for &mut Responder<'a, T> {
send_var_info( &mut self, name: &str, args: impl IntoIterator<Item = &'_ str>, val: &str, ) -> Result<()>567*5225e6b1SAndroid Build Coastguard Worker async fn send_var_info(
568*5225e6b1SAndroid Build Coastguard Worker &mut self,
569*5225e6b1SAndroid Build Coastguard Worker name: &str,
570*5225e6b1SAndroid Build Coastguard Worker args: impl IntoIterator<Item = &'_ str>,
571*5225e6b1SAndroid Build Coastguard Worker val: &str,
572*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
573*5225e6b1SAndroid Build Coastguard Worker // Sends a "INFO<var>:<':'-separated args>:<val>" packet to the host.
574*5225e6b1SAndroid Build Coastguard Worker Ok(self
575*5225e6b1SAndroid Build Coastguard Worker .send_formatted_msg("INFO", |v| {
576*5225e6b1SAndroid Build Coastguard Worker write!(v, "{}", name).unwrap();
577*5225e6b1SAndroid Build Coastguard Worker args.into_iter().for_each(|arg| write!(v, ":{}", arg).unwrap());
578*5225e6b1SAndroid Build Coastguard Worker write!(v, ": {}", val).unwrap();
579*5225e6b1SAndroid Build Coastguard Worker })
580*5225e6b1SAndroid Build Coastguard Worker .await?)
581*5225e6b1SAndroid Build Coastguard Worker }
582*5225e6b1SAndroid Build Coastguard Worker }
583*5225e6b1SAndroid Build Coastguard Worker
584*5225e6b1SAndroid Build Coastguard Worker /// An internal convenient macro that sends a formatted fastboot OKAY message via a `Responder`
585*5225e6b1SAndroid Build Coastguard Worker macro_rules! reply_okay {
586*5225e6b1SAndroid Build Coastguard Worker ( $resp:expr, $( $x:expr ),* $(,)?) => {
587*5225e6b1SAndroid Build Coastguard Worker {
588*5225e6b1SAndroid Build Coastguard Worker let len = fastboot_okay!($resp.buffer, $($x,)*).len();
589*5225e6b1SAndroid Build Coastguard Worker $resp.send_buffer(len).await
590*5225e6b1SAndroid Build Coastguard Worker }
591*5225e6b1SAndroid Build Coastguard Worker };
592*5225e6b1SAndroid Build Coastguard Worker }
593*5225e6b1SAndroid Build Coastguard Worker
594*5225e6b1SAndroid Build Coastguard Worker /// An internal convenient macro that sends a formatted fastboot FAIL message via a `Responder`
595*5225e6b1SAndroid Build Coastguard Worker macro_rules! reply_fail {
596*5225e6b1SAndroid Build Coastguard Worker ( $resp:expr, $( $x:expr ),* $(,)?) => {
597*5225e6b1SAndroid Build Coastguard Worker {
598*5225e6b1SAndroid Build Coastguard Worker let len = fastboot_fail!($resp.buffer, $($x,)*).len();
599*5225e6b1SAndroid Build Coastguard Worker $resp.send_buffer(len).await
600*5225e6b1SAndroid Build Coastguard Worker }
601*5225e6b1SAndroid Build Coastguard Worker };
602*5225e6b1SAndroid Build Coastguard Worker }
603*5225e6b1SAndroid Build Coastguard Worker
604*5225e6b1SAndroid Build Coastguard Worker impl<T: Transport> InfoSender for &mut Responder<'_, T> {
send_formatted_info<F: FnOnce(&mut dyn Write)>(&mut self, cb: F) -> Result<()>605*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_info<F: FnOnce(&mut dyn Write)>(&mut self, cb: F) -> Result<()> {
606*5225e6b1SAndroid Build Coastguard Worker Ok(self.send_formatted_msg("INFO", cb).await?)
607*5225e6b1SAndroid Build Coastguard Worker }
608*5225e6b1SAndroid Build Coastguard Worker }
609*5225e6b1SAndroid Build Coastguard Worker
610*5225e6b1SAndroid Build Coastguard Worker impl<T: Transport> OkaySender for &mut Responder<'_, T> {
send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, cb: F) -> Result<()>611*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, cb: F) -> Result<()> {
612*5225e6b1SAndroid Build Coastguard Worker Ok(self.send_formatted_msg("OKAY", cb).await?)
613*5225e6b1SAndroid Build Coastguard Worker }
614*5225e6b1SAndroid Build Coastguard Worker }
615*5225e6b1SAndroid Build Coastguard Worker
616*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: Transport> UploadBuilder for &mut Responder<'a, T> {
initiate_upload(self, data_size: u64) -> Result<impl Uploader>617*5225e6b1SAndroid Build Coastguard Worker async fn initiate_upload(self, data_size: u64) -> Result<impl Uploader> {
618*5225e6b1SAndroid Build Coastguard Worker self.send_data_message(data_size).await?;
619*5225e6b1SAndroid Build Coastguard Worker self.remaining_upload = data_size;
620*5225e6b1SAndroid Build Coastguard Worker Ok(self)
621*5225e6b1SAndroid Build Coastguard Worker }
622*5225e6b1SAndroid Build Coastguard Worker }
623*5225e6b1SAndroid Build Coastguard Worker
624*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: Transport> Uploader for &mut Responder<'a, T> {
625*5225e6b1SAndroid Build Coastguard Worker /// Uploads data. Returns error if accumulative amount exceeds `data_size` passed to
626*5225e6b1SAndroid Build Coastguard Worker /// `UploadBuilder::start()`.
upload(&mut self, data: &[u8]) -> Result<()>627*5225e6b1SAndroid Build Coastguard Worker async fn upload(&mut self, data: &[u8]) -> Result<()> {
628*5225e6b1SAndroid Build Coastguard Worker self.transport_error?;
629*5225e6b1SAndroid Build Coastguard Worker self.remaining_upload = self
630*5225e6b1SAndroid Build Coastguard Worker .remaining_upload
631*5225e6b1SAndroid Build Coastguard Worker .checked_sub(data.len().try_into().map_err(|_| "")?)
632*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::Other(Some("Invalid size of upload data")))?;
633*5225e6b1SAndroid Build Coastguard Worker self.transport_error = self.transport.send_packet(data).await;
634*5225e6b1SAndroid Build Coastguard Worker Ok(())
635*5225e6b1SAndroid Build Coastguard Worker }
636*5225e6b1SAndroid Build Coastguard Worker }
637*5225e6b1SAndroid Build Coastguard Worker
638*5225e6b1SAndroid Build Coastguard Worker pub mod test_utils {
639*5225e6b1SAndroid Build Coastguard Worker //! Test utilities to help users of this library write unit tests.
640*5225e6b1SAndroid Build Coastguard Worker
641*5225e6b1SAndroid Build Coastguard Worker use crate::{InfoSender, UploadBuilder, Uploader};
642*5225e6b1SAndroid Build Coastguard Worker use core::fmt::Write;
643*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
644*5225e6b1SAndroid Build Coastguard Worker
645*5225e6b1SAndroid Build Coastguard Worker /// A test implementation of `UploadBuilder` for unittesting
646*5225e6b1SAndroid Build Coastguard Worker /// `FastbootImplementation::upload()`.
647*5225e6b1SAndroid Build Coastguard Worker ///
648*5225e6b1SAndroid Build Coastguard Worker /// The test uploader simply uploads to a user provided buffer.
649*5225e6b1SAndroid Build Coastguard Worker pub struct TestUploadBuilder<'a>(pub &'a mut [u8]);
650*5225e6b1SAndroid Build Coastguard Worker
651*5225e6b1SAndroid Build Coastguard Worker impl<'a> UploadBuilder for TestUploadBuilder<'a> {
initiate_upload(self, _: u64) -> Result<impl Uploader, Error>652*5225e6b1SAndroid Build Coastguard Worker async fn initiate_upload(self, _: u64) -> Result<impl Uploader, Error> {
653*5225e6b1SAndroid Build Coastguard Worker Ok(TestUploader(0, self.0))
654*5225e6b1SAndroid Build Coastguard Worker }
655*5225e6b1SAndroid Build Coastguard Worker }
656*5225e6b1SAndroid Build Coastguard Worker
657*5225e6b1SAndroid Build Coastguard Worker impl<'a> InfoSender for TestUploadBuilder<'a> {
send_formatted_info<F: FnOnce(&mut dyn Write)>( &mut self, _: F, ) -> Result<(), Error>658*5225e6b1SAndroid Build Coastguard Worker async fn send_formatted_info<F: FnOnce(&mut dyn Write)>(
659*5225e6b1SAndroid Build Coastguard Worker &mut self,
660*5225e6b1SAndroid Build Coastguard Worker _: F,
661*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error> {
662*5225e6b1SAndroid Build Coastguard Worker // Not needed currently.
663*5225e6b1SAndroid Build Coastguard Worker Ok(())
664*5225e6b1SAndroid Build Coastguard Worker }
665*5225e6b1SAndroid Build Coastguard Worker }
666*5225e6b1SAndroid Build Coastguard Worker
667*5225e6b1SAndroid Build Coastguard Worker // (Bytes sent, upload buffer)
668*5225e6b1SAndroid Build Coastguard Worker struct TestUploader<'a>(usize, &'a mut [u8]);
669*5225e6b1SAndroid Build Coastguard Worker
670*5225e6b1SAndroid Build Coastguard Worker impl Uploader for TestUploader<'_> {
upload(&mut self, data: &[u8]) -> Result<(), Error>671*5225e6b1SAndroid Build Coastguard Worker async fn upload(&mut self, data: &[u8]) -> Result<(), Error> {
672*5225e6b1SAndroid Build Coastguard Worker self.1[self.0..][..data.len()].clone_from_slice(data);
673*5225e6b1SAndroid Build Coastguard Worker self.0 = self.0.checked_add(data.len()).unwrap();
674*5225e6b1SAndroid Build Coastguard Worker Ok(())
675*5225e6b1SAndroid Build Coastguard Worker }
676*5225e6b1SAndroid Build Coastguard Worker }
677*5225e6b1SAndroid Build Coastguard Worker }
678*5225e6b1SAndroid Build Coastguard Worker
679*5225e6b1SAndroid Build Coastguard Worker const MAX_DOWNLOAD_SIZE_NAME: &'static str = "max-download-size";
680*5225e6b1SAndroid Build Coastguard Worker
681*5225e6b1SAndroid Build Coastguard Worker /// Converts a null-terminated command line string where arguments are separated by ':' into an
682*5225e6b1SAndroid Build Coastguard Worker /// iterator of individual argument as CStr.
cmd_to_c_string_args(cmd: &mut [u8]) -> impl Iterator<Item = &CStr> + Clone683*5225e6b1SAndroid Build Coastguard Worker fn cmd_to_c_string_args(cmd: &mut [u8]) -> impl Iterator<Item = &CStr> + Clone {
684*5225e6b1SAndroid Build Coastguard Worker let end = cmd.iter().position(|v| *v == 0).unwrap();
685*5225e6b1SAndroid Build Coastguard Worker // Replace ':' with NULL.
686*5225e6b1SAndroid Build Coastguard Worker cmd.iter_mut().filter(|v| **v == b':').for_each(|v| *v = 0);
687*5225e6b1SAndroid Build Coastguard Worker cmd[..end + 1].split_inclusive(|v| *v == 0).map(|v| CStr::from_bytes_until_nul(v).unwrap())
688*5225e6b1SAndroid Build Coastguard Worker }
689*5225e6b1SAndroid Build Coastguard Worker
690*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot getvar ..."
get_var( cmd: &mut [u8], transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>691*5225e6b1SAndroid Build Coastguard Worker async fn get_var(
692*5225e6b1SAndroid Build Coastguard Worker cmd: &mut [u8],
693*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
694*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
695*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
696*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
697*5225e6b1SAndroid Build Coastguard Worker let mut args = cmd_to_c_string_args(cmd).skip(1);
698*5225e6b1SAndroid Build Coastguard Worker let Some(var) = args.next() else {
699*5225e6b1SAndroid Build Coastguard Worker return reply_fail!(resp, "Missing variable");
700*5225e6b1SAndroid Build Coastguard Worker };
701*5225e6b1SAndroid Build Coastguard Worker
702*5225e6b1SAndroid Build Coastguard Worker match var.to_str()? {
703*5225e6b1SAndroid Build Coastguard Worker "all" => return get_var_all(transport, fb_impl).await,
704*5225e6b1SAndroid Build Coastguard Worker MAX_DOWNLOAD_SIZE_NAME => {
705*5225e6b1SAndroid Build Coastguard Worker return reply_okay!(resp, "{:#x}", fb_impl.get_download_buffer().await.len());
706*5225e6b1SAndroid Build Coastguard Worker }
707*5225e6b1SAndroid Build Coastguard Worker _ => {
708*5225e6b1SAndroid Build Coastguard Worker let mut val = [0u8; MAX_RESPONSE_SIZE];
709*5225e6b1SAndroid Build Coastguard Worker match fb_impl.get_var_as_str(var, args, &mut resp, &mut val[..]).await {
710*5225e6b1SAndroid Build Coastguard Worker Ok(s) => reply_okay!(resp, "{}", s),
711*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
712*5225e6b1SAndroid Build Coastguard Worker }
713*5225e6b1SAndroid Build Coastguard Worker }
714*5225e6b1SAndroid Build Coastguard Worker }
715*5225e6b1SAndroid Build Coastguard Worker }
716*5225e6b1SAndroid Build Coastguard Worker
717*5225e6b1SAndroid Build Coastguard Worker /// A wrapper of `get_var_all()` that first iterates reserved variables.
get_var_all_with_native( fb_impl: &mut impl FastbootImplementation, mut sender: impl VarInfoSender, ) -> CommandResult<()>718*5225e6b1SAndroid Build Coastguard Worker async fn get_var_all_with_native(
719*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
720*5225e6b1SAndroid Build Coastguard Worker mut sender: impl VarInfoSender,
721*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> {
722*5225e6b1SAndroid Build Coastguard Worker // Process the built-in MAX_DOWNLOAD_SIZE_NAME variable.
723*5225e6b1SAndroid Build Coastguard Worker let mut size_str = [0u8; 32];
724*5225e6b1SAndroid Build Coastguard Worker let size_str = snprintf!(size_str, "{:#x}", fb_impl.get_download_buffer().await.len());
725*5225e6b1SAndroid Build Coastguard Worker sender.send_var_info(MAX_DOWNLOAD_SIZE_NAME, [], size_str).await?;
726*5225e6b1SAndroid Build Coastguard Worker fb_impl.get_var_all(sender).await
727*5225e6b1SAndroid Build Coastguard Worker }
728*5225e6b1SAndroid Build Coastguard Worker
729*5225e6b1SAndroid Build Coastguard Worker /// Method for handling "fastboot getvar all"
get_var_all( transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>730*5225e6b1SAndroid Build Coastguard Worker async fn get_var_all(
731*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
732*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
733*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
734*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
735*5225e6b1SAndroid Build Coastguard Worker // Don't allow custom INFO messages because variable values are sent as INFO messages.
736*5225e6b1SAndroid Build Coastguard Worker let get_res = get_var_all_with_native(fb_impl, &mut resp).await;
737*5225e6b1SAndroid Build Coastguard Worker match get_res {
738*5225e6b1SAndroid Build Coastguard Worker Ok(()) => reply_okay!(resp, ""),
739*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
740*5225e6b1SAndroid Build Coastguard Worker }
741*5225e6b1SAndroid Build Coastguard Worker }
742*5225e6b1SAndroid Build Coastguard Worker
743*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot download:...".
download( mut args: Split<'_, char>, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>744*5225e6b1SAndroid Build Coastguard Worker async fn download(
745*5225e6b1SAndroid Build Coastguard Worker mut args: Split<'_, char>,
746*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
747*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
748*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
749*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
750*5225e6b1SAndroid Build Coastguard Worker let total_download_size = match (|| -> CommandResult<usize> {
751*5225e6b1SAndroid Build Coastguard Worker usize::try_from(next_arg_u64(&mut args)?.ok_or("Not enough argument")?)
752*5225e6b1SAndroid Build Coastguard Worker .map_err(|_| "Download size overflow".into())
753*5225e6b1SAndroid Build Coastguard Worker })() {
754*5225e6b1SAndroid Build Coastguard Worker Err(e) => return reply_fail!(resp, "{}", e.to_str()),
755*5225e6b1SAndroid Build Coastguard Worker Ok(v) => v,
756*5225e6b1SAndroid Build Coastguard Worker };
757*5225e6b1SAndroid Build Coastguard Worker let download_buffer = &mut fb_impl.get_download_buffer().await;
758*5225e6b1SAndroid Build Coastguard Worker if total_download_size > download_buffer.len() {
759*5225e6b1SAndroid Build Coastguard Worker return reply_fail!(resp, "Download size is too big");
760*5225e6b1SAndroid Build Coastguard Worker } else if total_download_size == 0 {
761*5225e6b1SAndroid Build Coastguard Worker return reply_fail!(resp, "Zero download size");
762*5225e6b1SAndroid Build Coastguard Worker }
763*5225e6b1SAndroid Build Coastguard Worker
764*5225e6b1SAndroid Build Coastguard Worker // Starts the download
765*5225e6b1SAndroid Build Coastguard Worker let download_buffer = &mut download_buffer[..total_download_size];
766*5225e6b1SAndroid Build Coastguard Worker // `total_download_size` is parsed from `next_arg_u64` and thus should fit into u64.
767*5225e6b1SAndroid Build Coastguard Worker resp.send_data_message(u64::try_from(total_download_size).unwrap()).await?;
768*5225e6b1SAndroid Build Coastguard Worker let mut downloaded = 0;
769*5225e6b1SAndroid Build Coastguard Worker while downloaded < total_download_size {
770*5225e6b1SAndroid Build Coastguard Worker let (_, remains) = &mut download_buffer.split_at_mut(downloaded);
771*5225e6b1SAndroid Build Coastguard Worker match resp.transport.receive_packet(remains).await? {
772*5225e6b1SAndroid Build Coastguard Worker 0 => yield_now().await,
773*5225e6b1SAndroid Build Coastguard Worker v => match downloaded.checked_add(v) {
774*5225e6b1SAndroid Build Coastguard Worker Some(v) if v > total_download_size => {
775*5225e6b1SAndroid Build Coastguard Worker return reply_fail!(resp, "More data received then expected");
776*5225e6b1SAndroid Build Coastguard Worker }
777*5225e6b1SAndroid Build Coastguard Worker Some(v) => downloaded = v,
778*5225e6b1SAndroid Build Coastguard Worker _ => return Err(Error::Other(Some("Invalid read size from transport"))),
779*5225e6b1SAndroid Build Coastguard Worker },
780*5225e6b1SAndroid Build Coastguard Worker };
781*5225e6b1SAndroid Build Coastguard Worker }
782*5225e6b1SAndroid Build Coastguard Worker match fb_impl.download_complete(downloaded, &mut resp).await {
783*5225e6b1SAndroid Build Coastguard Worker Ok(()) => reply_okay!(resp, ""),
784*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
785*5225e6b1SAndroid Build Coastguard Worker }
786*5225e6b1SAndroid Build Coastguard Worker }
787*5225e6b1SAndroid Build Coastguard Worker
788*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot flash ...".
flash( cmd: &str, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>789*5225e6b1SAndroid Build Coastguard Worker async fn flash(
790*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
791*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
792*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
793*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
794*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
795*5225e6b1SAndroid Build Coastguard Worker let flash_res =
796*5225e6b1SAndroid Build Coastguard Worker match cmd.strip_prefix("flash:").ok_or::<CommandError>("Missing partition".into()) {
797*5225e6b1SAndroid Build Coastguard Worker Ok(part) => fb_impl.flash(part, &mut resp).await,
798*5225e6b1SAndroid Build Coastguard Worker Err(e) => Err(e),
799*5225e6b1SAndroid Build Coastguard Worker };
800*5225e6b1SAndroid Build Coastguard Worker match flash_res {
801*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
802*5225e6b1SAndroid Build Coastguard Worker _ => reply_okay!(resp, ""),
803*5225e6b1SAndroid Build Coastguard Worker }
804*5225e6b1SAndroid Build Coastguard Worker }
805*5225e6b1SAndroid Build Coastguard Worker
806*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot erase ...".
erase( cmd: &str, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>807*5225e6b1SAndroid Build Coastguard Worker async fn erase(
808*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
809*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
810*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
811*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
812*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
813*5225e6b1SAndroid Build Coastguard Worker let flash_res =
814*5225e6b1SAndroid Build Coastguard Worker match cmd.strip_prefix("erase:").ok_or::<CommandError>("Missing partition".into()) {
815*5225e6b1SAndroid Build Coastguard Worker Ok(part) => fb_impl.erase(part, &mut resp).await,
816*5225e6b1SAndroid Build Coastguard Worker Err(e) => Err(e),
817*5225e6b1SAndroid Build Coastguard Worker };
818*5225e6b1SAndroid Build Coastguard Worker match flash_res {
819*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
820*5225e6b1SAndroid Build Coastguard Worker _ => reply_okay!(resp, ""),
821*5225e6b1SAndroid Build Coastguard Worker }
822*5225e6b1SAndroid Build Coastguard Worker }
823*5225e6b1SAndroid Build Coastguard Worker
824*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot get_staged ...".
upload( transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>825*5225e6b1SAndroid Build Coastguard Worker async fn upload(
826*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
827*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
828*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
829*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
830*5225e6b1SAndroid Build Coastguard Worker let upload_res = fb_impl.upload(&mut resp).await;
831*5225e6b1SAndroid Build Coastguard Worker match resp.remaining_upload > 0 {
832*5225e6b1SAndroid Build Coastguard Worker true => return Err(Error::InvalidInput),
833*5225e6b1SAndroid Build Coastguard Worker _ => match upload_res {
834*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
835*5225e6b1SAndroid Build Coastguard Worker _ => reply_okay!(resp, ""),
836*5225e6b1SAndroid Build Coastguard Worker },
837*5225e6b1SAndroid Build Coastguard Worker }
838*5225e6b1SAndroid Build Coastguard Worker }
839*5225e6b1SAndroid Build Coastguard Worker
840*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot fetch ...".
fetch( cmd: &str, args: Split<'_, char>, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>841*5225e6b1SAndroid Build Coastguard Worker async fn fetch(
842*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
843*5225e6b1SAndroid Build Coastguard Worker args: Split<'_, char>,
844*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
845*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
846*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
847*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
848*5225e6b1SAndroid Build Coastguard Worker let fetch_res = async {
849*5225e6b1SAndroid Build Coastguard Worker let cmd = cmd.strip_prefix("fetch:").ok_or::<CommandError>("Missing arguments".into())?;
850*5225e6b1SAndroid Build Coastguard Worker if args.clone().count() < 3 {
851*5225e6b1SAndroid Build Coastguard Worker return Err("Not enough argments".into());
852*5225e6b1SAndroid Build Coastguard Worker }
853*5225e6b1SAndroid Build Coastguard Worker // Parses backward. Parses size, offset first and treats the remaining string as
854*5225e6b1SAndroid Build Coastguard Worker // partition name. This allows ":" in partition name.
855*5225e6b1SAndroid Build Coastguard Worker let mut rev = args.clone().rev();
856*5225e6b1SAndroid Build Coastguard Worker let sz = next_arg(&mut rev).ok_or("Missing size")?;
857*5225e6b1SAndroid Build Coastguard Worker let off = next_arg(&mut rev).ok_or("Invalid offset")?;
858*5225e6b1SAndroid Build Coastguard Worker let part = &cmd[..cmd.len() - (off.len() + sz.len() + 2)];
859*5225e6b1SAndroid Build Coastguard Worker fb_impl.fetch(part, hex_to_u64(off)?, hex_to_u64(sz)?, &mut resp).await
860*5225e6b1SAndroid Build Coastguard Worker }
861*5225e6b1SAndroid Build Coastguard Worker .await;
862*5225e6b1SAndroid Build Coastguard Worker match resp.remaining_upload > 0 {
863*5225e6b1SAndroid Build Coastguard Worker true => return Err(Error::InvalidInput),
864*5225e6b1SAndroid Build Coastguard Worker _ => match fetch_res {
865*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
866*5225e6b1SAndroid Build Coastguard Worker _ => reply_okay!(resp, ""),
867*5225e6b1SAndroid Build Coastguard Worker },
868*5225e6b1SAndroid Build Coastguard Worker }
869*5225e6b1SAndroid Build Coastguard Worker }
870*5225e6b1SAndroid Build Coastguard Worker
871*5225e6b1SAndroid Build Coastguard Worker // Handles `fastboot reboot*`
reboot( mode: RebootMode, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>872*5225e6b1SAndroid Build Coastguard Worker async fn reboot(
873*5225e6b1SAndroid Build Coastguard Worker mode: RebootMode,
874*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
875*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
876*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
877*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
878*5225e6b1SAndroid Build Coastguard Worker let e = fb_impl.reboot(mode, &mut resp).await;
879*5225e6b1SAndroid Build Coastguard Worker reply_fail!(resp, "{}", e.to_str())
880*5225e6b1SAndroid Build Coastguard Worker }
881*5225e6b1SAndroid Build Coastguard Worker
882*5225e6b1SAndroid Build Coastguard Worker // Handles `fastboot boot`
boot( transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>883*5225e6b1SAndroid Build Coastguard Worker async fn boot(
884*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
885*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
886*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
887*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
888*5225e6b1SAndroid Build Coastguard Worker let boot_res = async { fb_impl.boot(&mut resp).await }.await;
889*5225e6b1SAndroid Build Coastguard Worker match boot_res {
890*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
891*5225e6b1SAndroid Build Coastguard Worker _ => reply_okay!(resp, "boot_command"),
892*5225e6b1SAndroid Build Coastguard Worker }
893*5225e6b1SAndroid Build Coastguard Worker }
894*5225e6b1SAndroid Build Coastguard Worker
895*5225e6b1SAndroid Build Coastguard Worker // Handles `fastboot continue`
896*5225e6b1SAndroid Build Coastguard Worker async fn r#continue(
897*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
898*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
899*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
900*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
901*5225e6b1SAndroid Build Coastguard Worker match fb_impl.r#continue(&mut resp).await {
902*5225e6b1SAndroid Build Coastguard Worker Ok(_) => reply_okay!(resp, ""),
903*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
904*5225e6b1SAndroid Build Coastguard Worker }
905*5225e6b1SAndroid Build Coastguard Worker }
906*5225e6b1SAndroid Build Coastguard Worker
907*5225e6b1SAndroid Build Coastguard Worker // Handles `fastboot set_active`
set_active( mut args: Split<'_, char>, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>908*5225e6b1SAndroid Build Coastguard Worker async fn set_active(
909*5225e6b1SAndroid Build Coastguard Worker mut args: Split<'_, char>,
910*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
911*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
912*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
913*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
914*5225e6b1SAndroid Build Coastguard Worker let res = async {
915*5225e6b1SAndroid Build Coastguard Worker let slot = next_arg(&mut args).ok_or("Missing slot")?;
916*5225e6b1SAndroid Build Coastguard Worker fb_impl.set_active(slot, &mut resp).await
917*5225e6b1SAndroid Build Coastguard Worker };
918*5225e6b1SAndroid Build Coastguard Worker match res.await {
919*5225e6b1SAndroid Build Coastguard Worker Ok(_) => reply_okay!(resp, ""),
920*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
921*5225e6b1SAndroid Build Coastguard Worker }
922*5225e6b1SAndroid Build Coastguard Worker }
923*5225e6b1SAndroid Build Coastguard Worker
924*5225e6b1SAndroid Build Coastguard Worker /// Helper for handling "fastboot oem ...".
oem( cmd: &str, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>925*5225e6b1SAndroid Build Coastguard Worker async fn oem(
926*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
927*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
928*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
929*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
930*5225e6b1SAndroid Build Coastguard Worker let mut resp = Responder::new(transport);
931*5225e6b1SAndroid Build Coastguard Worker let mut oem_out = [0u8; MAX_RESPONSE_SIZE - 4];
932*5225e6b1SAndroid Build Coastguard Worker let oem_res = fb_impl.oem(cmd, &mut resp, &mut oem_out[..]).await;
933*5225e6b1SAndroid Build Coastguard Worker match oem_res {
934*5225e6b1SAndroid Build Coastguard Worker Ok(msg) => match from_utf8(msg) {
935*5225e6b1SAndroid Build Coastguard Worker Ok(s) => reply_okay!(resp, "{}", s),
936*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "Invalid return string {}", e),
937*5225e6b1SAndroid Build Coastguard Worker },
938*5225e6b1SAndroid Build Coastguard Worker Err(e) => reply_fail!(resp, "{}", e.to_str()),
939*5225e6b1SAndroid Build Coastguard Worker }
940*5225e6b1SAndroid Build Coastguard Worker }
941*5225e6b1SAndroid Build Coastguard Worker
942*5225e6b1SAndroid Build Coastguard Worker /// Process the next Fastboot command from the transport.
943*5225e6b1SAndroid Build Coastguard Worker ///
944*5225e6b1SAndroid Build Coastguard Worker /// # Returns
945*5225e6b1SAndroid Build Coastguard Worker ///
946*5225e6b1SAndroid Build Coastguard Worker /// * Returns Ok(is_continue) on success where `is_continue` is true if command is
947*5225e6b1SAndroid Build Coastguard Worker /// `fastboot continue`.
948*5225e6b1SAndroid Build Coastguard Worker /// * Returns Err() on errors.
process_next_command( transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<bool>949*5225e6b1SAndroid Build Coastguard Worker pub async fn process_next_command(
950*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
951*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
952*5225e6b1SAndroid Build Coastguard Worker ) -> Result<bool> {
953*5225e6b1SAndroid Build Coastguard Worker let mut packet = [0u8; MAX_COMMAND_SIZE + 1];
954*5225e6b1SAndroid Build Coastguard Worker let cmd_size = match transport.receive_packet(&mut packet[..MAX_COMMAND_SIZE]).await? {
955*5225e6b1SAndroid Build Coastguard Worker 0 => return Ok(false),
956*5225e6b1SAndroid Build Coastguard Worker v => v,
957*5225e6b1SAndroid Build Coastguard Worker };
958*5225e6b1SAndroid Build Coastguard Worker let Ok(cmd_str) = from_utf8(&packet[..cmd_size]) else {
959*5225e6b1SAndroid Build Coastguard Worker transport.send_packet(fastboot_fail!(packet, "Invalid Command")).await?;
960*5225e6b1SAndroid Build Coastguard Worker return Ok(false);
961*5225e6b1SAndroid Build Coastguard Worker };
962*5225e6b1SAndroid Build Coastguard Worker let mut args = cmd_str.split(':');
963*5225e6b1SAndroid Build Coastguard Worker let Some(cmd) = args.next() else {
964*5225e6b1SAndroid Build Coastguard Worker return transport.send_packet(fastboot_fail!(packet, "No command")).await.map(|_| false);
965*5225e6b1SAndroid Build Coastguard Worker };
966*5225e6b1SAndroid Build Coastguard Worker match cmd {
967*5225e6b1SAndroid Build Coastguard Worker "boot" => {
968*5225e6b1SAndroid Build Coastguard Worker boot(transport, fb_impl).await?;
969*5225e6b1SAndroid Build Coastguard Worker return Ok(true);
970*5225e6b1SAndroid Build Coastguard Worker }
971*5225e6b1SAndroid Build Coastguard Worker "continue" => {
972*5225e6b1SAndroid Build Coastguard Worker r#continue(transport, fb_impl).await?;
973*5225e6b1SAndroid Build Coastguard Worker return Ok(true);
974*5225e6b1SAndroid Build Coastguard Worker }
975*5225e6b1SAndroid Build Coastguard Worker "download" => download(args, transport, fb_impl).await,
976*5225e6b1SAndroid Build Coastguard Worker "erase" => erase(cmd_str, transport, fb_impl).await,
977*5225e6b1SAndroid Build Coastguard Worker "fetch" => fetch(cmd_str, args, transport, fb_impl).await,
978*5225e6b1SAndroid Build Coastguard Worker "flash" => flash(cmd_str, transport, fb_impl).await,
979*5225e6b1SAndroid Build Coastguard Worker "getvar" => get_var(&mut packet[..], transport, fb_impl).await,
980*5225e6b1SAndroid Build Coastguard Worker "reboot" => reboot(RebootMode::Normal, transport, fb_impl).await,
981*5225e6b1SAndroid Build Coastguard Worker "reboot-bootloader" => reboot(RebootMode::Bootloader, transport, fb_impl).await,
982*5225e6b1SAndroid Build Coastguard Worker "reboot-fastboot" => reboot(RebootMode::Fastboot, transport, fb_impl).await,
983*5225e6b1SAndroid Build Coastguard Worker "reboot-recovery" => reboot(RebootMode::Recovery, transport, fb_impl).await,
984*5225e6b1SAndroid Build Coastguard Worker "set_active" => set_active(args, transport, fb_impl).await,
985*5225e6b1SAndroid Build Coastguard Worker "upload" => upload(transport, fb_impl).await,
986*5225e6b1SAndroid Build Coastguard Worker _ if cmd_str.starts_with("oem ") => oem(&cmd_str[4..], transport, fb_impl).await,
987*5225e6b1SAndroid Build Coastguard Worker _ => transport.send_packet(fastboot_fail!(packet, "Command not found")).await,
988*5225e6b1SAndroid Build Coastguard Worker }?;
989*5225e6b1SAndroid Build Coastguard Worker Ok(false)
990*5225e6b1SAndroid Build Coastguard Worker }
991*5225e6b1SAndroid Build Coastguard Worker
992*5225e6b1SAndroid Build Coastguard Worker /// Keeps polling and processing fastboot commands from the transport.
993*5225e6b1SAndroid Build Coastguard Worker ///
994*5225e6b1SAndroid Build Coastguard Worker /// # Returns
995*5225e6b1SAndroid Build Coastguard Worker ///
996*5225e6b1SAndroid Build Coastguard Worker /// * Returns Ok(()) if "fastboot continue" is received.
997*5225e6b1SAndroid Build Coastguard Worker /// * Returns Err() on errors.
run( transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>998*5225e6b1SAndroid Build Coastguard Worker pub async fn run(
999*5225e6b1SAndroid Build Coastguard Worker transport: &mut impl Transport,
1000*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
1001*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
1002*5225e6b1SAndroid Build Coastguard Worker while !process_next_command(transport, fb_impl).await? {}
1003*5225e6b1SAndroid Build Coastguard Worker Ok(())
1004*5225e6b1SAndroid Build Coastguard Worker }
1005*5225e6b1SAndroid Build Coastguard Worker
1006*5225e6b1SAndroid Build Coastguard Worker /// Runs a fastboot over TCP session.
1007*5225e6b1SAndroid Build Coastguard Worker ///
1008*5225e6b1SAndroid Build Coastguard Worker /// The method performs fastboot over TCP handshake and then call `run(...)`.
1009*5225e6b1SAndroid Build Coastguard Worker ///
1010*5225e6b1SAndroid Build Coastguard Worker /// Returns Ok(()) if "fastboot continue" is received.
run_tcp_session( tcp_stream: &mut impl TcpStream, fb_impl: &mut impl FastbootImplementation, ) -> Result<()>1011*5225e6b1SAndroid Build Coastguard Worker pub async fn run_tcp_session(
1012*5225e6b1SAndroid Build Coastguard Worker tcp_stream: &mut impl TcpStream,
1013*5225e6b1SAndroid Build Coastguard Worker fb_impl: &mut impl FastbootImplementation,
1014*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
1015*5225e6b1SAndroid Build Coastguard Worker run(&mut TcpTransport::new_and_handshake(tcp_stream)?, fb_impl).await
1016*5225e6b1SAndroid Build Coastguard Worker }
1017*5225e6b1SAndroid Build Coastguard Worker
1018*5225e6b1SAndroid Build Coastguard Worker /// A helper data structure for writing formatted string to fixed size bytes array.
1019*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug)]
1020*5225e6b1SAndroid Build Coastguard Worker pub struct FormattedBytes<T: AsMut<[u8]>>(T, usize);
1021*5225e6b1SAndroid Build Coastguard Worker
1022*5225e6b1SAndroid Build Coastguard Worker impl<T: AsMut<[u8]>> FormattedBytes<T> {
1023*5225e6b1SAndroid Build Coastguard Worker /// Create an instance.
new(buf: T) -> Self1024*5225e6b1SAndroid Build Coastguard Worker pub fn new(buf: T) -> Self {
1025*5225e6b1SAndroid Build Coastguard Worker Self(buf, 0)
1026*5225e6b1SAndroid Build Coastguard Worker }
1027*5225e6b1SAndroid Build Coastguard Worker
1028*5225e6b1SAndroid Build Coastguard Worker /// Get the size of content.
size(&self) -> usize1029*5225e6b1SAndroid Build Coastguard Worker pub fn size(&self) -> usize {
1030*5225e6b1SAndroid Build Coastguard Worker self.1
1031*5225e6b1SAndroid Build Coastguard Worker }
1032*5225e6b1SAndroid Build Coastguard Worker
1033*5225e6b1SAndroid Build Coastguard Worker /// Appends the given `bytes` to the contents.
1034*5225e6b1SAndroid Build Coastguard Worker ///
1035*5225e6b1SAndroid Build Coastguard Worker /// If `bytes` exceeds the remaining buffer space, any excess bytes are discarded.
1036*5225e6b1SAndroid Build Coastguard Worker ///
1037*5225e6b1SAndroid Build Coastguard Worker /// Returns the resulting contents.
append(&mut self, bytes: &[u8]) -> &mut [u8]1038*5225e6b1SAndroid Build Coastguard Worker pub fn append(&mut self, bytes: &[u8]) -> &mut [u8] {
1039*5225e6b1SAndroid Build Coastguard Worker let buf = &mut self.0.as_mut()[self.1..];
1040*5225e6b1SAndroid Build Coastguard Worker // Only write as much as the size of the bytes buffer. Additional write is silently
1041*5225e6b1SAndroid Build Coastguard Worker // ignored.
1042*5225e6b1SAndroid Build Coastguard Worker let to_write = min(buf.len(), bytes.len());
1043*5225e6b1SAndroid Build Coastguard Worker buf[..to_write].clone_from_slice(&bytes[..to_write]);
1044*5225e6b1SAndroid Build Coastguard Worker self.1 += to_write;
1045*5225e6b1SAndroid Build Coastguard Worker &mut self.0.as_mut()[..self.1]
1046*5225e6b1SAndroid Build Coastguard Worker }
1047*5225e6b1SAndroid Build Coastguard Worker }
1048*5225e6b1SAndroid Build Coastguard Worker
1049*5225e6b1SAndroid Build Coastguard Worker impl<T: AsMut<[u8]>> core::fmt::Write for FormattedBytes<T> {
write_str(&mut self, s: &str) -> core::fmt::Result1050*5225e6b1SAndroid Build Coastguard Worker fn write_str(&mut self, s: &str) -> core::fmt::Result {
1051*5225e6b1SAndroid Build Coastguard Worker self.append(s.as_bytes());
1052*5225e6b1SAndroid Build Coastguard Worker Ok(())
1053*5225e6b1SAndroid Build Coastguard Worker }
1054*5225e6b1SAndroid Build Coastguard Worker }
1055*5225e6b1SAndroid Build Coastguard Worker
1056*5225e6b1SAndroid Build Coastguard Worker /// A convenient macro that behaves similar to snprintf in C.
1057*5225e6b1SAndroid Build Coastguard Worker #[macro_export]
1058*5225e6b1SAndroid Build Coastguard Worker macro_rules! snprintf {
1059*5225e6b1SAndroid Build Coastguard Worker ( $arr:expr, $( $x:expr ),* ) => {
1060*5225e6b1SAndroid Build Coastguard Worker {
1061*5225e6b1SAndroid Build Coastguard Worker let mut formatted_bytes = FormattedBytes::new(&mut $arr[..]);
1062*5225e6b1SAndroid Build Coastguard Worker write!(formatted_bytes, $($x,)*).unwrap();
1063*5225e6b1SAndroid Build Coastguard Worker let size = formatted_bytes.size();
1064*5225e6b1SAndroid Build Coastguard Worker from_utf8(&$arr[..size]).unwrap()
1065*5225e6b1SAndroid Build Coastguard Worker }
1066*5225e6b1SAndroid Build Coastguard Worker };
1067*5225e6b1SAndroid Build Coastguard Worker }
1068*5225e6b1SAndroid Build Coastguard Worker
1069*5225e6b1SAndroid Build Coastguard Worker /// A helper to convert a hex string into u64.
hex_to_u64(s: &str) -> CommandResult<u64>1070*5225e6b1SAndroid Build Coastguard Worker pub(crate) fn hex_to_u64(s: &str) -> CommandResult<u64> {
1071*5225e6b1SAndroid Build Coastguard Worker Ok(u64::from_str_radix(s.strip_prefix("0x").unwrap_or(s), 16)?)
1072*5225e6b1SAndroid Build Coastguard Worker }
1073*5225e6b1SAndroid Build Coastguard Worker
1074*5225e6b1SAndroid Build Coastguard Worker /// A helper to check and fetch the next non-empty argument.
1075*5225e6b1SAndroid Build Coastguard Worker ///
1076*5225e6b1SAndroid Build Coastguard Worker /// # Args
1077*5225e6b1SAndroid Build Coastguard Worker ///
1078*5225e6b1SAndroid Build Coastguard Worker /// args: A string iterator.
next_arg<'a, T: Iterator<Item = &'a str>>(args: &mut T) -> Option<&'a str>1079*5225e6b1SAndroid Build Coastguard Worker pub fn next_arg<'a, T: Iterator<Item = &'a str>>(args: &mut T) -> Option<&'a str> {
1080*5225e6b1SAndroid Build Coastguard Worker args.next().filter(|v| *v != "")
1081*5225e6b1SAndroid Build Coastguard Worker }
1082*5225e6b1SAndroid Build Coastguard Worker
1083*5225e6b1SAndroid Build Coastguard Worker /// A helper to check and fetch the next argument as a u64 hex string.
1084*5225e6b1SAndroid Build Coastguard Worker ///
1085*5225e6b1SAndroid Build Coastguard Worker /// # Args
1086*5225e6b1SAndroid Build Coastguard Worker ///
1087*5225e6b1SAndroid Build Coastguard Worker /// args: A string iterator.
1088*5225e6b1SAndroid Build Coastguard Worker ///
1089*5225e6b1SAndroid Build Coastguard Worker ///
1090*5225e6b1SAndroid Build Coastguard Worker /// # Returns
1091*5225e6b1SAndroid Build Coastguard Worker ///
1092*5225e6b1SAndroid Build Coastguard Worker /// * Returns Ok(Some(v)) is next argument is available and a valid u64 hex.
1093*5225e6b1SAndroid Build Coastguard Worker /// * Returns Ok(None) is next argument is not available
1094*5225e6b1SAndroid Build Coastguard Worker /// * Returns Err() if next argument is present but not a valid u64 hex.
next_arg_u64<'a, T: Iterator<Item = &'a str>>(args: &mut T) -> CommandResult<Option<u64>>1095*5225e6b1SAndroid Build Coastguard Worker pub fn next_arg_u64<'a, T: Iterator<Item = &'a str>>(args: &mut T) -> CommandResult<Option<u64>> {
1096*5225e6b1SAndroid Build Coastguard Worker match next_arg(args) {
1097*5225e6b1SAndroid Build Coastguard Worker Some(v) => Ok(Some(hex_to_u64(v)?)),
1098*5225e6b1SAndroid Build Coastguard Worker _ => Ok(None),
1099*5225e6b1SAndroid Build Coastguard Worker }
1100*5225e6b1SAndroid Build Coastguard Worker }
1101*5225e6b1SAndroid Build Coastguard Worker
1102*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
1103*5225e6b1SAndroid Build Coastguard Worker mod test {
1104*5225e6b1SAndroid Build Coastguard Worker use super::*;
1105*5225e6b1SAndroid Build Coastguard Worker use std::collections::{BTreeMap, VecDeque};
1106*5225e6b1SAndroid Build Coastguard Worker
1107*5225e6b1SAndroid Build Coastguard Worker #[derive(Default)]
1108*5225e6b1SAndroid Build Coastguard Worker struct FastbootTest {
1109*5225e6b1SAndroid Build Coastguard Worker // A mapping from (variable name, argument) to variable value.
1110*5225e6b1SAndroid Build Coastguard Worker vars: BTreeMap<(&'static str, &'static [&'static str]), &'static str>,
1111*5225e6b1SAndroid Build Coastguard Worker // The partition arg from Fastboot flash command
1112*5225e6b1SAndroid Build Coastguard Worker flash_partition: String,
1113*5225e6b1SAndroid Build Coastguard Worker // The partition arg from Fastboot erase command
1114*5225e6b1SAndroid Build Coastguard Worker erase_partition: String,
1115*5225e6b1SAndroid Build Coastguard Worker // Upload size, batches of data to upload,
1116*5225e6b1SAndroid Build Coastguard Worker upload_config: (u64, Vec<Vec<u8>>),
1117*5225e6b1SAndroid Build Coastguard Worker // A map from partition name to (upload size override, partition data)
1118*5225e6b1SAndroid Build Coastguard Worker fetch_data: BTreeMap<&'static str, (u64, Vec<u8>)>,
1119*5225e6b1SAndroid Build Coastguard Worker // result string, INFO strings.
1120*5225e6b1SAndroid Build Coastguard Worker oem_output: (String, Vec<String>),
1121*5225e6b1SAndroid Build Coastguard Worker oem_command: String,
1122*5225e6b1SAndroid Build Coastguard Worker download_buffer: Vec<u8>,
1123*5225e6b1SAndroid Build Coastguard Worker downloaded_size: usize,
1124*5225e6b1SAndroid Build Coastguard Worker reboot_mode: Option<RebootMode>,
1125*5225e6b1SAndroid Build Coastguard Worker active_slot: Option<String>,
1126*5225e6b1SAndroid Build Coastguard Worker }
1127*5225e6b1SAndroid Build Coastguard Worker
1128*5225e6b1SAndroid Build Coastguard Worker impl FastbootImplementation for FastbootTest {
get_var( &mut self, var: &CStr, args: impl Iterator<Item = &'_ CStr> + Clone, out: &mut [u8], _: impl InfoSender, ) -> CommandResult<usize>1129*5225e6b1SAndroid Build Coastguard Worker async fn get_var(
1130*5225e6b1SAndroid Build Coastguard Worker &mut self,
1131*5225e6b1SAndroid Build Coastguard Worker var: &CStr,
1132*5225e6b1SAndroid Build Coastguard Worker args: impl Iterator<Item = &'_ CStr> + Clone,
1133*5225e6b1SAndroid Build Coastguard Worker out: &mut [u8],
1134*5225e6b1SAndroid Build Coastguard Worker _: impl InfoSender,
1135*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<usize> {
1136*5225e6b1SAndroid Build Coastguard Worker let args = args.map(|v| v.to_str().unwrap()).collect::<Vec<_>>();
1137*5225e6b1SAndroid Build Coastguard Worker match self.vars.get(&(var.to_str()?, &args[..])) {
1138*5225e6b1SAndroid Build Coastguard Worker Some(v) => {
1139*5225e6b1SAndroid Build Coastguard Worker out[..v.len()].clone_from_slice(v.as_bytes());
1140*5225e6b1SAndroid Build Coastguard Worker Ok(v.len())
1141*5225e6b1SAndroid Build Coastguard Worker }
1142*5225e6b1SAndroid Build Coastguard Worker _ => Err("Not Found".into()),
1143*5225e6b1SAndroid Build Coastguard Worker }
1144*5225e6b1SAndroid Build Coastguard Worker }
1145*5225e6b1SAndroid Build Coastguard Worker
get_var_all(&mut self, mut responder: impl VarInfoSender) -> CommandResult<()>1146*5225e6b1SAndroid Build Coastguard Worker async fn get_var_all(&mut self, mut responder: impl VarInfoSender) -> CommandResult<()> {
1147*5225e6b1SAndroid Build Coastguard Worker for ((var, config), value) in &self.vars {
1148*5225e6b1SAndroid Build Coastguard Worker responder.send_var_info(var, config.iter().copied(), value).await?;
1149*5225e6b1SAndroid Build Coastguard Worker }
1150*5225e6b1SAndroid Build Coastguard Worker Ok(())
1151*5225e6b1SAndroid Build Coastguard Worker }
1152*5225e6b1SAndroid Build Coastguard Worker
get_download_buffer(&mut self) -> &mut [u8]1153*5225e6b1SAndroid Build Coastguard Worker async fn get_download_buffer(&mut self) -> &mut [u8] {
1154*5225e6b1SAndroid Build Coastguard Worker self.download_buffer.as_mut_slice()
1155*5225e6b1SAndroid Build Coastguard Worker }
1156*5225e6b1SAndroid Build Coastguard Worker
download_complete( &mut self, download_size: usize, _: impl InfoSender, ) -> CommandResult<()>1157*5225e6b1SAndroid Build Coastguard Worker async fn download_complete(
1158*5225e6b1SAndroid Build Coastguard Worker &mut self,
1159*5225e6b1SAndroid Build Coastguard Worker download_size: usize,
1160*5225e6b1SAndroid Build Coastguard Worker _: impl InfoSender,
1161*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> {
1162*5225e6b1SAndroid Build Coastguard Worker self.downloaded_size = download_size;
1163*5225e6b1SAndroid Build Coastguard Worker Ok(())
1164*5225e6b1SAndroid Build Coastguard Worker }
1165*5225e6b1SAndroid Build Coastguard Worker
flash(&mut self, part: &str, _: impl InfoSender) -> CommandResult<()>1166*5225e6b1SAndroid Build Coastguard Worker async fn flash(&mut self, part: &str, _: impl InfoSender) -> CommandResult<()> {
1167*5225e6b1SAndroid Build Coastguard Worker self.flash_partition = part.into();
1168*5225e6b1SAndroid Build Coastguard Worker Ok(())
1169*5225e6b1SAndroid Build Coastguard Worker }
1170*5225e6b1SAndroid Build Coastguard Worker
erase(&mut self, part: &str, _: impl InfoSender) -> CommandResult<()>1171*5225e6b1SAndroid Build Coastguard Worker async fn erase(&mut self, part: &str, _: impl InfoSender) -> CommandResult<()> {
1172*5225e6b1SAndroid Build Coastguard Worker self.erase_partition = part.into();
1173*5225e6b1SAndroid Build Coastguard Worker Ok(())
1174*5225e6b1SAndroid Build Coastguard Worker }
1175*5225e6b1SAndroid Build Coastguard Worker
upload(&mut self, responder: impl UploadBuilder) -> CommandResult<()>1176*5225e6b1SAndroid Build Coastguard Worker async fn upload(&mut self, responder: impl UploadBuilder) -> CommandResult<()> {
1177*5225e6b1SAndroid Build Coastguard Worker let (size, batches) = &self.upload_config;
1178*5225e6b1SAndroid Build Coastguard Worker let mut uploader = responder.initiate_upload(*size).await?;
1179*5225e6b1SAndroid Build Coastguard Worker for ele in batches {
1180*5225e6b1SAndroid Build Coastguard Worker uploader.upload(&ele[..]).await?;
1181*5225e6b1SAndroid Build Coastguard Worker }
1182*5225e6b1SAndroid Build Coastguard Worker Ok(())
1183*5225e6b1SAndroid Build Coastguard Worker }
1184*5225e6b1SAndroid Build Coastguard Worker
fetch( &mut self, part: &str, offset: u64, size: u64, responder: impl UploadBuilder + InfoSender, ) -> CommandResult<()>1185*5225e6b1SAndroid Build Coastguard Worker async fn fetch(
1186*5225e6b1SAndroid Build Coastguard Worker &mut self,
1187*5225e6b1SAndroid Build Coastguard Worker part: &str,
1188*5225e6b1SAndroid Build Coastguard Worker offset: u64,
1189*5225e6b1SAndroid Build Coastguard Worker size: u64,
1190*5225e6b1SAndroid Build Coastguard Worker responder: impl UploadBuilder + InfoSender,
1191*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> {
1192*5225e6b1SAndroid Build Coastguard Worker let (size_override, data) = self.fetch_data.get(part).ok_or("Not Found")?;
1193*5225e6b1SAndroid Build Coastguard Worker let mut uploader = responder.initiate_upload(*size_override).await?;
1194*5225e6b1SAndroid Build Coastguard Worker Ok(uploader
1195*5225e6b1SAndroid Build Coastguard Worker .upload(&data[offset.try_into().unwrap()..][..size.try_into().unwrap()])
1196*5225e6b1SAndroid Build Coastguard Worker .await?)
1197*5225e6b1SAndroid Build Coastguard Worker }
1198*5225e6b1SAndroid Build Coastguard Worker
boot(&mut self, mut responder: impl InfoSender + OkaySender) -> CommandResult<()>1199*5225e6b1SAndroid Build Coastguard Worker async fn boot(&mut self, mut responder: impl InfoSender + OkaySender) -> CommandResult<()> {
1200*5225e6b1SAndroid Build Coastguard Worker Ok(responder.send_info("Boot to boot.img...").await?)
1201*5225e6b1SAndroid Build Coastguard Worker }
1202*5225e6b1SAndroid Build Coastguard Worker
reboot( &mut self, mode: RebootMode, responder: impl InfoSender + OkaySender, ) -> CommandError1203*5225e6b1SAndroid Build Coastguard Worker async fn reboot(
1204*5225e6b1SAndroid Build Coastguard Worker &mut self,
1205*5225e6b1SAndroid Build Coastguard Worker mode: RebootMode,
1206*5225e6b1SAndroid Build Coastguard Worker responder: impl InfoSender + OkaySender,
1207*5225e6b1SAndroid Build Coastguard Worker ) -> CommandError {
1208*5225e6b1SAndroid Build Coastguard Worker responder.send_okay("").await.unwrap();
1209*5225e6b1SAndroid Build Coastguard Worker self.reboot_mode = Some(mode);
1210*5225e6b1SAndroid Build Coastguard Worker "reboot-return".into()
1211*5225e6b1SAndroid Build Coastguard Worker }
1212*5225e6b1SAndroid Build Coastguard Worker
1213*5225e6b1SAndroid Build Coastguard Worker async fn r#continue(&mut self, mut responder: impl InfoSender) -> CommandResult<()> {
1214*5225e6b1SAndroid Build Coastguard Worker Ok(responder.send_info("Continuing to boot...").await?)
1215*5225e6b1SAndroid Build Coastguard Worker }
1216*5225e6b1SAndroid Build Coastguard Worker
set_active(&mut self, slot: &str, _: impl InfoSender) -> CommandResult<()>1217*5225e6b1SAndroid Build Coastguard Worker async fn set_active(&mut self, slot: &str, _: impl InfoSender) -> CommandResult<()> {
1218*5225e6b1SAndroid Build Coastguard Worker self.active_slot = Some(slot.into());
1219*5225e6b1SAndroid Build Coastguard Worker Ok(())
1220*5225e6b1SAndroid Build Coastguard Worker }
1221*5225e6b1SAndroid Build Coastguard Worker
oem<'b>( &mut self, cmd: &str, mut responder: impl InfoSender, res: &'b mut [u8], ) -> CommandResult<&'b [u8]>1222*5225e6b1SAndroid Build Coastguard Worker async fn oem<'b>(
1223*5225e6b1SAndroid Build Coastguard Worker &mut self,
1224*5225e6b1SAndroid Build Coastguard Worker cmd: &str,
1225*5225e6b1SAndroid Build Coastguard Worker mut responder: impl InfoSender,
1226*5225e6b1SAndroid Build Coastguard Worker res: &'b mut [u8],
1227*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'b [u8]> {
1228*5225e6b1SAndroid Build Coastguard Worker let (res_str, infos) = &mut self.oem_output;
1229*5225e6b1SAndroid Build Coastguard Worker self.oem_command = cmd.into();
1230*5225e6b1SAndroid Build Coastguard Worker for ele in infos {
1231*5225e6b1SAndroid Build Coastguard Worker responder.send_info(ele.as_str()).await?;
1232*5225e6b1SAndroid Build Coastguard Worker }
1233*5225e6b1SAndroid Build Coastguard Worker Ok(snprintf!(res, "{}", *res_str).as_bytes())
1234*5225e6b1SAndroid Build Coastguard Worker }
1235*5225e6b1SAndroid Build Coastguard Worker }
1236*5225e6b1SAndroid Build Coastguard Worker
1237*5225e6b1SAndroid Build Coastguard Worker struct TestTransport {
1238*5225e6b1SAndroid Build Coastguard Worker in_queue: VecDeque<Vec<u8>>,
1239*5225e6b1SAndroid Build Coastguard Worker out_queue: VecDeque<Vec<u8>>,
1240*5225e6b1SAndroid Build Coastguard Worker }
1241*5225e6b1SAndroid Build Coastguard Worker
1242*5225e6b1SAndroid Build Coastguard Worker impl TestTransport {
new() -> Self1243*5225e6b1SAndroid Build Coastguard Worker fn new() -> Self {
1244*5225e6b1SAndroid Build Coastguard Worker Self { in_queue: VecDeque::new(), out_queue: VecDeque::new() }
1245*5225e6b1SAndroid Build Coastguard Worker }
1246*5225e6b1SAndroid Build Coastguard Worker
add_input(&mut self, packet: &[u8])1247*5225e6b1SAndroid Build Coastguard Worker fn add_input(&mut self, packet: &[u8]) {
1248*5225e6b1SAndroid Build Coastguard Worker self.in_queue.push_back(packet.into());
1249*5225e6b1SAndroid Build Coastguard Worker }
1250*5225e6b1SAndroid Build Coastguard Worker }
1251*5225e6b1SAndroid Build Coastguard Worker
1252*5225e6b1SAndroid Build Coastguard Worker impl Transport for TestTransport {
receive_packet(&mut self, out: &mut [u8]) -> Result<usize>1253*5225e6b1SAndroid Build Coastguard Worker async fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize> {
1254*5225e6b1SAndroid Build Coastguard Worker match self.in_queue.pop_front() {
1255*5225e6b1SAndroid Build Coastguard Worker Some(v) => {
1256*5225e6b1SAndroid Build Coastguard Worker let size = min(out.len(), v.len());
1257*5225e6b1SAndroid Build Coastguard Worker out[..size].clone_from_slice(&v[..size]);
1258*5225e6b1SAndroid Build Coastguard Worker // Returns the input length so that we can test bogus download size.
1259*5225e6b1SAndroid Build Coastguard Worker Ok(v.len())
1260*5225e6b1SAndroid Build Coastguard Worker }
1261*5225e6b1SAndroid Build Coastguard Worker _ => Err(Error::Other(Some("No more data"))),
1262*5225e6b1SAndroid Build Coastguard Worker }
1263*5225e6b1SAndroid Build Coastguard Worker }
1264*5225e6b1SAndroid Build Coastguard Worker
send_packet(&mut self, packet: &[u8]) -> Result<()>1265*5225e6b1SAndroid Build Coastguard Worker async fn send_packet(&mut self, packet: &[u8]) -> Result<()> {
1266*5225e6b1SAndroid Build Coastguard Worker self.out_queue.push_back(packet.into());
1267*5225e6b1SAndroid Build Coastguard Worker Ok(())
1268*5225e6b1SAndroid Build Coastguard Worker }
1269*5225e6b1SAndroid Build Coastguard Worker }
1270*5225e6b1SAndroid Build Coastguard Worker
1271*5225e6b1SAndroid Build Coastguard Worker #[derive(Default)]
1272*5225e6b1SAndroid Build Coastguard Worker struct TestTcpStream {
1273*5225e6b1SAndroid Build Coastguard Worker in_queue: VecDeque<u8>,
1274*5225e6b1SAndroid Build Coastguard Worker out_queue: VecDeque<u8>,
1275*5225e6b1SAndroid Build Coastguard Worker }
1276*5225e6b1SAndroid Build Coastguard Worker
1277*5225e6b1SAndroid Build Coastguard Worker impl TestTcpStream {
1278*5225e6b1SAndroid Build Coastguard Worker /// Adds bytes to input stream.
add_input(&mut self, data: &[u8])1279*5225e6b1SAndroid Build Coastguard Worker fn add_input(&mut self, data: &[u8]) {
1280*5225e6b1SAndroid Build Coastguard Worker data.iter().for_each(|v| self.in_queue.push_back(*v));
1281*5225e6b1SAndroid Build Coastguard Worker }
1282*5225e6b1SAndroid Build Coastguard Worker
1283*5225e6b1SAndroid Build Coastguard Worker /// Adds a length pre-fixed bytes stream.
add_length_prefixed_input(&mut self, data: &[u8])1284*5225e6b1SAndroid Build Coastguard Worker fn add_length_prefixed_input(&mut self, data: &[u8]) {
1285*5225e6b1SAndroid Build Coastguard Worker self.add_input(&(data.len() as u64).to_be_bytes());
1286*5225e6b1SAndroid Build Coastguard Worker self.add_input(data);
1287*5225e6b1SAndroid Build Coastguard Worker }
1288*5225e6b1SAndroid Build Coastguard Worker }
1289*5225e6b1SAndroid Build Coastguard Worker
1290*5225e6b1SAndroid Build Coastguard Worker impl TcpStream for TestTcpStream {
read_exact(&mut self, out: &mut [u8]) -> Result<()>1291*5225e6b1SAndroid Build Coastguard Worker async fn read_exact(&mut self, out: &mut [u8]) -> Result<()> {
1292*5225e6b1SAndroid Build Coastguard Worker for ele in out {
1293*5225e6b1SAndroid Build Coastguard Worker *ele = self.in_queue.pop_front().ok_or(Error::OperationProhibited)?;
1294*5225e6b1SAndroid Build Coastguard Worker }
1295*5225e6b1SAndroid Build Coastguard Worker Ok(())
1296*5225e6b1SAndroid Build Coastguard Worker }
1297*5225e6b1SAndroid Build Coastguard Worker
write_exact(&mut self, data: &[u8]) -> Result<()>1298*5225e6b1SAndroid Build Coastguard Worker async fn write_exact(&mut self, data: &[u8]) -> Result<()> {
1299*5225e6b1SAndroid Build Coastguard Worker data.iter().for_each(|v| self.out_queue.push_back(*v));
1300*5225e6b1SAndroid Build Coastguard Worker Ok(())
1301*5225e6b1SAndroid Build Coastguard Worker }
1302*5225e6b1SAndroid Build Coastguard Worker }
1303*5225e6b1SAndroid Build Coastguard Worker
1304*5225e6b1SAndroid Build Coastguard Worker #[test]
test_boot()1305*5225e6b1SAndroid Build Coastguard Worker fn test_boot() {
1306*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1307*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1308*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1309*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"boot");
1310*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1311*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1312*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1313*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1314*5225e6b1SAndroid Build Coastguard Worker b"INFOBoot to boot.img...".into(),
1315*5225e6b1SAndroid Build Coastguard Worker b"OKAYboot_command".into()
1316*5225e6b1SAndroid Build Coastguard Worker ])
1317*5225e6b1SAndroid Build Coastguard Worker );
1318*5225e6b1SAndroid Build Coastguard Worker }
1319*5225e6b1SAndroid Build Coastguard Worker
1320*5225e6b1SAndroid Build Coastguard Worker #[test]
test_non_exist_command()1321*5225e6b1SAndroid Build Coastguard Worker fn test_non_exist_command() {
1322*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1323*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1324*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1325*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"non_exist");
1326*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1327*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"FAILCommand not found"]);
1328*5225e6b1SAndroid Build Coastguard Worker }
1329*5225e6b1SAndroid Build Coastguard Worker
1330*5225e6b1SAndroid Build Coastguard Worker #[test]
test_non_ascii_command_string()1331*5225e6b1SAndroid Build Coastguard Worker fn test_non_ascii_command_string() {
1332*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1333*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1334*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1335*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"\xff\xff\xff");
1336*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1337*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"FAILInvalid Command"]);
1338*5225e6b1SAndroid Build Coastguard Worker }
1339*5225e6b1SAndroid Build Coastguard Worker
1340*5225e6b1SAndroid Build Coastguard Worker #[test]
test_get_var_max_download_size()1341*5225e6b1SAndroid Build Coastguard Worker fn test_get_var_max_download_size() {
1342*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1343*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1344*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1345*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:max-download-size");
1346*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1347*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"OKAY0x400"]);
1348*5225e6b1SAndroid Build Coastguard Worker }
1349*5225e6b1SAndroid Build Coastguard Worker
1350*5225e6b1SAndroid Build Coastguard Worker #[test]
test_get_var()1351*5225e6b1SAndroid Build Coastguard Worker fn test_get_var() {
1352*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1353*5225e6b1SAndroid Build Coastguard Worker let vars: [((&str, &[&str]), &str); 4] = [
1354*5225e6b1SAndroid Build Coastguard Worker (("var_0", &[]), "val_0"),
1355*5225e6b1SAndroid Build Coastguard Worker (("var_1", &["a", "b"]), "val_1_a_b"),
1356*5225e6b1SAndroid Build Coastguard Worker (("var_1", &["c", "d"]), "val_1_c_d"),
1357*5225e6b1SAndroid Build Coastguard Worker (("var_2", &["e", "f"]), "val_2_e_f"),
1358*5225e6b1SAndroid Build Coastguard Worker ];
1359*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.vars = BTreeMap::from(vars);
1360*5225e6b1SAndroid Build Coastguard Worker
1361*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1362*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1363*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_0");
1364*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_1:a:b");
1365*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_1:c:d");
1366*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_1"); // Not Found
1367*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_2:e:f");
1368*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:var_3"); // Not Found
1369*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar"); // Not Found
1370*5225e6b1SAndroid Build Coastguard Worker
1371*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1372*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1373*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1374*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1375*5225e6b1SAndroid Build Coastguard Worker b"OKAYval_0".into(),
1376*5225e6b1SAndroid Build Coastguard Worker b"OKAYval_1_a_b".into(),
1377*5225e6b1SAndroid Build Coastguard Worker b"OKAYval_1_c_d".into(),
1378*5225e6b1SAndroid Build Coastguard Worker b"FAILNot Found".into(),
1379*5225e6b1SAndroid Build Coastguard Worker b"OKAYval_2_e_f".into(),
1380*5225e6b1SAndroid Build Coastguard Worker b"FAILNot Found".into(),
1381*5225e6b1SAndroid Build Coastguard Worker b"FAILMissing variable".into(),
1382*5225e6b1SAndroid Build Coastguard Worker ])
1383*5225e6b1SAndroid Build Coastguard Worker );
1384*5225e6b1SAndroid Build Coastguard Worker }
1385*5225e6b1SAndroid Build Coastguard Worker
1386*5225e6b1SAndroid Build Coastguard Worker #[test]
test_get_var_all()1387*5225e6b1SAndroid Build Coastguard Worker fn test_get_var_all() {
1388*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1389*5225e6b1SAndroid Build Coastguard Worker let vars: [((&str, &[&str]), &str); 4] = [
1390*5225e6b1SAndroid Build Coastguard Worker (("var_0", &[]), "val_0"),
1391*5225e6b1SAndroid Build Coastguard Worker (("var_1", &["a", "b"]), "val_1_a_b"),
1392*5225e6b1SAndroid Build Coastguard Worker (("var_1", &["c", "d"]), "val_1_c_d"),
1393*5225e6b1SAndroid Build Coastguard Worker (("var_2", &["e", "f"]), "val_2_e_f"),
1394*5225e6b1SAndroid Build Coastguard Worker ];
1395*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.vars = BTreeMap::from(vars);
1396*5225e6b1SAndroid Build Coastguard Worker
1397*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1398*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1399*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:all");
1400*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1401*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1402*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1403*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1404*5225e6b1SAndroid Build Coastguard Worker b"INFOmax-download-size: 0x400".into(),
1405*5225e6b1SAndroid Build Coastguard Worker b"INFOvar_0: val_0".into(),
1406*5225e6b1SAndroid Build Coastguard Worker b"INFOvar_1:a:b: val_1_a_b".into(),
1407*5225e6b1SAndroid Build Coastguard Worker b"INFOvar_1:c:d: val_1_c_d".into(),
1408*5225e6b1SAndroid Build Coastguard Worker b"INFOvar_2:e:f: val_2_e_f".into(),
1409*5225e6b1SAndroid Build Coastguard Worker b"OKAY".into(),
1410*5225e6b1SAndroid Build Coastguard Worker ])
1411*5225e6b1SAndroid Build Coastguard Worker );
1412*5225e6b1SAndroid Build Coastguard Worker }
1413*5225e6b1SAndroid Build Coastguard Worker
1414*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download()1415*5225e6b1SAndroid Build Coastguard Worker fn test_download() {
1416*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1417*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1418*5225e6b1SAndroid Build Coastguard Worker let download_content: Vec<u8> =
1419*5225e6b1SAndroid Build Coastguard Worker (0..fastboot_impl.download_buffer.len()).into_iter().map(|v| v as u8).collect();
1420*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1421*5225e6b1SAndroid Build Coastguard Worker // Splits download into two batches.
1422*5225e6b1SAndroid Build Coastguard Worker let (first, second) = download_content.as_slice().split_at(download_content.len() / 2);
1423*5225e6b1SAndroid Build Coastguard Worker transport.add_input(format!("download:{:#x}", download_content.len()).as_bytes());
1424*5225e6b1SAndroid Build Coastguard Worker transport.add_input(first);
1425*5225e6b1SAndroid Build Coastguard Worker transport.add_input(second);
1426*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1427*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1428*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1429*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([b"DATA00000400".into(), b"OKAY".into(),])
1430*5225e6b1SAndroid Build Coastguard Worker );
1431*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.downloaded_size, download_content.len());
1432*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.download_buffer, download_content);
1433*5225e6b1SAndroid Build Coastguard Worker }
1434*5225e6b1SAndroid Build Coastguard Worker
1435*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download_not_enough_args()1436*5225e6b1SAndroid Build Coastguard Worker fn test_download_not_enough_args() {
1437*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1438*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1439*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1440*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"download");
1441*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1442*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"FAILNot enough argument"]);
1443*5225e6b1SAndroid Build Coastguard Worker }
1444*5225e6b1SAndroid Build Coastguard Worker
1445*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download_invalid_hex_string()1446*5225e6b1SAndroid Build Coastguard Worker fn test_download_invalid_hex_string() {
1447*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1448*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1449*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1450*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"download:hhh");
1451*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1452*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue.len(), 1);
1453*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue[0].starts_with(b"FAIL"));
1454*5225e6b1SAndroid Build Coastguard Worker }
1455*5225e6b1SAndroid Build Coastguard Worker
test_download_size(download_buffer_size: usize, download_size: usize, msg: &str)1456*5225e6b1SAndroid Build Coastguard Worker fn test_download_size(download_buffer_size: usize, download_size: usize, msg: &str) {
1457*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1458*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; download_buffer_size];
1459*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1460*5225e6b1SAndroid Build Coastguard Worker transport.add_input(format!("download:{:#x}", download_size).as_bytes());
1461*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1462*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([msg.as_bytes().into()]));
1463*5225e6b1SAndroid Build Coastguard Worker }
1464*5225e6b1SAndroid Build Coastguard Worker
1465*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download_download_size_too_big()1466*5225e6b1SAndroid Build Coastguard Worker fn test_download_download_size_too_big() {
1467*5225e6b1SAndroid Build Coastguard Worker test_download_size(1024, 1025, "FAILDownload size is too big");
1468*5225e6b1SAndroid Build Coastguard Worker }
1469*5225e6b1SAndroid Build Coastguard Worker
1470*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download_zero_download_size()1471*5225e6b1SAndroid Build Coastguard Worker fn test_download_zero_download_size() {
1472*5225e6b1SAndroid Build Coastguard Worker test_download_size(1024, 0, "FAILZero download size");
1473*5225e6b1SAndroid Build Coastguard Worker }
1474*5225e6b1SAndroid Build Coastguard Worker
1475*5225e6b1SAndroid Build Coastguard Worker #[test]
test_download_more_than_expected()1476*5225e6b1SAndroid Build Coastguard Worker fn test_download_more_than_expected() {
1477*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1478*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1479*5225e6b1SAndroid Build Coastguard Worker let download_content: Vec<u8> = vec![0u8; fastboot_impl.download_buffer.len()];
1480*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1481*5225e6b1SAndroid Build Coastguard Worker transport.add_input(format!("download:{:#x}", download_content.len() - 1).as_bytes());
1482*5225e6b1SAndroid Build Coastguard Worker transport.add_input(&download_content[..]);
1483*5225e6b1SAndroid Build Coastguard Worker // State should be reset to command state.
1484*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:max-download-size");
1485*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1486*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1487*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1488*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1489*5225e6b1SAndroid Build Coastguard Worker b"DATA000003ff".into(),
1490*5225e6b1SAndroid Build Coastguard Worker b"FAILMore data received then expected".into(),
1491*5225e6b1SAndroid Build Coastguard Worker b"OKAY0x400".into(),
1492*5225e6b1SAndroid Build Coastguard Worker ])
1493*5225e6b1SAndroid Build Coastguard Worker );
1494*5225e6b1SAndroid Build Coastguard Worker }
1495*5225e6b1SAndroid Build Coastguard Worker
1496*5225e6b1SAndroid Build Coastguard Worker #[test]
test_oem_cmd()1497*5225e6b1SAndroid Build Coastguard Worker fn test_oem_cmd() {
1498*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1499*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1500*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1501*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"oem oem-command");
1502*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.oem_output =
1503*5225e6b1SAndroid Build Coastguard Worker ("oem-return".into(), vec!["oem-info-1".into(), "oem-info-2".into()]);
1504*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1505*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.oem_command, "oem-command");
1506*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1507*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1508*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1509*5225e6b1SAndroid Build Coastguard Worker b"INFOoem-info-1".into(),
1510*5225e6b1SAndroid Build Coastguard Worker b"INFOoem-info-2".into(),
1511*5225e6b1SAndroid Build Coastguard Worker b"OKAYoem-return".into(),
1512*5225e6b1SAndroid Build Coastguard Worker ])
1513*5225e6b1SAndroid Build Coastguard Worker );
1514*5225e6b1SAndroid Build Coastguard Worker }
1515*5225e6b1SAndroid Build Coastguard Worker
1516*5225e6b1SAndroid Build Coastguard Worker #[test]
test_flash()1517*5225e6b1SAndroid Build Coastguard Worker fn test_flash() {
1518*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1519*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1520*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1521*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"flash:boot_a:0::");
1522*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1523*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.flash_partition, "boot_a:0::");
1524*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([b"OKAY".into()]));
1525*5225e6b1SAndroid Build Coastguard Worker }
1526*5225e6b1SAndroid Build Coastguard Worker
1527*5225e6b1SAndroid Build Coastguard Worker #[test]
test_flash_missing_partition()1528*5225e6b1SAndroid Build Coastguard Worker fn test_flash_missing_partition() {
1529*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1530*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1531*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"flash");
1532*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1533*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"FAILMissing partition"]);
1534*5225e6b1SAndroid Build Coastguard Worker }
1535*5225e6b1SAndroid Build Coastguard Worker
1536*5225e6b1SAndroid Build Coastguard Worker #[test]
test_erase()1537*5225e6b1SAndroid Build Coastguard Worker fn test_erase() {
1538*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1539*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1540*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1541*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"erase:boot_a:0::");
1542*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1543*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.erase_partition, "boot_a:0::");
1544*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([b"OKAY".into()]));
1545*5225e6b1SAndroid Build Coastguard Worker }
1546*5225e6b1SAndroid Build Coastguard Worker
1547*5225e6b1SAndroid Build Coastguard Worker #[test]
test_erase_missing_partition()1548*5225e6b1SAndroid Build Coastguard Worker fn test_erase_missing_partition() {
1549*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1550*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1551*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"erase");
1552*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1553*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, [b"FAILMissing partition"]);
1554*5225e6b1SAndroid Build Coastguard Worker }
1555*5225e6b1SAndroid Build Coastguard Worker
1556*5225e6b1SAndroid Build Coastguard Worker #[test]
test_upload()1557*5225e6b1SAndroid Build Coastguard Worker fn test_upload() {
1558*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1559*5225e6b1SAndroid Build Coastguard Worker let upload_content: Vec<u8> = (0..1024).into_iter().map(|v| v as u8).collect();
1560*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1561*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"upload");
1562*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.upload_config = (
1563*5225e6b1SAndroid Build Coastguard Worker upload_content.len().try_into().unwrap(),
1564*5225e6b1SAndroid Build Coastguard Worker vec![
1565*5225e6b1SAndroid Build Coastguard Worker upload_content[..upload_content.len() / 2].to_vec(),
1566*5225e6b1SAndroid Build Coastguard Worker upload_content[upload_content.len() / 2..].to_vec(),
1567*5225e6b1SAndroid Build Coastguard Worker ],
1568*5225e6b1SAndroid Build Coastguard Worker );
1569*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1570*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1571*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1572*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1573*5225e6b1SAndroid Build Coastguard Worker b"DATA00000400".into(),
1574*5225e6b1SAndroid Build Coastguard Worker upload_content[..upload_content.len() / 2].to_vec(),
1575*5225e6b1SAndroid Build Coastguard Worker upload_content[upload_content.len() / 2..].to_vec(),
1576*5225e6b1SAndroid Build Coastguard Worker b"OKAY".into(),
1577*5225e6b1SAndroid Build Coastguard Worker ])
1578*5225e6b1SAndroid Build Coastguard Worker );
1579*5225e6b1SAndroid Build Coastguard Worker }
1580*5225e6b1SAndroid Build Coastguard Worker
1581*5225e6b1SAndroid Build Coastguard Worker #[test]
test_upload_not_enough_data()1582*5225e6b1SAndroid Build Coastguard Worker fn test_upload_not_enough_data() {
1583*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1584*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1585*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1586*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"upload");
1587*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.upload_config = (0x400, vec![vec![0u8; 0x400 - 1]]);
1588*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(run(&mut transport, &mut fastboot_impl)).is_err());
1589*5225e6b1SAndroid Build Coastguard Worker }
1590*5225e6b1SAndroid Build Coastguard Worker
1591*5225e6b1SAndroid Build Coastguard Worker #[test]
test_upload_more_data()1592*5225e6b1SAndroid Build Coastguard Worker fn test_upload_more_data() {
1593*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1594*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1595*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1596*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"upload");
1597*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.upload_config = (0x400, vec![vec![0u8; 0x400 + 1]]);
1598*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(run(&mut transport, &mut fastboot_impl)).is_err());
1599*5225e6b1SAndroid Build Coastguard Worker }
1600*5225e6b1SAndroid Build Coastguard Worker
1601*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fetch()1602*5225e6b1SAndroid Build Coastguard Worker fn test_fetch() {
1603*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1604*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1605*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1606*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:0:::200:400");
1607*5225e6b1SAndroid Build Coastguard Worker fastboot_impl
1608*5225e6b1SAndroid Build Coastguard Worker .fetch_data
1609*5225e6b1SAndroid Build Coastguard Worker .insert("boot_a:0::", (0x400, vec![vec![0u8; 0x200], vec![1u8; 0x400]].concat()));
1610*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1611*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1612*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1613*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1614*5225e6b1SAndroid Build Coastguard Worker b"DATA00000400".into(),
1615*5225e6b1SAndroid Build Coastguard Worker [1u8; 0x400].to_vec(),
1616*5225e6b1SAndroid Build Coastguard Worker b"OKAY".into(),
1617*5225e6b1SAndroid Build Coastguard Worker ])
1618*5225e6b1SAndroid Build Coastguard Worker );
1619*5225e6b1SAndroid Build Coastguard Worker }
1620*5225e6b1SAndroid Build Coastguard Worker
1621*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fetch_not_enough_data()1622*5225e6b1SAndroid Build Coastguard Worker fn test_fetch_not_enough_data() {
1623*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1624*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1625*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1626*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:0:::200:400");
1627*5225e6b1SAndroid Build Coastguard Worker fastboot_impl
1628*5225e6b1SAndroid Build Coastguard Worker .fetch_data
1629*5225e6b1SAndroid Build Coastguard Worker .insert("boot_a:0::", (0x400 - 1, vec![vec![0u8; 0x200], vec![1u8; 0x400]].concat()));
1630*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(process_next_command(&mut transport, &mut fastboot_impl)).is_err());
1631*5225e6b1SAndroid Build Coastguard Worker }
1632*5225e6b1SAndroid Build Coastguard Worker
1633*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fetch_more_data()1634*5225e6b1SAndroid Build Coastguard Worker fn test_fetch_more_data() {
1635*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1636*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1637*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1638*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:0:::200:400");
1639*5225e6b1SAndroid Build Coastguard Worker fastboot_impl
1640*5225e6b1SAndroid Build Coastguard Worker .fetch_data
1641*5225e6b1SAndroid Build Coastguard Worker .insert("boot_a:0::", (0x400 + 1, vec![vec![0u8; 0x200], vec![1u8; 0x400]].concat()));
1642*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(process_next_command(&mut transport, &mut fastboot_impl)).is_err());
1643*5225e6b1SAndroid Build Coastguard Worker }
1644*5225e6b1SAndroid Build Coastguard Worker
1645*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fetch_invalid_args()1646*5225e6b1SAndroid Build Coastguard Worker fn test_fetch_invalid_args() {
1647*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1648*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 2048];
1649*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1650*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch");
1651*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:");
1652*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a");
1653*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:200");
1654*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a::400");
1655*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a::");
1656*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:xxx:400");
1657*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"fetch:boot_a:200:xxx");
1658*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run(&mut transport, &mut fastboot_impl));
1659*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue.iter().all(|v| v.starts_with(b"FAIL")));
1660*5225e6b1SAndroid Build Coastguard Worker }
1661*5225e6b1SAndroid Build Coastguard Worker
1662*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fastboot_tcp()1663*5225e6b1SAndroid Build Coastguard Worker fn test_fastboot_tcp() {
1664*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1665*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1666*5225e6b1SAndroid Build Coastguard Worker let download_content: Vec<u8> =
1667*5225e6b1SAndroid Build Coastguard Worker (0..fastboot_impl.download_buffer.len()).into_iter().map(|v| v as u8).collect();
1668*5225e6b1SAndroid Build Coastguard Worker let mut tcp_stream: TestTcpStream = Default::default();
1669*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_input(TCP_HANDSHAKE_MESSAGE);
1670*5225e6b1SAndroid Build Coastguard Worker // Add two commands and verify both are executed.
1671*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_length_prefixed_input(b"getvar:max-download-size");
1672*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_length_prefixed_input(
1673*5225e6b1SAndroid Build Coastguard Worker format!("download:{:#x}", download_content.len()).as_bytes(),
1674*5225e6b1SAndroid Build Coastguard Worker );
1675*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_length_prefixed_input(&download_content[..]);
1676*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(run_tcp_session(&mut tcp_stream, &mut fastboot_impl));
1677*5225e6b1SAndroid Build Coastguard Worker let expected: &[&[u8]] = &[
1678*5225e6b1SAndroid Build Coastguard Worker b"FB01",
1679*5225e6b1SAndroid Build Coastguard Worker b"\x00\x00\x00\x00\x00\x00\x00\x09OKAY0x400",
1680*5225e6b1SAndroid Build Coastguard Worker b"\x00\x00\x00\x00\x00\x00\x00\x0cDATA00000400",
1681*5225e6b1SAndroid Build Coastguard Worker b"\x00\x00\x00\x00\x00\x00\x00\x04OKAY",
1682*5225e6b1SAndroid Build Coastguard Worker ];
1683*5225e6b1SAndroid Build Coastguard Worker assert_eq!(tcp_stream.out_queue, VecDeque::from(expected.concat()));
1684*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.download_buffer, download_content);
1685*5225e6b1SAndroid Build Coastguard Worker }
1686*5225e6b1SAndroid Build Coastguard Worker
1687*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fastboot_tcp_invalid_handshake()1688*5225e6b1SAndroid Build Coastguard Worker fn test_fastboot_tcp_invalid_handshake() {
1689*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1690*5225e6b1SAndroid Build Coastguard Worker let mut tcp_stream: TestTcpStream = Default::default();
1691*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_input(b"ABCD");
1692*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1693*5225e6b1SAndroid Build Coastguard Worker block_on(run_tcp_session(&mut tcp_stream, &mut fastboot_impl)).unwrap_err(),
1694*5225e6b1SAndroid Build Coastguard Worker Error::InvalidHandshake
1695*5225e6b1SAndroid Build Coastguard Worker );
1696*5225e6b1SAndroid Build Coastguard Worker }
1697*5225e6b1SAndroid Build Coastguard Worker
1698*5225e6b1SAndroid Build Coastguard Worker #[test]
test_fastboot_tcp_packet_size_exceeds_maximum()1699*5225e6b1SAndroid Build Coastguard Worker fn test_fastboot_tcp_packet_size_exceeds_maximum() {
1700*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1701*5225e6b1SAndroid Build Coastguard Worker let mut tcp_stream: TestTcpStream = Default::default();
1702*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_input(TCP_HANDSHAKE_MESSAGE);
1703*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_input(&(MAX_COMMAND_SIZE + 1).to_be_bytes());
1704*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1705*5225e6b1SAndroid Build Coastguard Worker block_on(run_tcp_session(&mut tcp_stream, &mut fastboot_impl)).unwrap_err(),
1706*5225e6b1SAndroid Build Coastguard Worker Error::InvalidInput
1707*5225e6b1SAndroid Build Coastguard Worker );
1708*5225e6b1SAndroid Build Coastguard Worker }
1709*5225e6b1SAndroid Build Coastguard Worker
1710*5225e6b1SAndroid Build Coastguard Worker #[test]
test_reboot()1711*5225e6b1SAndroid Build Coastguard Worker fn test_reboot() {
1712*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1713*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1714*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"reboot");
1715*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1716*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.reboot_mode, Some(RebootMode::Normal));
1717*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue[0], b"OKAY");
1718*5225e6b1SAndroid Build Coastguard Worker // Failure is expected here because test reboot implementation always returns, which
1719*5225e6b1SAndroid Build Coastguard Worker // automatically generates a fastboot failure packet.
1720*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue[1].starts_with(b"FAIL"));
1721*5225e6b1SAndroid Build Coastguard Worker }
1722*5225e6b1SAndroid Build Coastguard Worker
1723*5225e6b1SAndroid Build Coastguard Worker #[test]
test_reboot_bootloader()1724*5225e6b1SAndroid Build Coastguard Worker fn test_reboot_bootloader() {
1725*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1726*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1727*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"reboot-bootloader");
1728*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1729*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.reboot_mode, Some(RebootMode::Bootloader));
1730*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue[0], b"OKAY");
1731*5225e6b1SAndroid Build Coastguard Worker // Failure is expected here because test reboot implementation always returns, which
1732*5225e6b1SAndroid Build Coastguard Worker // automatically generates a fastboot failure packet.
1733*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue[1].starts_with(b"FAIL"));
1734*5225e6b1SAndroid Build Coastguard Worker }
1735*5225e6b1SAndroid Build Coastguard Worker
1736*5225e6b1SAndroid Build Coastguard Worker #[test]
test_reboot_fastboot()1737*5225e6b1SAndroid Build Coastguard Worker fn test_reboot_fastboot() {
1738*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1739*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1740*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"reboot-fastboot");
1741*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1742*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.reboot_mode, Some(RebootMode::Fastboot));
1743*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue[0], b"OKAY");
1744*5225e6b1SAndroid Build Coastguard Worker // Failure is expected here because test reboot implementation always returns, which
1745*5225e6b1SAndroid Build Coastguard Worker // automatically generates a fastboot failure packet.
1746*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue[1].starts_with(b"FAIL"));
1747*5225e6b1SAndroid Build Coastguard Worker }
1748*5225e6b1SAndroid Build Coastguard Worker
1749*5225e6b1SAndroid Build Coastguard Worker #[test]
test_reboot_recovery()1750*5225e6b1SAndroid Build Coastguard Worker fn test_reboot_recovery() {
1751*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1752*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1753*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"reboot-recovery");
1754*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1755*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.reboot_mode, Some(RebootMode::Recovery));
1756*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue[0], b"OKAY");
1757*5225e6b1SAndroid Build Coastguard Worker // Failure is expected here because test reboot implementation always returns, which
1758*5225e6b1SAndroid Build Coastguard Worker // automatically generates a fastboot failure packet.
1759*5225e6b1SAndroid Build Coastguard Worker assert!(transport.out_queue[1].starts_with(b"FAIL"));
1760*5225e6b1SAndroid Build Coastguard Worker }
1761*5225e6b1SAndroid Build Coastguard Worker
1762*5225e6b1SAndroid Build Coastguard Worker #[test]
test_continue()1763*5225e6b1SAndroid Build Coastguard Worker fn test_continue() {
1764*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1765*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1766*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1767*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:max-download-size");
1768*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"continue");
1769*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"getvar:max-download-size");
1770*5225e6b1SAndroid Build Coastguard Worker block_on(run(&mut transport, &mut fastboot_impl)).unwrap();
1771*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
1772*5225e6b1SAndroid Build Coastguard Worker transport.out_queue,
1773*5225e6b1SAndroid Build Coastguard Worker VecDeque::<Vec<u8>>::from([
1774*5225e6b1SAndroid Build Coastguard Worker b"OKAY0x400".into(),
1775*5225e6b1SAndroid Build Coastguard Worker b"INFOContinuing to boot...".into(),
1776*5225e6b1SAndroid Build Coastguard Worker b"OKAY".into()
1777*5225e6b1SAndroid Build Coastguard Worker ])
1778*5225e6b1SAndroid Build Coastguard Worker );
1779*5225e6b1SAndroid Build Coastguard Worker }
1780*5225e6b1SAndroid Build Coastguard Worker
1781*5225e6b1SAndroid Build Coastguard Worker #[test]
test_continue_run_tcp()1782*5225e6b1SAndroid Build Coastguard Worker fn test_continue_run_tcp() {
1783*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1784*5225e6b1SAndroid Build Coastguard Worker let mut tcp_stream: TestTcpStream = Default::default();
1785*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_input(TCP_HANDSHAKE_MESSAGE);
1786*5225e6b1SAndroid Build Coastguard Worker tcp_stream.add_length_prefixed_input(b"continue");
1787*5225e6b1SAndroid Build Coastguard Worker block_on(run_tcp_session(&mut tcp_stream, &mut fastboot_impl)).unwrap();
1788*5225e6b1SAndroid Build Coastguard Worker }
1789*5225e6b1SAndroid Build Coastguard Worker
1790*5225e6b1SAndroid Build Coastguard Worker #[test]
test_set_active()1791*5225e6b1SAndroid Build Coastguard Worker fn test_set_active() {
1792*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1793*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1794*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1795*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"set_active:a");
1796*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1797*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([b"OKAY".into()]));
1798*5225e6b1SAndroid Build Coastguard Worker assert_eq!(fastboot_impl.active_slot, Some("a".into()));
1799*5225e6b1SAndroid Build Coastguard Worker }
1800*5225e6b1SAndroid Build Coastguard Worker
1801*5225e6b1SAndroid Build Coastguard Worker #[test]
test_set_active_missing_slot()1802*5225e6b1SAndroid Build Coastguard Worker fn test_set_active_missing_slot() {
1803*5225e6b1SAndroid Build Coastguard Worker let mut fastboot_impl: FastbootTest = Default::default();
1804*5225e6b1SAndroid Build Coastguard Worker fastboot_impl.download_buffer = vec![0u8; 1024];
1805*5225e6b1SAndroid Build Coastguard Worker let mut transport = TestTransport::new();
1806*5225e6b1SAndroid Build Coastguard Worker transport.add_input(b"set_active");
1807*5225e6b1SAndroid Build Coastguard Worker block_on(process_next_command(&mut transport, &mut fastboot_impl)).unwrap();
1808*5225e6b1SAndroid Build Coastguard Worker assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([b"FAILMissing slot".into()]));
1809*5225e6b1SAndroid Build Coastguard Worker }
1810*5225e6b1SAndroid Build Coastguard Worker }
1811