xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/fastboot/mod.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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 //! Fastboot backend for libgbl.
16*5225e6b1SAndroid Build Coastguard Worker 
17*5225e6b1SAndroid Build Coastguard Worker use crate::{
18*5225e6b1SAndroid Build Coastguard Worker     fuchsia_boot::GblAbrOps,
19*5225e6b1SAndroid Build Coastguard Worker     gbl_print, gbl_println,
20*5225e6b1SAndroid Build Coastguard Worker     partition::{check_part_unique, GblDisk, PartitionIo},
21*5225e6b1SAndroid Build Coastguard Worker     GblOps,
22*5225e6b1SAndroid Build Coastguard Worker };
23*5225e6b1SAndroid Build Coastguard Worker pub use abr::{mark_slot_active, set_one_shot_bootloader, set_one_shot_recovery, SlotIndex};
24*5225e6b1SAndroid Build Coastguard Worker use core::{
25*5225e6b1SAndroid Build Coastguard Worker     array::from_fn, cmp::min, ffi::CStr, fmt::Write, future::Future, marker::PhantomData,
26*5225e6b1SAndroid Build Coastguard Worker     mem::take, ops::DerefMut, pin::Pin, str::from_utf8,
27*5225e6b1SAndroid Build Coastguard Worker };
28*5225e6b1SAndroid Build Coastguard Worker use fastboot::{
29*5225e6b1SAndroid Build Coastguard Worker     next_arg, next_arg_u64, process_next_command, run_tcp_session, snprintf, CommandError,
30*5225e6b1SAndroid Build Coastguard Worker     CommandResult, FastbootImplementation, FormattedBytes, InfoSender, OkaySender, RebootMode,
31*5225e6b1SAndroid Build Coastguard Worker     UploadBuilder, Uploader, VarInfoSender,
32*5225e6b1SAndroid Build Coastguard Worker };
33*5225e6b1SAndroid Build Coastguard Worker use gbl_async::{join, yield_now};
34*5225e6b1SAndroid Build Coastguard Worker use gbl_storage::{BlockIo, Disk, Gpt};
35*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
36*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
37*5225e6b1SAndroid Build Coastguard Worker use zbi::{ZbiContainer, ZbiType};
38*5225e6b1SAndroid Build Coastguard Worker 
39*5225e6b1SAndroid Build Coastguard Worker mod vars;
40*5225e6b1SAndroid Build Coastguard Worker 
41*5225e6b1SAndroid Build Coastguard Worker pub(crate) mod sparse;
42*5225e6b1SAndroid Build Coastguard Worker use sparse::is_sparse_image;
43*5225e6b1SAndroid Build Coastguard Worker 
44*5225e6b1SAndroid Build Coastguard Worker mod shared;
45*5225e6b1SAndroid Build Coastguard Worker pub use shared::Shared;
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker mod buffer_pool;
48*5225e6b1SAndroid Build Coastguard Worker pub use buffer_pool::BufferPool;
49*5225e6b1SAndroid Build Coastguard Worker use buffer_pool::ScopedBuffer;
50*5225e6b1SAndroid Build Coastguard Worker 
51*5225e6b1SAndroid Build Coastguard Worker mod pin_fut_container;
52*5225e6b1SAndroid Build Coastguard Worker pub use pin_fut_container::PinFutContainer;
53*5225e6b1SAndroid Build Coastguard Worker use pin_fut_container::{PinFutContainerTyped, PinFutSlice};
54*5225e6b1SAndroid Build Coastguard Worker 
55*5225e6b1SAndroid Build Coastguard Worker // Re-exports dependency types
56*5225e6b1SAndroid Build Coastguard Worker pub use fastboot::{TcpStream, Transport};
57*5225e6b1SAndroid Build Coastguard Worker 
58*5225e6b1SAndroid Build Coastguard Worker /// Reserved name for indicating flashing GPT.
59*5225e6b1SAndroid Build Coastguard Worker const FLASH_GPT_PART: &str = "gpt";
60*5225e6b1SAndroid Build Coastguard Worker 
61*5225e6b1SAndroid Build Coastguard Worker /// Represents a GBL Fastboot async task.
62*5225e6b1SAndroid Build Coastguard Worker enum Task<'a, 'b, B: BlockIo, P: BufferPool> {
63*5225e6b1SAndroid Build Coastguard Worker     /// Image flashing task. (partition io, downloaded data, data size)
64*5225e6b1SAndroid Build Coastguard Worker     Flash(PartitionIo<'a, B>, ScopedBuffer<'b, P>, usize),
65*5225e6b1SAndroid Build Coastguard Worker     // Image erase task.
66*5225e6b1SAndroid Build Coastguard Worker     Erase(PartitionIo<'a, B>, ScopedBuffer<'b, P>),
67*5225e6b1SAndroid Build Coastguard Worker     None,
68*5225e6b1SAndroid Build Coastguard Worker }
69*5225e6b1SAndroid Build Coastguard Worker 
70*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'b, B: BlockIo, P: BufferPool> Task<'a, 'b, B, P> {
71*5225e6b1SAndroid Build Coastguard Worker     // Runs the task.
run(self)72*5225e6b1SAndroid Build Coastguard Worker     async fn run(self) {
73*5225e6b1SAndroid Build Coastguard Worker         let _ = async {
74*5225e6b1SAndroid Build Coastguard Worker             match self {
75*5225e6b1SAndroid Build Coastguard Worker                 Self::Flash(mut part_io, mut download, data_size) => {
76*5225e6b1SAndroid Build Coastguard Worker                     match is_sparse_image(&download) {
77*5225e6b1SAndroid Build Coastguard Worker                         Ok(_) => part_io.write_sparse(0, &mut download).await,
78*5225e6b1SAndroid Build Coastguard Worker                         _ => part_io.write(0, &mut download[..data_size]).await,
79*5225e6b1SAndroid Build Coastguard Worker                     }
80*5225e6b1SAndroid Build Coastguard Worker                 }
81*5225e6b1SAndroid Build Coastguard Worker                 Self::Erase(mut part_io, mut buffer) => part_io.zeroize(&mut buffer).await,
82*5225e6b1SAndroid Build Coastguard Worker                 _ => Ok(()),
83*5225e6b1SAndroid Build Coastguard Worker             }
84*5225e6b1SAndroid Build Coastguard Worker         }
85*5225e6b1SAndroid Build Coastguard Worker         .await;
86*5225e6b1SAndroid Build Coastguard Worker     }
87*5225e6b1SAndroid Build Coastguard Worker }
88*5225e6b1SAndroid Build Coastguard Worker 
89*5225e6b1SAndroid Build Coastguard Worker /// `GblFastboot` implements fastboot commands in the GBL context.
90*5225e6b1SAndroid Build Coastguard Worker ///
91*5225e6b1SAndroid Build Coastguard Worker /// # Lifetimes
92*5225e6b1SAndroid Build Coastguard Worker ///
93*5225e6b1SAndroid Build Coastguard Worker /// * `'a`: [GblOps] and disks lifetime.
94*5225e6b1SAndroid Build Coastguard Worker /// * `'b`: Lifetime for the buffer allocated by `P`.
95*5225e6b1SAndroid Build Coastguard Worker /// * `'c`: Lifetime of the pinned [Future]s in task container `task`.
96*5225e6b1SAndroid Build Coastguard Worker /// * `'d`: Lifetime of the `tasks` and `gbl_ops` objects borrowed.
97*5225e6b1SAndroid Build Coastguard Worker /// * `'e`: Lifetime of the ImageBuffers returned by `get_image_buffer()`.
98*5225e6b1SAndroid Build Coastguard Worker ///
99*5225e6b1SAndroid Build Coastguard Worker /// # Generics
100*5225e6b1SAndroid Build Coastguard Worker ///
101*5225e6b1SAndroid Build Coastguard Worker /// * `G`: Type of `Self::gbl_ops` which implements [GblOps].
102*5225e6b1SAndroid Build Coastguard Worker /// * `B`: Type that implements [BlockIo] in the [Disk] parameter of [GblDisk] for `Self::disks`.
103*5225e6b1SAndroid Build Coastguard Worker /// * `S`: Type of scratch buffer in the [Disk] parameter of [GblDisk] for `Self::disks`.
104*5225e6b1SAndroid Build Coastguard Worker /// * `T`: Type of gpt buffer in the [Gpt] parameter of [GblDisk] for `Self::disks`.
105*5225e6b1SAndroid Build Coastguard Worker /// * `P`: Type of `Self::buffer_pool` which implements [BufferPool].
106*5225e6b1SAndroid Build Coastguard Worker /// * `C`: Type of `Self::tasks` which implements [PinFutContainerTyped].
107*5225e6b1SAndroid Build Coastguard Worker /// * `F`: Type of [Future] stored by `Self::Tasks`.
108*5225e6b1SAndroid Build Coastguard Worker struct GblFastboot<'a, 'b, 'c, 'd, 'e, G, B, S, T, P, C, F>
109*5225e6b1SAndroid Build Coastguard Worker where
110*5225e6b1SAndroid Build Coastguard Worker     G: GblOps<'a, 'e>,
111*5225e6b1SAndroid Build Coastguard Worker     B: BlockIo,
112*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
113*5225e6b1SAndroid Build Coastguard Worker     T: DerefMut<Target = [u8]>,
114*5225e6b1SAndroid Build Coastguard Worker     P: BufferPool,
115*5225e6b1SAndroid Build Coastguard Worker {
116*5225e6b1SAndroid Build Coastguard Worker     pub(crate) gbl_ops: &'d mut G,
117*5225e6b1SAndroid Build Coastguard Worker     // We store the partition devices returned by `gbl_ops.disks()` directly instead of getting it
118*5225e6b1SAndroid Build Coastguard Worker     // from `gbl_ops` later because we need to establish to the compiler that the hidden type of
119*5225e6b1SAndroid Build Coastguard Worker     // [BlockIo] in `GblDisk<Disk<impl BlockIO...>...>` returned by `gbl_ops.disks()` will be the
120*5225e6b1SAndroid Build Coastguard Worker     // same as the [BlockIo] type (denoted as B) in the function pointer
121*5225e6b1SAndroid Build Coastguard Worker     // `task_mapper`: fn(Task<'a, 'b, B, P>) -> F`. Otherwise, compiler won't allow `fn flash()`
122*5225e6b1SAndroid Build Coastguard Worker     // to call `task_mapper` with a `Task` constructed from `GblDisk<Disk<impl BlockIO...>...>`.
123*5225e6b1SAndroid Build Coastguard Worker     disks: &'a [GblDisk<Disk<B, S>, Gpt<T>>],
124*5225e6b1SAndroid Build Coastguard Worker     buffer_pool: &'b Shared<P>,
125*5225e6b1SAndroid Build Coastguard Worker     task_mapper: fn(Task<'a, 'b, B, P>) -> F,
126*5225e6b1SAndroid Build Coastguard Worker     tasks: &'d Shared<C>,
127*5225e6b1SAndroid Build Coastguard Worker     current_download_buffer: Option<ScopedBuffer<'b, P>>,
128*5225e6b1SAndroid Build Coastguard Worker     current_download_size: usize,
129*5225e6b1SAndroid Build Coastguard Worker     enable_async_task: bool,
130*5225e6b1SAndroid Build Coastguard Worker     default_block: Option<usize>,
131*5225e6b1SAndroid Build Coastguard Worker     bootimg_buf: &'b mut [u8],
132*5225e6b1SAndroid Build Coastguard Worker     // Introduces marker type so that we can enforce constraint 'd <= min('b, 'c).
133*5225e6b1SAndroid Build Coastguard Worker     // The constraint is expressed in the implementation block for the `FastbootImplementation`
134*5225e6b1SAndroid Build Coastguard Worker     // trait.
135*5225e6b1SAndroid Build Coastguard Worker     _tasks_context_lifetime: PhantomData<&'c P>,
136*5225e6b1SAndroid Build Coastguard Worker     _get_image_buffer_lifetime: PhantomData<&'e ()>,
137*5225e6b1SAndroid Build Coastguard Worker }
138*5225e6b1SAndroid Build Coastguard Worker 
139*5225e6b1SAndroid Build Coastguard Worker // See definition of [GblFastboot] for docs on lifetimes and generics parameters.
140*5225e6b1SAndroid Build Coastguard Worker impl<'a: 'c, 'b: 'c, 'c, 'd, 'e, G, B, S, T, P, C, F>
141*5225e6b1SAndroid Build Coastguard Worker     GblFastboot<'a, 'b, 'c, 'd, 'e, G, B, S, T, P, C, F>
142*5225e6b1SAndroid Build Coastguard Worker where
143*5225e6b1SAndroid Build Coastguard Worker     G: GblOps<'a, 'e>,
144*5225e6b1SAndroid Build Coastguard Worker     B: BlockIo,
145*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
146*5225e6b1SAndroid Build Coastguard Worker     T: DerefMut<Target = [u8]>,
147*5225e6b1SAndroid Build Coastguard Worker     P: BufferPool,
148*5225e6b1SAndroid Build Coastguard Worker     C: PinFutContainerTyped<'c, F>,
149*5225e6b1SAndroid Build Coastguard Worker     F: Future<Output = ()> + 'c,
150*5225e6b1SAndroid Build Coastguard Worker {
151*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new [GblFastboot].
152*5225e6b1SAndroid Build Coastguard Worker     ///
153*5225e6b1SAndroid Build Coastguard Worker     /// # Args
154*5225e6b1SAndroid Build Coastguard Worker     ///
155*5225e6b1SAndroid Build Coastguard Worker     /// * `gbl_ops`: An implementation of `GblOps`.
156*5225e6b1SAndroid Build Coastguard Worker     /// * `disks`: The disk devices returned by `gbl_ops.disks()`. This is needed for expressing the
157*5225e6b1SAndroid Build Coastguard Worker     ///   property that the hidden [BlockIo] type is the same as that in `task_mapper`.
158*5225e6b1SAndroid Build Coastguard Worker     /// * `task_mapper`: A function pointer that maps `Task<'a, 'b, G, B>` to the target [Future]
159*5225e6b1SAndroid Build Coastguard Worker     ///   type `F` for input to `PinFutContainerTyped<F>::add_with()`.
160*5225e6b1SAndroid Build Coastguard Worker     /// * `tasks`: A shared instance of `PinFutContainerTyped<F>`.
161*5225e6b1SAndroid Build Coastguard Worker     /// * `buffer_pool`: A shared instance of `BufferPool`.
162*5225e6b1SAndroid Build Coastguard Worker     ///
163*5225e6b1SAndroid Build Coastguard Worker     /// The combination of `task_mapper` and `tasks` allows type `F`, which will be running the
164*5225e6b1SAndroid Build Coastguard Worker     /// async function `Task::run()`, to be defined at the callsite. This is necessary for the
165*5225e6b1SAndroid Build Coastguard Worker     /// usage of preallocated pinned futures (by `run_gbl_fastboot_stack()`) because the returned
166*5225e6b1SAndroid Build Coastguard Worker     /// type of a `async fn` is compiler-generated and can't be named. The only way to create a
167*5225e6b1SAndroid Build Coastguard Worker     /// preallocated slice of anonymous future is to keep the type generic and pass in the
168*5225e6b1SAndroid Build Coastguard Worker     /// anonymous future instance at the initialization callsite (aka defining use) and let compiler
169*5225e6b1SAndroid Build Coastguard Worker     /// infer and propagate it.
new( gbl_ops: &'d mut G, disks: &'a [GblDisk<Disk<B, S>, Gpt<T>>], task_mapper: fn(Task<'a, 'b, B, P>) -> F, tasks: &'d Shared<C>, buffer_pool: &'b Shared<P>, bootimg_buf: &'b mut [u8], ) -> Self170*5225e6b1SAndroid Build Coastguard Worker     fn new(
171*5225e6b1SAndroid Build Coastguard Worker         gbl_ops: &'d mut G,
172*5225e6b1SAndroid Build Coastguard Worker         disks: &'a [GblDisk<Disk<B, S>, Gpt<T>>],
173*5225e6b1SAndroid Build Coastguard Worker         task_mapper: fn(Task<'a, 'b, B, P>) -> F,
174*5225e6b1SAndroid Build Coastguard Worker         tasks: &'d Shared<C>,
175*5225e6b1SAndroid Build Coastguard Worker         buffer_pool: &'b Shared<P>,
176*5225e6b1SAndroid Build Coastguard Worker         bootimg_buf: &'b mut [u8],
177*5225e6b1SAndroid Build Coastguard Worker     ) -> Self {
178*5225e6b1SAndroid Build Coastguard Worker         Self {
179*5225e6b1SAndroid Build Coastguard Worker             gbl_ops,
180*5225e6b1SAndroid Build Coastguard Worker             disks,
181*5225e6b1SAndroid Build Coastguard Worker             task_mapper,
182*5225e6b1SAndroid Build Coastguard Worker             tasks,
183*5225e6b1SAndroid Build Coastguard Worker             buffer_pool,
184*5225e6b1SAndroid Build Coastguard Worker             current_download_buffer: None,
185*5225e6b1SAndroid Build Coastguard Worker             current_download_size: 0,
186*5225e6b1SAndroid Build Coastguard Worker             enable_async_task: false,
187*5225e6b1SAndroid Build Coastguard Worker             default_block: None,
188*5225e6b1SAndroid Build Coastguard Worker             bootimg_buf,
189*5225e6b1SAndroid Build Coastguard Worker             _tasks_context_lifetime: PhantomData,
190*5225e6b1SAndroid Build Coastguard Worker             _get_image_buffer_lifetime: PhantomData,
191*5225e6b1SAndroid Build Coastguard Worker         }
192*5225e6b1SAndroid Build Coastguard Worker     }
193*5225e6b1SAndroid Build Coastguard Worker 
194*5225e6b1SAndroid Build Coastguard Worker     /// Returns the shared task container.
tasks(&self) -> &'d Shared<impl PinFutContainerTyped<'c, F>>195*5225e6b1SAndroid Build Coastguard Worker     fn tasks(&self) -> &'d Shared<impl PinFutContainerTyped<'c, F>> {
196*5225e6b1SAndroid Build Coastguard Worker         self.tasks
197*5225e6b1SAndroid Build Coastguard Worker     }
198*5225e6b1SAndroid Build Coastguard Worker 
199*5225e6b1SAndroid Build Coastguard Worker     /// Listens on the given USB/TCP channels and runs fastboot.
run( &mut self, mut usb: Option<impl GblUsbTransport>, mut tcp: Option<impl GblTcpStream>, )200*5225e6b1SAndroid Build Coastguard Worker     async fn run(
201*5225e6b1SAndroid Build Coastguard Worker         &mut self,
202*5225e6b1SAndroid Build Coastguard Worker         mut usb: Option<impl GblUsbTransport>,
203*5225e6b1SAndroid Build Coastguard Worker         mut tcp: Option<impl GblTcpStream>,
204*5225e6b1SAndroid Build Coastguard Worker     ) {
205*5225e6b1SAndroid Build Coastguard Worker         if usb.is_none() && tcp.is_none() {
206*5225e6b1SAndroid Build Coastguard Worker             gbl_println!(self.gbl_ops, "No USB or TCP found for GBL Fastboot");
207*5225e6b1SAndroid Build Coastguard Worker             return;
208*5225e6b1SAndroid Build Coastguard Worker         }
209*5225e6b1SAndroid Build Coastguard Worker         let tasks = self.tasks();
210*5225e6b1SAndroid Build Coastguard Worker         // The fastboot command loop task for interacting with the remote host.
211*5225e6b1SAndroid Build Coastguard Worker         let cmd_loop_end = Shared::from(false);
212*5225e6b1SAndroid Build Coastguard Worker         let cmd_loop_task = async {
213*5225e6b1SAndroid Build Coastguard Worker             loop {
214*5225e6b1SAndroid Build Coastguard Worker                 if let Some(v) = usb.as_mut() {
215*5225e6b1SAndroid Build Coastguard Worker                     if v.has_packet() {
216*5225e6b1SAndroid Build Coastguard Worker                         let res = match process_next_command(v, self).await {
217*5225e6b1SAndroid Build Coastguard Worker                             Ok(true) => break,
218*5225e6b1SAndroid Build Coastguard Worker                             v => v,
219*5225e6b1SAndroid Build Coastguard Worker                         };
220*5225e6b1SAndroid Build Coastguard Worker                         if res.is_err() {
221*5225e6b1SAndroid Build Coastguard Worker                             gbl_println!(self.gbl_ops, "GBL Fastboot USB session error: {:?}", res);
222*5225e6b1SAndroid Build Coastguard Worker                         }
223*5225e6b1SAndroid Build Coastguard Worker                     }
224*5225e6b1SAndroid Build Coastguard Worker                 }
225*5225e6b1SAndroid Build Coastguard Worker 
226*5225e6b1SAndroid Build Coastguard Worker                 if let Some(v) = tcp.as_mut() {
227*5225e6b1SAndroid Build Coastguard Worker                     if v.accept_new() {
228*5225e6b1SAndroid Build Coastguard Worker                         let res = match run_tcp_session(v, self).await {
229*5225e6b1SAndroid Build Coastguard Worker                             Ok(()) => break,
230*5225e6b1SAndroid Build Coastguard Worker                             v => v,
231*5225e6b1SAndroid Build Coastguard Worker                         };
232*5225e6b1SAndroid Build Coastguard Worker                         if res.is_err_and(|e| e != Error::Disconnected) {
233*5225e6b1SAndroid Build Coastguard Worker                             gbl_println!(self.gbl_ops, "GBL Fastboot TCP session error: {:?}", res);
234*5225e6b1SAndroid Build Coastguard Worker                         }
235*5225e6b1SAndroid Build Coastguard Worker                     }
236*5225e6b1SAndroid Build Coastguard Worker                 }
237*5225e6b1SAndroid Build Coastguard Worker 
238*5225e6b1SAndroid Build Coastguard Worker                 yield_now().await;
239*5225e6b1SAndroid Build Coastguard Worker             }
240*5225e6b1SAndroid Build Coastguard Worker             *cmd_loop_end.borrow_mut() = true;
241*5225e6b1SAndroid Build Coastguard Worker         };
242*5225e6b1SAndroid Build Coastguard Worker 
243*5225e6b1SAndroid Build Coastguard Worker         // Schedules [Task] spawned by GBL fastboot.
244*5225e6b1SAndroid Build Coastguard Worker         let gbl_fb_tasks = async {
245*5225e6b1SAndroid Build Coastguard Worker             while tasks.borrow_mut().poll_all() > 0 || !*cmd_loop_end.borrow_mut() {
246*5225e6b1SAndroid Build Coastguard Worker                 yield_now().await;
247*5225e6b1SAndroid Build Coastguard Worker             }
248*5225e6b1SAndroid Build Coastguard Worker         };
249*5225e6b1SAndroid Build Coastguard Worker 
250*5225e6b1SAndroid Build Coastguard Worker         let _ = join(cmd_loop_task, gbl_fb_tasks).await;
251*5225e6b1SAndroid Build Coastguard Worker     }
252*5225e6b1SAndroid Build Coastguard Worker 
253*5225e6b1SAndroid Build Coastguard Worker     /// Extracts the next argument and verifies that it is a valid block device ID if present.
254*5225e6b1SAndroid Build Coastguard Worker     ///
255*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
256*5225e6b1SAndroid Build Coastguard Worker     ///
257*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Ok(Some(blk_id))` if next argument is present and is a valid block device ID.
258*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `None` if next argument is not available and there are more than one block
259*5225e6b1SAndroid Build Coastguard Worker     ///   devices.
260*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Err(())` if next argument is present but is an invalid block device ID.
check_next_arg_blk_id<'s>( &self, args: &mut impl Iterator<Item = &'s str>, ) -> CommandResult<Option<usize>>261*5225e6b1SAndroid Build Coastguard Worker     fn check_next_arg_blk_id<'s>(
262*5225e6b1SAndroid Build Coastguard Worker         &self,
263*5225e6b1SAndroid Build Coastguard Worker         args: &mut impl Iterator<Item = &'s str>,
264*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<Option<usize>> {
265*5225e6b1SAndroid Build Coastguard Worker         let devs = self.disks;
266*5225e6b1SAndroid Build Coastguard Worker         let blk_id = match next_arg_u64(args)? {
267*5225e6b1SAndroid Build Coastguard Worker             Some(v) => {
268*5225e6b1SAndroid Build Coastguard Worker                 let v = usize::try_from(v)?;
269*5225e6b1SAndroid Build Coastguard Worker                 // Checks out of range.
270*5225e6b1SAndroid Build Coastguard Worker                 devs.get(v).ok_or("Invalid block ID")?;
271*5225e6b1SAndroid Build Coastguard Worker                 Some(v)
272*5225e6b1SAndroid Build Coastguard Worker             }
273*5225e6b1SAndroid Build Coastguard Worker             _ => None,
274*5225e6b1SAndroid Build Coastguard Worker         };
275*5225e6b1SAndroid Build Coastguard Worker         let blk_id = blk_id.or(self.default_block);
276*5225e6b1SAndroid Build Coastguard Worker         let blk_id = blk_id.or((devs.len() == 1).then_some(0));
277*5225e6b1SAndroid Build Coastguard Worker         Ok(blk_id)
278*5225e6b1SAndroid Build Coastguard Worker     }
279*5225e6b1SAndroid Build Coastguard Worker 
280*5225e6b1SAndroid Build Coastguard Worker     /// Parses and checks the argument for "fastboot flash gpt/<blk_idx>/"resize".
281*5225e6b1SAndroid Build Coastguard Worker     ///
282*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
283*5225e6b1SAndroid Build Coastguard Worker     ///
284*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Ok(Some((blk_idx, resize)))` if command is a GPT flashing command.
285*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Ok(None)` if command is not a GPT flashing command.
286*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Err()` otherwise.
parse_flash_gpt_args(&self, part: &str) -> CommandResult<Option<(usize, bool)>>287*5225e6b1SAndroid Build Coastguard Worker     pub(crate) fn parse_flash_gpt_args(&self, part: &str) -> CommandResult<Option<(usize, bool)>> {
288*5225e6b1SAndroid Build Coastguard Worker         // Syntax: flash gpt/<blk_idx>/"resize"
289*5225e6b1SAndroid Build Coastguard Worker         let mut args = part.split('/');
290*5225e6b1SAndroid Build Coastguard Worker         if next_arg(&mut args).filter(|v| *v == FLASH_GPT_PART).is_none() {
291*5225e6b1SAndroid Build Coastguard Worker             return Ok(None);
292*5225e6b1SAndroid Build Coastguard Worker         }
293*5225e6b1SAndroid Build Coastguard Worker         // Parses block device ID.
294*5225e6b1SAndroid Build Coastguard Worker         let blk_id = self
295*5225e6b1SAndroid Build Coastguard Worker             .check_next_arg_blk_id(&mut args)?
296*5225e6b1SAndroid Build Coastguard Worker             .ok_or("Block ID is required for flashing GPT")?;
297*5225e6b1SAndroid Build Coastguard Worker         // Parses resize option.
298*5225e6b1SAndroid Build Coastguard Worker         let resize = match next_arg(&mut args) {
299*5225e6b1SAndroid Build Coastguard Worker             Some("resize") => true,
300*5225e6b1SAndroid Build Coastguard Worker             Some(_) => return Err("Unknown argument".into()),
301*5225e6b1SAndroid Build Coastguard Worker             _ => false,
302*5225e6b1SAndroid Build Coastguard Worker         };
303*5225e6b1SAndroid Build Coastguard Worker         Ok(Some((blk_id, resize)))
304*5225e6b1SAndroid Build Coastguard Worker     }
305*5225e6b1SAndroid Build Coastguard Worker 
306*5225e6b1SAndroid Build Coastguard Worker     /// Parses and checks the partition argument and returns the partition name, block device
307*5225e6b1SAndroid Build Coastguard Worker     /// index, start offset and size.
parse_partition<'s>( &self, part: &'s str, ) -> CommandResult<(Option<&'s str>, usize, u64, u64)>308*5225e6b1SAndroid Build Coastguard Worker     pub(crate) fn parse_partition<'s>(
309*5225e6b1SAndroid Build Coastguard Worker         &self,
310*5225e6b1SAndroid Build Coastguard Worker         part: &'s str,
311*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<(Option<&'s str>, usize, u64, u64)> {
312*5225e6b1SAndroid Build Coastguard Worker         let devs = self.disks;
313*5225e6b1SAndroid Build Coastguard Worker         let mut args = part.split('/');
314*5225e6b1SAndroid Build Coastguard Worker         // Parses partition name.
315*5225e6b1SAndroid Build Coastguard Worker         let part = next_arg(&mut args);
316*5225e6b1SAndroid Build Coastguard Worker         // Parses block device ID.
317*5225e6b1SAndroid Build Coastguard Worker         let blk_id = self.check_next_arg_blk_id(&mut args)?;
318*5225e6b1SAndroid Build Coastguard Worker         // Parses sub window offset.
319*5225e6b1SAndroid Build Coastguard Worker         let window_offset = next_arg_u64(&mut args)?.unwrap_or(0);
320*5225e6b1SAndroid Build Coastguard Worker         // Parses sub window size.
321*5225e6b1SAndroid Build Coastguard Worker         let window_size = next_arg_u64(&mut args)?;
322*5225e6b1SAndroid Build Coastguard Worker         // Checks uniqueness of the partition and resolves its block device ID.
323*5225e6b1SAndroid Build Coastguard Worker         let find = |p: Option<&'s str>| match blk_id {
324*5225e6b1SAndroid Build Coastguard Worker             None => Ok((check_part_unique(devs, p.ok_or("Must provide a partition")?)?, p)),
325*5225e6b1SAndroid Build Coastguard Worker             Some(v) => Ok(((v, devs[v].find_partition(p)?), p)),
326*5225e6b1SAndroid Build Coastguard Worker         };
327*5225e6b1SAndroid Build Coastguard Worker         let ((blk_id, partition), actual) = match find(part) {
328*5225e6b1SAndroid Build Coastguard Worker             // Some legacy Fuchsia devices in the field uses name "fuchsia-fvm" for the standard
329*5225e6b1SAndroid Build Coastguard Worker             // "fvm" partition. However all of our infra uses the standard name "fvm" when flashing.
330*5225e6b1SAndroid Build Coastguard Worker             // Here we do a one off mapping if the device falls into this case. Once we have a
331*5225e6b1SAndroid Build Coastguard Worker             // solution for migrating those devices off the legacy name, we can remove this.
332*5225e6b1SAndroid Build Coastguard Worker             //
333*5225e6b1SAndroid Build Coastguard Worker             // If we run into more of such legacy aliases that we can't migrate, consider adding
334*5225e6b1SAndroid Build Coastguard Worker             // interfaces in GblOps for this.
335*5225e6b1SAndroid Build Coastguard Worker             Err(Error::NotFound) if part == Some("fvm") => find(Some("fuchsia-fvm"))?,
336*5225e6b1SAndroid Build Coastguard Worker             v => v?,
337*5225e6b1SAndroid Build Coastguard Worker         };
338*5225e6b1SAndroid Build Coastguard Worker         let part_sz = SafeNum::from(partition.size()?);
339*5225e6b1SAndroid Build Coastguard Worker         let window_size = window_size.unwrap_or((part_sz - window_offset).try_into()?);
340*5225e6b1SAndroid Build Coastguard Worker         u64::try_from(part_sz - window_size - window_offset)?;
341*5225e6b1SAndroid Build Coastguard Worker         Ok((actual, blk_id, window_offset, window_size))
342*5225e6b1SAndroid Build Coastguard Worker     }
343*5225e6b1SAndroid Build Coastguard Worker 
344*5225e6b1SAndroid Build Coastguard Worker     /// Takes the download data and resets download size.
take_download(&mut self) -> Option<(ScopedBuffer<'b, P>, usize)>345*5225e6b1SAndroid Build Coastguard Worker     fn take_download(&mut self) -> Option<(ScopedBuffer<'b, P>, usize)> {
346*5225e6b1SAndroid Build Coastguard Worker         Some((self.current_download_buffer.take()?, take(&mut self.current_download_size)))
347*5225e6b1SAndroid Build Coastguard Worker     }
348*5225e6b1SAndroid Build Coastguard Worker 
349*5225e6b1SAndroid Build Coastguard Worker     /// Waits until a Disk device is ready and get the [PartitionIo] for `part`.
wait_partition_io( &self, blk: usize, part: Option<&str>, ) -> CommandResult<PartitionIo<'a, B>>350*5225e6b1SAndroid Build Coastguard Worker     pub async fn wait_partition_io(
351*5225e6b1SAndroid Build Coastguard Worker         &self,
352*5225e6b1SAndroid Build Coastguard Worker         blk: usize,
353*5225e6b1SAndroid Build Coastguard Worker         part: Option<&str>,
354*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<PartitionIo<'a, B>> {
355*5225e6b1SAndroid Build Coastguard Worker         loop {
356*5225e6b1SAndroid Build Coastguard Worker             match self.disks[blk].partition_io(part) {
357*5225e6b1SAndroid Build Coastguard Worker                 Err(Error::NotReady) => yield_now().await,
358*5225e6b1SAndroid Build Coastguard Worker                 Ok(v) => {
359*5225e6b1SAndroid Build Coastguard Worker                     v.last_err()?;
360*5225e6b1SAndroid Build Coastguard Worker                     return Ok(v);
361*5225e6b1SAndroid Build Coastguard Worker                 }
362*5225e6b1SAndroid Build Coastguard Worker                 Err(e) => return Err(e.into()),
363*5225e6b1SAndroid Build Coastguard Worker             }
364*5225e6b1SAndroid Build Coastguard Worker         }
365*5225e6b1SAndroid Build Coastguard Worker     }
366*5225e6b1SAndroid Build Coastguard Worker 
367*5225e6b1SAndroid Build Coastguard Worker     /// An internal helper for parsing a partition and getting the partition IO
parse_and_get_partition_io( &self, part: &str, ) -> CommandResult<(usize, PartitionIo<'a, B>)>368*5225e6b1SAndroid Build Coastguard Worker     async fn parse_and_get_partition_io(
369*5225e6b1SAndroid Build Coastguard Worker         &self,
370*5225e6b1SAndroid Build Coastguard Worker         part: &str,
371*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<(usize, PartitionIo<'a, B>)> {
372*5225e6b1SAndroid Build Coastguard Worker         let (part, blk_idx, start, sz) = self.parse_partition(part)?;
373*5225e6b1SAndroid Build Coastguard Worker         Ok((blk_idx, self.wait_partition_io(blk_idx, part).await?.sub(start, sz)?))
374*5225e6b1SAndroid Build Coastguard Worker     }
375*5225e6b1SAndroid Build Coastguard Worker 
376*5225e6b1SAndroid Build Coastguard Worker     /// Helper for scheduiling an async task.
377*5225e6b1SAndroid Build Coastguard Worker     ///
378*5225e6b1SAndroid Build Coastguard Worker     /// * If `Self::enable_async_task` is true, the method will add the task to the background task
379*5225e6b1SAndroid Build Coastguard Worker     ///   list. Otherwise it simply runs the task.
schedule_task( &mut self, task: Task<'a, 'b, B, P>, responder: &mut impl InfoSender, ) -> CommandResult<()>380*5225e6b1SAndroid Build Coastguard Worker     async fn schedule_task(
381*5225e6b1SAndroid Build Coastguard Worker         &mut self,
382*5225e6b1SAndroid Build Coastguard Worker         task: Task<'a, 'b, B, P>,
383*5225e6b1SAndroid Build Coastguard Worker         responder: &mut impl InfoSender,
384*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<()> {
385*5225e6b1SAndroid Build Coastguard Worker         match self.enable_async_task {
386*5225e6b1SAndroid Build Coastguard Worker             true => {
387*5225e6b1SAndroid Build Coastguard Worker                 let mut t = Some((self.task_mapper)(task));
388*5225e6b1SAndroid Build Coastguard Worker                 self.tasks.borrow_mut().add_with(|| t.take().unwrap());
389*5225e6b1SAndroid Build Coastguard Worker                 while t.is_some() {
390*5225e6b1SAndroid Build Coastguard Worker                     yield_now().await;
391*5225e6b1SAndroid Build Coastguard Worker                     self.tasks.borrow_mut().add_with(|| t.take().unwrap());
392*5225e6b1SAndroid Build Coastguard Worker                 }
393*5225e6b1SAndroid Build Coastguard Worker                 self.tasks.borrow_mut().poll_all();
394*5225e6b1SAndroid Build Coastguard Worker                 let info = "An IO task is launched. To sync manually, run \"oem gbl-sync-tasks\".";
395*5225e6b1SAndroid Build Coastguard Worker                 responder.send_info(info).await?
396*5225e6b1SAndroid Build Coastguard Worker             }
397*5225e6b1SAndroid Build Coastguard Worker             _ => task.run().await,
398*5225e6b1SAndroid Build Coastguard Worker         };
399*5225e6b1SAndroid Build Coastguard Worker         Ok(())
400*5225e6b1SAndroid Build Coastguard Worker     }
401*5225e6b1SAndroid Build Coastguard Worker 
402*5225e6b1SAndroid Build Coastguard Worker     /// Waits for all block devices to be ready.
sync_all_blocks(&self) -> CommandResult<()>403*5225e6b1SAndroid Build Coastguard Worker     async fn sync_all_blocks(&self) -> CommandResult<()> {
404*5225e6b1SAndroid Build Coastguard Worker         for (idx, _) in self.disks.iter().enumerate() {
405*5225e6b1SAndroid Build Coastguard Worker             let _ = self.wait_partition_io(idx, None).await;
406*5225e6b1SAndroid Build Coastguard Worker         }
407*5225e6b1SAndroid Build Coastguard Worker         Ok(())
408*5225e6b1SAndroid Build Coastguard Worker     }
409*5225e6b1SAndroid Build Coastguard Worker 
410*5225e6b1SAndroid Build Coastguard Worker     /// Implementation for "fastboot oem gbl-sync-tasks".
oem_sync_blocks<'s>( &self, mut responder: impl InfoSender, res: &'s mut [u8], ) -> CommandResult<&'s [u8]>411*5225e6b1SAndroid Build Coastguard Worker     async fn oem_sync_blocks<'s>(
412*5225e6b1SAndroid Build Coastguard Worker         &self,
413*5225e6b1SAndroid Build Coastguard Worker         mut responder: impl InfoSender,
414*5225e6b1SAndroid Build Coastguard Worker         res: &'s mut [u8],
415*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<&'s [u8]> {
416*5225e6b1SAndroid Build Coastguard Worker         self.sync_all_blocks().await?;
417*5225e6b1SAndroid Build Coastguard Worker         // Checks error.
418*5225e6b1SAndroid Build Coastguard Worker         let mut has_error = false;
419*5225e6b1SAndroid Build Coastguard Worker         for (i, ele) in self.disks.iter().enumerate() {
420*5225e6b1SAndroid Build Coastguard Worker             match ele.partition_io(None)?.last_err() {
421*5225e6b1SAndroid Build Coastguard Worker                 Ok(_) => {}
422*5225e6b1SAndroid Build Coastguard Worker                 Err(e) => {
423*5225e6b1SAndroid Build Coastguard Worker                     has_error = true;
424*5225e6b1SAndroid Build Coastguard Worker                     responder.send_info(snprintf!(res, "Block #{} error: {:?}.", i, e)).await?;
425*5225e6b1SAndroid Build Coastguard Worker                 }
426*5225e6b1SAndroid Build Coastguard Worker             }
427*5225e6b1SAndroid Build Coastguard Worker         }
428*5225e6b1SAndroid Build Coastguard Worker         match has_error {
429*5225e6b1SAndroid Build Coastguard Worker             true => Err("Errors during async block IO. Please reset device.".into()),
430*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(b""),
431*5225e6b1SAndroid Build Coastguard Worker         }
432*5225e6b1SAndroid Build Coastguard Worker     }
433*5225e6b1SAndroid Build Coastguard Worker 
434*5225e6b1SAndroid Build Coastguard Worker     /// Syncs all storage devices and reboots.
sync_block_and_reboot( &mut self, mode: RebootMode, mut resp: impl InfoSender + OkaySender, ) -> CommandResult<()>435*5225e6b1SAndroid Build Coastguard Worker     async fn sync_block_and_reboot(
436*5225e6b1SAndroid Build Coastguard Worker         &mut self,
437*5225e6b1SAndroid Build Coastguard Worker         mode: RebootMode,
438*5225e6b1SAndroid Build Coastguard Worker         mut resp: impl InfoSender + OkaySender,
439*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<()> {
440*5225e6b1SAndroid Build Coastguard Worker         resp.send_info("Syncing storage...").await?;
441*5225e6b1SAndroid Build Coastguard Worker         self.sync_all_blocks().await?;
442*5225e6b1SAndroid Build Coastguard Worker         match mode {
443*5225e6b1SAndroid Build Coastguard Worker             RebootMode::Normal => {
444*5225e6b1SAndroid Build Coastguard Worker                 resp.send_info("Rebooting...").await?;
445*5225e6b1SAndroid Build Coastguard Worker                 resp.send_okay("").await?;
446*5225e6b1SAndroid Build Coastguard Worker                 self.gbl_ops.reboot();
447*5225e6b1SAndroid Build Coastguard Worker             }
448*5225e6b1SAndroid Build Coastguard Worker             RebootMode::Bootloader => {
449*5225e6b1SAndroid Build Coastguard Worker                 let f = self.gbl_ops.reboot_bootloader()?;
450*5225e6b1SAndroid Build Coastguard Worker                 resp.send_info("Rebooting to bootloader...").await?;
451*5225e6b1SAndroid Build Coastguard Worker                 resp.send_okay("").await?;
452*5225e6b1SAndroid Build Coastguard Worker                 f()
453*5225e6b1SAndroid Build Coastguard Worker             }
454*5225e6b1SAndroid Build Coastguard Worker             RebootMode::Recovery => {
455*5225e6b1SAndroid Build Coastguard Worker                 let f = self.gbl_ops.reboot_recovery()?;
456*5225e6b1SAndroid Build Coastguard Worker                 resp.send_info("Rebooting to recovery...").await?;
457*5225e6b1SAndroid Build Coastguard Worker                 resp.send_okay("").await?;
458*5225e6b1SAndroid Build Coastguard Worker                 f()
459*5225e6b1SAndroid Build Coastguard Worker             }
460*5225e6b1SAndroid Build Coastguard Worker             _ => return Err("Unsupported".into()),
461*5225e6b1SAndroid Build Coastguard Worker         }
462*5225e6b1SAndroid Build Coastguard Worker         Ok(())
463*5225e6b1SAndroid Build Coastguard Worker     }
464*5225e6b1SAndroid Build Coastguard Worker 
465*5225e6b1SAndroid Build Coastguard Worker     /// Appends a staged payload as bootloader file.
add_staged_bootloader_file(&mut self, file_name: &str) -> CommandResult<()>466*5225e6b1SAndroid Build Coastguard Worker     async fn add_staged_bootloader_file(&mut self, file_name: &str) -> CommandResult<()> {
467*5225e6b1SAndroid Build Coastguard Worker         let buffer = self
468*5225e6b1SAndroid Build Coastguard Worker             .gbl_ops
469*5225e6b1SAndroid Build Coastguard Worker             .get_zbi_bootloader_files_buffer_aligned()
470*5225e6b1SAndroid Build Coastguard Worker             .ok_or("No ZBI bootloader file buffer is provided")?;
471*5225e6b1SAndroid Build Coastguard Worker         let data = self.current_download_buffer.as_mut().ok_or("No file staged")?;
472*5225e6b1SAndroid Build Coastguard Worker         let data = &mut data[..self.current_download_size];
473*5225e6b1SAndroid Build Coastguard Worker         let mut zbi = match ZbiContainer::parse(&mut buffer[..]) {
474*5225e6b1SAndroid Build Coastguard Worker             Ok(v) => v,
475*5225e6b1SAndroid Build Coastguard Worker             _ => ZbiContainer::new(&mut buffer[..])?,
476*5225e6b1SAndroid Build Coastguard Worker         };
477*5225e6b1SAndroid Build Coastguard Worker         let next_payload = zbi.get_next_payload()?;
478*5225e6b1SAndroid Build Coastguard Worker         // Format: name length (1 byte) | name | file content.
479*5225e6b1SAndroid Build Coastguard Worker         let (name_len, rest) = next_payload.split_at_mut_checked(1).ok_or("Buffer too small")?;
480*5225e6b1SAndroid Build Coastguard Worker         let (name, rest) = rest.split_at_mut_checked(file_name.len()).ok_or("Buffer too small")?;
481*5225e6b1SAndroid Build Coastguard Worker         let file_content = rest.get_mut(..data.len()).ok_or("Buffer too small")?;
482*5225e6b1SAndroid Build Coastguard Worker         name_len[0] = file_name.len().try_into().map_err(|_| "File name length overflows 256")?;
483*5225e6b1SAndroid Build Coastguard Worker         name.clone_from_slice(file_name.as_bytes());
484*5225e6b1SAndroid Build Coastguard Worker         file_content.clone_from_slice(data);
485*5225e6b1SAndroid Build Coastguard Worker         // Creates the entry;
486*5225e6b1SAndroid Build Coastguard Worker         zbi.create_entry(
487*5225e6b1SAndroid Build Coastguard Worker             ZbiType::BootloaderFile,
488*5225e6b1SAndroid Build Coastguard Worker             0,
489*5225e6b1SAndroid Build Coastguard Worker             Default::default(),
490*5225e6b1SAndroid Build Coastguard Worker             1 + file_name.len() + data.len(),
491*5225e6b1SAndroid Build Coastguard Worker         )?;
492*5225e6b1SAndroid Build Coastguard Worker         Ok(())
493*5225e6b1SAndroid Build Coastguard Worker     }
494*5225e6b1SAndroid Build Coastguard Worker }
495*5225e6b1SAndroid Build Coastguard Worker 
496*5225e6b1SAndroid Build Coastguard Worker // See definition of [GblFastboot] for docs on lifetimes and generics parameters.
497*5225e6b1SAndroid Build Coastguard Worker impl<'a: 'c, 'b: 'c, 'c, 'e, G, B, S, T, P, C, F> FastbootImplementation
498*5225e6b1SAndroid Build Coastguard Worker     for GblFastboot<'a, 'b, 'c, '_, 'e, G, B, S, T, P, C, F>
499*5225e6b1SAndroid Build Coastguard Worker where
500*5225e6b1SAndroid Build Coastguard Worker     G: GblOps<'a, 'e>,
501*5225e6b1SAndroid Build Coastguard Worker     B: BlockIo,
502*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
503*5225e6b1SAndroid Build Coastguard Worker     T: DerefMut<Target = [u8]>,
504*5225e6b1SAndroid Build Coastguard Worker     P: BufferPool,
505*5225e6b1SAndroid Build Coastguard Worker     C: PinFutContainerTyped<'c, F>,
506*5225e6b1SAndroid Build Coastguard Worker     F: Future<Output = ()> + 'c,
507*5225e6b1SAndroid Build Coastguard Worker {
get_var( &mut self, var: &CStr, args: impl Iterator<Item = &'_ CStr> + Clone, out: &mut [u8], _: impl InfoSender, ) -> CommandResult<usize>508*5225e6b1SAndroid Build Coastguard Worker     async fn get_var(
509*5225e6b1SAndroid Build Coastguard Worker         &mut self,
510*5225e6b1SAndroid Build Coastguard Worker         var: &CStr,
511*5225e6b1SAndroid Build Coastguard Worker         args: impl Iterator<Item = &'_ CStr> + Clone,
512*5225e6b1SAndroid Build Coastguard Worker         out: &mut [u8],
513*5225e6b1SAndroid Build Coastguard Worker         _: impl InfoSender,
514*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<usize> {
515*5225e6b1SAndroid Build Coastguard Worker         Ok(self.get_var_internal(var, args, out)?.len())
516*5225e6b1SAndroid Build Coastguard Worker     }
517*5225e6b1SAndroid Build Coastguard Worker 
get_var_all(&mut self, mut resp: impl VarInfoSender) -> CommandResult<()>518*5225e6b1SAndroid Build Coastguard Worker     async fn get_var_all(&mut self, mut resp: impl VarInfoSender) -> CommandResult<()> {
519*5225e6b1SAndroid Build Coastguard Worker         self.get_var_all_internal(&mut resp).await
520*5225e6b1SAndroid Build Coastguard Worker     }
521*5225e6b1SAndroid Build Coastguard Worker 
get_download_buffer(&mut self) -> &mut [u8]522*5225e6b1SAndroid Build Coastguard Worker     async fn get_download_buffer(&mut self) -> &mut [u8] {
523*5225e6b1SAndroid Build Coastguard Worker         if self.current_download_buffer.is_none() {
524*5225e6b1SAndroid Build Coastguard Worker             self.current_download_buffer = Some(self.buffer_pool.allocate_async().await);
525*5225e6b1SAndroid Build Coastguard Worker         }
526*5225e6b1SAndroid Build Coastguard Worker         self.current_download_buffer.as_mut().unwrap()
527*5225e6b1SAndroid Build Coastguard Worker     }
528*5225e6b1SAndroid Build Coastguard Worker 
download_complete( &mut self, download_size: usize, _: impl InfoSender, ) -> CommandResult<()>529*5225e6b1SAndroid Build Coastguard Worker     async fn download_complete(
530*5225e6b1SAndroid Build Coastguard Worker         &mut self,
531*5225e6b1SAndroid Build Coastguard Worker         download_size: usize,
532*5225e6b1SAndroid Build Coastguard Worker         _: impl InfoSender,
533*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<()> {
534*5225e6b1SAndroid Build Coastguard Worker         self.current_download_size = download_size;
535*5225e6b1SAndroid Build Coastguard Worker         Ok(())
536*5225e6b1SAndroid Build Coastguard Worker     }
537*5225e6b1SAndroid Build Coastguard Worker 
flash(&mut self, part: &str, mut responder: impl InfoSender) -> CommandResult<()>538*5225e6b1SAndroid Build Coastguard Worker     async fn flash(&mut self, part: &str, mut responder: impl InfoSender) -> CommandResult<()> {
539*5225e6b1SAndroid Build Coastguard Worker         let disks = self.disks;
540*5225e6b1SAndroid Build Coastguard Worker 
541*5225e6b1SAndroid Build Coastguard Worker         // Checks if we are flashing new GPT partition table
542*5225e6b1SAndroid Build Coastguard Worker         if let Some((blk_idx, resize)) = self.parse_flash_gpt_args(part)? {
543*5225e6b1SAndroid Build Coastguard Worker             self.wait_partition_io(blk_idx, None).await?;
544*5225e6b1SAndroid Build Coastguard Worker             let (mut gpt, size) = self.take_download().ok_or("No GPT downloaded")?;
545*5225e6b1SAndroid Build Coastguard Worker             responder.send_info("Updating GPT...").await?;
546*5225e6b1SAndroid Build Coastguard Worker             return match disks[blk_idx].update_gpt(&mut gpt[..size], resize).await {
547*5225e6b1SAndroid Build Coastguard Worker                 Err(Error::NotReady) => panic!("Should not be busy"),
548*5225e6b1SAndroid Build Coastguard Worker                 Err(Error::Unsupported) => Err("Block device is not for GPT".into()),
549*5225e6b1SAndroid Build Coastguard Worker                 v => Ok(v?),
550*5225e6b1SAndroid Build Coastguard Worker             };
551*5225e6b1SAndroid Build Coastguard Worker         }
552*5225e6b1SAndroid Build Coastguard Worker 
553*5225e6b1SAndroid Build Coastguard Worker         let (blk_idx, part_io) = self.parse_and_get_partition_io(part).await?;
554*5225e6b1SAndroid Build Coastguard Worker         let (download_buffer, data_size) = self.take_download().ok_or("No download")?;
555*5225e6b1SAndroid Build Coastguard Worker         let write_task = Task::Flash(part_io, download_buffer, data_size);
556*5225e6b1SAndroid Build Coastguard Worker         self.schedule_task(write_task, &mut responder).await?;
557*5225e6b1SAndroid Build Coastguard Worker         // Checks if block is ready already and returns errors. This can be the case when the
558*5225e6b1SAndroid Build Coastguard Worker         // operation is synchronous or runs into early errors.
559*5225e6b1SAndroid Build Coastguard Worker         Ok(disks[blk_idx].status().result()?)
560*5225e6b1SAndroid Build Coastguard Worker     }
561*5225e6b1SAndroid Build Coastguard Worker 
erase(&mut self, part: &str, mut responder: impl InfoSender) -> CommandResult<()>562*5225e6b1SAndroid Build Coastguard Worker     async fn erase(&mut self, part: &str, mut responder: impl InfoSender) -> CommandResult<()> {
563*5225e6b1SAndroid Build Coastguard Worker         let disks = self.disks;
564*5225e6b1SAndroid Build Coastguard Worker 
565*5225e6b1SAndroid Build Coastguard Worker         // Checks if we are erasing GPT partition table.
566*5225e6b1SAndroid Build Coastguard Worker         if let Some((blk_idx, _)) = self.parse_flash_gpt_args(part)? {
567*5225e6b1SAndroid Build Coastguard Worker             self.wait_partition_io(blk_idx, None).await?;
568*5225e6b1SAndroid Build Coastguard Worker             return match disks[blk_idx].erase_gpt().await {
569*5225e6b1SAndroid Build Coastguard Worker                 Err(Error::NotReady) => panic!("Should not be busy"),
570*5225e6b1SAndroid Build Coastguard Worker                 Err(Error::Unsupported) => Err("Block device is not for GPT".into()),
571*5225e6b1SAndroid Build Coastguard Worker                 v => Ok(v?),
572*5225e6b1SAndroid Build Coastguard Worker             };
573*5225e6b1SAndroid Build Coastguard Worker         }
574*5225e6b1SAndroid Build Coastguard Worker 
575*5225e6b1SAndroid Build Coastguard Worker         let (blk_idx, part_io) = self.parse_and_get_partition_io(part).await?;
576*5225e6b1SAndroid Build Coastguard Worker         self.get_download_buffer().await;
577*5225e6b1SAndroid Build Coastguard Worker         let erase_task = Task::Erase(part_io, self.take_download().unwrap().0);
578*5225e6b1SAndroid Build Coastguard Worker         self.schedule_task(erase_task, &mut responder).await?;
579*5225e6b1SAndroid Build Coastguard Worker         // Checks if block is ready already and returns errors. This can be the case when the
580*5225e6b1SAndroid Build Coastguard Worker         // operation is synchronous or runs into early errors.
581*5225e6b1SAndroid Build Coastguard Worker         Ok(disks[blk_idx].status().result()?)
582*5225e6b1SAndroid Build Coastguard Worker     }
583*5225e6b1SAndroid Build Coastguard Worker 
upload(&mut self, _: impl UploadBuilder) -> CommandResult<()>584*5225e6b1SAndroid Build Coastguard Worker     async fn upload(&mut self, _: impl UploadBuilder) -> CommandResult<()> {
585*5225e6b1SAndroid Build Coastguard Worker         Err("Unimplemented".into())
586*5225e6b1SAndroid Build Coastguard Worker     }
587*5225e6b1SAndroid Build Coastguard Worker 
fetch( &mut self, part: &str, offset: u64, size: u64, mut responder: impl UploadBuilder + InfoSender, ) -> CommandResult<()>588*5225e6b1SAndroid Build Coastguard Worker     async fn fetch(
589*5225e6b1SAndroid Build Coastguard Worker         &mut self,
590*5225e6b1SAndroid Build Coastguard Worker         part: &str,
591*5225e6b1SAndroid Build Coastguard Worker         offset: u64,
592*5225e6b1SAndroid Build Coastguard Worker         size: u64,
593*5225e6b1SAndroid Build Coastguard Worker         mut responder: impl UploadBuilder + InfoSender,
594*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<()> {
595*5225e6b1SAndroid Build Coastguard Worker         let (_, mut part_io) = self.parse_and_get_partition_io(part).await?;
596*5225e6b1SAndroid Build Coastguard Worker         let buffer = self.get_download_buffer().await;
597*5225e6b1SAndroid Build Coastguard Worker         let end = u64::try_from(SafeNum::from(offset) + size)?;
598*5225e6b1SAndroid Build Coastguard Worker         let mut curr = offset;
599*5225e6b1SAndroid Build Coastguard Worker         responder
600*5225e6b1SAndroid Build Coastguard Worker             .send_formatted_info(|v| write!(v, "Uploading {} bytes...", size).unwrap())
601*5225e6b1SAndroid Build Coastguard Worker             .await?;
602*5225e6b1SAndroid Build Coastguard Worker         let mut uploader = responder.initiate_upload(size).await?;
603*5225e6b1SAndroid Build Coastguard Worker         while curr < end {
604*5225e6b1SAndroid Build Coastguard Worker             let to_send = min(usize::try_from(end - curr)?, buffer.len());
605*5225e6b1SAndroid Build Coastguard Worker             part_io.read(curr, &mut buffer[..to_send]).await?;
606*5225e6b1SAndroid Build Coastguard Worker             uploader.upload(&mut buffer[..to_send]).await?;
607*5225e6b1SAndroid Build Coastguard Worker             curr += u64::try_from(to_send)?;
608*5225e6b1SAndroid Build Coastguard Worker         }
609*5225e6b1SAndroid Build Coastguard Worker         Ok(())
610*5225e6b1SAndroid Build Coastguard Worker     }
611*5225e6b1SAndroid Build Coastguard Worker 
reboot( &mut self, mode: RebootMode, resp: impl InfoSender + OkaySender, ) -> CommandError612*5225e6b1SAndroid Build Coastguard Worker     async fn reboot(
613*5225e6b1SAndroid Build Coastguard Worker         &mut self,
614*5225e6b1SAndroid Build Coastguard Worker         mode: RebootMode,
615*5225e6b1SAndroid Build Coastguard Worker         resp: impl InfoSender + OkaySender,
616*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandError {
617*5225e6b1SAndroid Build Coastguard Worker         match self.sync_block_and_reboot(mode, resp).await {
618*5225e6b1SAndroid Build Coastguard Worker             Err(e) => e,
619*5225e6b1SAndroid Build Coastguard Worker             _ => "Unknown".into(),
620*5225e6b1SAndroid Build Coastguard Worker         }
621*5225e6b1SAndroid Build Coastguard Worker     }
622*5225e6b1SAndroid Build Coastguard Worker 
623*5225e6b1SAndroid Build Coastguard Worker     async fn r#continue(&mut self, mut resp: impl InfoSender) -> CommandResult<()> {
624*5225e6b1SAndroid Build Coastguard Worker         resp.send_info("Syncing storage...").await?;
625*5225e6b1SAndroid Build Coastguard Worker         Ok(self.sync_all_blocks().await?)
626*5225e6b1SAndroid Build Coastguard Worker     }
627*5225e6b1SAndroid Build Coastguard Worker 
set_active(&mut self, slot: &str, _: impl InfoSender) -> CommandResult<()>628*5225e6b1SAndroid Build Coastguard Worker     async fn set_active(&mut self, slot: &str, _: impl InfoSender) -> CommandResult<()> {
629*5225e6b1SAndroid Build Coastguard Worker         self.sync_all_blocks().await?;
630*5225e6b1SAndroid Build Coastguard Worker         match self.gbl_ops.expected_os_is_fuchsia()? {
631*5225e6b1SAndroid Build Coastguard Worker             // TODO(b/374776896): Prioritizes platform specific `set_active_slot`  if available.
632*5225e6b1SAndroid Build Coastguard Worker             true => Ok(mark_slot_active(
633*5225e6b1SAndroid Build Coastguard Worker                 &mut GblAbrOps(self.gbl_ops),
634*5225e6b1SAndroid Build Coastguard Worker                 match slot {
635*5225e6b1SAndroid Build Coastguard Worker                     "a" => SlotIndex::A,
636*5225e6b1SAndroid Build Coastguard Worker                     "b" => SlotIndex::B,
637*5225e6b1SAndroid Build Coastguard Worker                     _ => return Err("Invalid slot index for Fuchsia A/B/R".into()),
638*5225e6b1SAndroid Build Coastguard Worker                 },
639*5225e6b1SAndroid Build Coastguard Worker             )?),
640*5225e6b1SAndroid Build Coastguard Worker             _ => Err("Not supported".into()),
641*5225e6b1SAndroid Build Coastguard Worker         }
642*5225e6b1SAndroid Build Coastguard Worker     }
643*5225e6b1SAndroid Build Coastguard Worker 
oem<'s>( &mut self, cmd: &str, mut responder: impl InfoSender, res: &'s mut [u8], ) -> CommandResult<&'s [u8]>644*5225e6b1SAndroid Build Coastguard Worker     async fn oem<'s>(
645*5225e6b1SAndroid Build Coastguard Worker         &mut self,
646*5225e6b1SAndroid Build Coastguard Worker         cmd: &str,
647*5225e6b1SAndroid Build Coastguard Worker         mut responder: impl InfoSender,
648*5225e6b1SAndroid Build Coastguard Worker         res: &'s mut [u8],
649*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<&'s [u8]> {
650*5225e6b1SAndroid Build Coastguard Worker         let mut args = cmd.split(' ');
651*5225e6b1SAndroid Build Coastguard Worker         let cmd = args.next().ok_or("Missing command")?;
652*5225e6b1SAndroid Build Coastguard Worker         match cmd {
653*5225e6b1SAndroid Build Coastguard Worker             "gbl-sync-tasks" => self.oem_sync_blocks(responder, res).await,
654*5225e6b1SAndroid Build Coastguard Worker             "gbl-enable-async-task" => {
655*5225e6b1SAndroid Build Coastguard Worker                 self.enable_async_task = true;
656*5225e6b1SAndroid Build Coastguard Worker                 Ok(b"")
657*5225e6b1SAndroid Build Coastguard Worker             }
658*5225e6b1SAndroid Build Coastguard Worker             "gbl-disable-async-task" => {
659*5225e6b1SAndroid Build Coastguard Worker                 self.enable_async_task = false;
660*5225e6b1SAndroid Build Coastguard Worker                 Ok(b"")
661*5225e6b1SAndroid Build Coastguard Worker             }
662*5225e6b1SAndroid Build Coastguard Worker             "gbl-unset-default-block" => {
663*5225e6b1SAndroid Build Coastguard Worker                 self.default_block = None;
664*5225e6b1SAndroid Build Coastguard Worker                 Ok(b"")
665*5225e6b1SAndroid Build Coastguard Worker             }
666*5225e6b1SAndroid Build Coastguard Worker             "gbl-set-default-block" => {
667*5225e6b1SAndroid Build Coastguard Worker                 let id = next_arg_u64(&mut args)?.ok_or("Missing block device ID")?;
668*5225e6b1SAndroid Build Coastguard Worker                 let id = usize::try_from(id)?;
669*5225e6b1SAndroid Build Coastguard Worker                 self.disks.get(id).ok_or("Out of range")?;
670*5225e6b1SAndroid Build Coastguard Worker                 self.default_block = Some(id.try_into()?);
671*5225e6b1SAndroid Build Coastguard Worker                 responder
672*5225e6b1SAndroid Build Coastguard Worker                     .send_formatted_info(|f| write!(f, "Default block device: {id:#x}").unwrap())
673*5225e6b1SAndroid Build Coastguard Worker                     .await?;
674*5225e6b1SAndroid Build Coastguard Worker                 Ok(b"")
675*5225e6b1SAndroid Build Coastguard Worker             }
676*5225e6b1SAndroid Build Coastguard Worker             "add-staged-bootloader-file" => {
677*5225e6b1SAndroid Build Coastguard Worker                 let file_name = next_arg(&mut args).ok_or("Missing file name")?;
678*5225e6b1SAndroid Build Coastguard Worker                 self.add_staged_bootloader_file(file_name).await?;
679*5225e6b1SAndroid Build Coastguard Worker                 Ok(b"")
680*5225e6b1SAndroid Build Coastguard Worker             }
681*5225e6b1SAndroid Build Coastguard Worker             _ => Err("Unknown oem command".into()),
682*5225e6b1SAndroid Build Coastguard Worker         }
683*5225e6b1SAndroid Build Coastguard Worker     }
684*5225e6b1SAndroid Build Coastguard Worker 
boot(&mut self, mut resp: impl InfoSender + OkaySender) -> CommandResult<()>685*5225e6b1SAndroid Build Coastguard Worker     async fn boot(&mut self, mut resp: impl InfoSender + OkaySender) -> CommandResult<()> {
686*5225e6b1SAndroid Build Coastguard Worker         let len = core::cmp::min(self.bootimg_buf.len(), self.current_download_size);
687*5225e6b1SAndroid Build Coastguard Worker         let data = self.current_download_buffer.as_mut().ok_or("No file staged")?;
688*5225e6b1SAndroid Build Coastguard Worker         let data = &mut data[..self.current_download_size];
689*5225e6b1SAndroid Build Coastguard Worker 
690*5225e6b1SAndroid Build Coastguard Worker         self.bootimg_buf[..len].copy_from_slice(&data[..len]);
691*5225e6b1SAndroid Build Coastguard Worker         resp.send_info("Boot into boot.img").await?;
692*5225e6b1SAndroid Build Coastguard Worker         Ok(())
693*5225e6b1SAndroid Build Coastguard Worker     }
694*5225e6b1SAndroid Build Coastguard Worker }
695*5225e6b1SAndroid Build Coastguard Worker 
696*5225e6b1SAndroid Build Coastguard Worker /// `GblUsbTransport` defines transport interfaces for running GBL fastboot over USB.
697*5225e6b1SAndroid Build Coastguard Worker pub trait GblUsbTransport: Transport {
698*5225e6b1SAndroid Build Coastguard Worker     /// Checks whether there is a new USB packet.
has_packet(&mut self) -> bool699*5225e6b1SAndroid Build Coastguard Worker     fn has_packet(&mut self) -> bool;
700*5225e6b1SAndroid Build Coastguard Worker }
701*5225e6b1SAndroid Build Coastguard Worker 
702*5225e6b1SAndroid Build Coastguard Worker /// `GblTcpStream` defines transport interfaces for running GBL fastboot over TCP.
703*5225e6b1SAndroid Build Coastguard Worker pub trait GblTcpStream: TcpStream {
704*5225e6b1SAndroid Build Coastguard Worker     /// Accepts a new TCP connection.
705*5225e6b1SAndroid Build Coastguard Worker     ///
706*5225e6b1SAndroid Build Coastguard Worker     /// If a connection is in progress, it should be aborted first.
707*5225e6b1SAndroid Build Coastguard Worker     ///
708*5225e6b1SAndroid Build Coastguard Worker     /// Returns true if a new connection is established, false otherwise.
accept_new(&mut self) -> bool709*5225e6b1SAndroid Build Coastguard Worker     fn accept_new(&mut self) -> bool;
710*5225e6b1SAndroid Build Coastguard Worker }
711*5225e6b1SAndroid Build Coastguard Worker 
712*5225e6b1SAndroid Build Coastguard Worker /// Runs GBL fastboot on the given USB/TCP channels.
713*5225e6b1SAndroid Build Coastguard Worker ///
714*5225e6b1SAndroid Build Coastguard Worker /// # Args:
715*5225e6b1SAndroid Build Coastguard Worker ///
716*5225e6b1SAndroid Build Coastguard Worker /// * `gbl_ops`: An instance of [GblOps].
717*5225e6b1SAndroid Build Coastguard Worker /// * `buffer_pool`: An implementation of [BufferPool].
718*5225e6b1SAndroid Build Coastguard Worker /// * `tasks`: An implementation of [PinFutContainer]
719*5225e6b1SAndroid Build Coastguard Worker /// * `usb`: An optional implementation of [GblUsbTransport].
720*5225e6b1SAndroid Build Coastguard Worker /// * `tcp`: An optional implementation of [GblTcpStream].
721*5225e6b1SAndroid Build Coastguard Worker ///
722*5225e6b1SAndroid Build Coastguard Worker /// # Lifetimes
723*5225e6b1SAndroid Build Coastguard Worker /// * `'a`: Lifetime of [GblOps].
724*5225e6b1SAndroid Build Coastguard Worker /// * `'b`: Lifetime of `download_buffers`.
725*5225e6b1SAndroid Build Coastguard Worker /// * `'c`: Lifetime of `tasks`.
run_gbl_fastboot<'a: 'c, 'b: 'c, 'c, 'd>( gbl_ops: &mut impl GblOps<'a, 'd>, buffer_pool: &'b Shared<impl BufferPool>, tasks: impl PinFutContainer<'c> + 'c, usb: Option<impl GblUsbTransport>, tcp: Option<impl GblTcpStream>, bootimg_buf: &'b mut [u8], )726*5225e6b1SAndroid Build Coastguard Worker pub async fn run_gbl_fastboot<'a: 'c, 'b: 'c, 'c, 'd>(
727*5225e6b1SAndroid Build Coastguard Worker     gbl_ops: &mut impl GblOps<'a, 'd>,
728*5225e6b1SAndroid Build Coastguard Worker     buffer_pool: &'b Shared<impl BufferPool>,
729*5225e6b1SAndroid Build Coastguard Worker     tasks: impl PinFutContainer<'c> + 'c,
730*5225e6b1SAndroid Build Coastguard Worker     usb: Option<impl GblUsbTransport>,
731*5225e6b1SAndroid Build Coastguard Worker     tcp: Option<impl GblTcpStream>,
732*5225e6b1SAndroid Build Coastguard Worker     bootimg_buf: &'b mut [u8],
733*5225e6b1SAndroid Build Coastguard Worker ) {
734*5225e6b1SAndroid Build Coastguard Worker     let tasks = tasks.into();
735*5225e6b1SAndroid Build Coastguard Worker     let disks = gbl_ops.disks();
736*5225e6b1SAndroid Build Coastguard Worker     GblFastboot::new(gbl_ops, disks, Task::run, &tasks, buffer_pool, bootimg_buf)
737*5225e6b1SAndroid Build Coastguard Worker         .run(usb, tcp)
738*5225e6b1SAndroid Build Coastguard Worker         .await;
739*5225e6b1SAndroid Build Coastguard Worker }
740*5225e6b1SAndroid Build Coastguard Worker 
741*5225e6b1SAndroid Build Coastguard Worker /// Runs GBL fastboot on the given USB/TCP channels with N stack allocated worker tasks.
742*5225e6b1SAndroid Build Coastguard Worker ///
743*5225e6b1SAndroid Build Coastguard Worker /// The choice of N depends on the level of parallelism the platform can support. For platform with
744*5225e6b1SAndroid Build Coastguard Worker /// `n` storage devices that can independently perform non-blocking IO, it will required `N = n`
745*5225e6b1SAndroid Build Coastguard Worker /// and a `buffer_pool` that can allocate at least n+1 buffers at the same time in order to achieve
746*5225e6b1SAndroid Build Coastguard Worker /// parallel flashing to all storages plus a parallel downloading. However, it is common for
747*5225e6b1SAndroid Build Coastguard Worker /// disks that need to be flashed to be on the same block deviece so flashing of them becomes
748*5225e6b1SAndroid Build Coastguard Worker /// sequential, in which case N can be smaller. Caller should take into consideration usage pattern
749*5225e6b1SAndroid Build Coastguard Worker /// for determining N.
750*5225e6b1SAndroid Build Coastguard Worker ///
751*5225e6b1SAndroid Build Coastguard Worker /// # Args:
752*5225e6b1SAndroid Build Coastguard Worker ///
753*5225e6b1SAndroid Build Coastguard Worker /// * `gbl_ops`: An instance of [GblOps].
754*5225e6b1SAndroid Build Coastguard Worker /// * `buffer_pool`: An implementation of [BufferPool].
755*5225e6b1SAndroid Build Coastguard Worker /// * `usb`: An optional implementation of [GblUsbTransport].
756*5225e6b1SAndroid Build Coastguard Worker /// * `tcp`: An optional implementation of [GblTcpStream].
run_gbl_fastboot_stack<'a, 'b, const N: usize>( gbl_ops: &mut impl GblOps<'a, 'b>, buffer_pool: impl BufferPool, usb: Option<impl GblUsbTransport>, tcp: Option<impl GblTcpStream>, bootimg_buf: &mut [u8], )757*5225e6b1SAndroid Build Coastguard Worker pub async fn run_gbl_fastboot_stack<'a, 'b, const N: usize>(
758*5225e6b1SAndroid Build Coastguard Worker     gbl_ops: &mut impl GblOps<'a, 'b>,
759*5225e6b1SAndroid Build Coastguard Worker     buffer_pool: impl BufferPool,
760*5225e6b1SAndroid Build Coastguard Worker     usb: Option<impl GblUsbTransport>,
761*5225e6b1SAndroid Build Coastguard Worker     tcp: Option<impl GblTcpStream>,
762*5225e6b1SAndroid Build Coastguard Worker     bootimg_buf: &mut [u8],
763*5225e6b1SAndroid Build Coastguard Worker ) {
764*5225e6b1SAndroid Build Coastguard Worker     let buffer_pool = buffer_pool.into();
765*5225e6b1SAndroid Build Coastguard Worker     // Creates N worker tasks.
766*5225e6b1SAndroid Build Coastguard Worker     let mut tasks: [_; N] = from_fn(|_| Task::None.run());
767*5225e6b1SAndroid Build Coastguard Worker     // It is possible to avoid the use of the unsafe `Pin::new_unchecked` by delaring the array and
768*5225e6b1SAndroid Build Coastguard Worker     // manually pinning each element i.e.
769*5225e6b1SAndroid Build Coastguard Worker     //
770*5225e6b1SAndroid Build Coastguard Worker     // ```
771*5225e6b1SAndroid Build Coastguard Worker     // let mut tasks = [
772*5225e6b1SAndroid Build Coastguard Worker     //     core::pin::pin!(Task::None.run()),
773*5225e6b1SAndroid Build Coastguard Worker     //     core::pin::pin!(Task::None.run()),
774*5225e6b1SAndroid Build Coastguard Worker     //     core::pin::pin!(Task::None.run()),
775*5225e6b1SAndroid Build Coastguard Worker     // ];
776*5225e6b1SAndroid Build Coastguard Worker     // ```
777*5225e6b1SAndroid Build Coastguard Worker     //
778*5225e6b1SAndroid Build Coastguard Worker     // Parameterization of `N` will be an issue, but might be solvable with procedural macro.
779*5225e6b1SAndroid Build Coastguard Worker     // SAFETY: `tasks` is immediately shadowed and thus guaranteed not moved for the rest of its
780*5225e6b1SAndroid Build Coastguard Worker     // lifetime.
781*5225e6b1SAndroid Build Coastguard Worker     let mut tasks: [_; N] = tasks.each_mut().map(|v| unsafe { Pin::new_unchecked(v) });
782*5225e6b1SAndroid Build Coastguard Worker     let tasks = PinFutSlice::new(&mut tasks[..]).into();
783*5225e6b1SAndroid Build Coastguard Worker     let disks = gbl_ops.disks();
784*5225e6b1SAndroid Build Coastguard Worker     GblFastboot::new(gbl_ops, disks, Task::run, &tasks, &buffer_pool, bootimg_buf)
785*5225e6b1SAndroid Build Coastguard Worker         .run(usb, tcp)
786*5225e6b1SAndroid Build Coastguard Worker         .await;
787*5225e6b1SAndroid Build Coastguard Worker }
788*5225e6b1SAndroid Build Coastguard Worker 
789*5225e6b1SAndroid Build Coastguard Worker /// Pre-generates a Fuchsia Fastboot MDNS service broadcast packet.
790*5225e6b1SAndroid Build Coastguard Worker ///
791*5225e6b1SAndroid Build Coastguard Worker /// Fuchsia ffx development flow can detect fastboot devices that broadcast a "_fastboot·_tcp·local"
792*5225e6b1SAndroid Build Coastguard Worker /// MDNS service. This API generates the broadcast MDNS packet for Ipv6. Caller is reponsible for
793*5225e6b1SAndroid Build Coastguard Worker /// sending this packet via UDP at the following address and port (defined by MDNS):
794*5225e6b1SAndroid Build Coastguard Worker ///
795*5225e6b1SAndroid Build Coastguard Worker /// * ipv6: ff02::fb
796*5225e6b1SAndroid Build Coastguard Worker /// * port: 5353
797*5225e6b1SAndroid Build Coastguard Worker ///
798*5225e6b1SAndroid Build Coastguard Worker /// # Args
799*5225e6b1SAndroid Build Coastguard Worker ///
800*5225e6b1SAndroid Build Coastguard Worker /// * `node_name`: The Fuchsia node name for the service. Must be a 22 character ASCII string in the
801*5225e6b1SAndroid Build Coastguard Worker ///   format "fuchsia-xxxx-xxxx-xxxx".
802*5225e6b1SAndroid Build Coastguard Worker /// * `ipv6_addr`: The Ipv6 address bytes.
803*5225e6b1SAndroid Build Coastguard Worker ///
804*5225e6b1SAndroid Build Coastguard Worker /// The packet generated by the API contains the given IPv6 address and a fuchsia node name derived
805*5225e6b1SAndroid Build Coastguard Worker /// from the given ethernet mac address `eth_mac`.
fuchsia_fastboot_mdns_packet(node_name: &str, ipv6_addr: &[u8]) -> Result<[u8; 140], Error>806*5225e6b1SAndroid Build Coastguard Worker pub fn fuchsia_fastboot_mdns_packet(node_name: &str, ipv6_addr: &[u8]) -> Result<[u8; 140], Error> {
807*5225e6b1SAndroid Build Coastguard Worker     // Pre-generated Fuchsia fastboot MDNS service packet template.
808*5225e6b1SAndroid Build Coastguard Worker     // It contains the node name and ipv6 address. We simply replace with the device's node name and
809*5225e6b1SAndroid Build Coastguard Worker     // ipv6 address.
810*5225e6b1SAndroid Build Coastguard Worker     let mut packet: [u8; 140] = [
811*5225e6b1SAndroid Build Coastguard Worker         0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x09, 0x5f, 0x66,
812*5225e6b1SAndroid Build Coastguard Worker         0x61, 0x73, 0x74, 0x62, 0x6f, 0x6f, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x6c, 0x6f,
813*5225e6b1SAndroid Build Coastguard Worker         0x63, 0x61, 0x6c, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x19, 0x16,
814*5225e6b1SAndroid Build Coastguard Worker         0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2d, 0x34, 0x38, 0x32, 0x31, 0x2d, 0x30, 0x62,
815*5225e6b1SAndroid Build Coastguard Worker         0x33, 0x31, 0x2d, 0x65, 0x61, 0x66, 0x38, 0xc0, 0x0c, 0xc0, 0x2c, 0x00, 0x21, 0x80, 0x01,
816*5225e6b1SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x78, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x15, 0xb2, 0x16, 0x66, 0x75,
817*5225e6b1SAndroid Build Coastguard Worker         0x63, 0x68, 0x73, 0x69, 0x61, 0x2d, 0x34, 0x38, 0x32, 0x31, 0x2d, 0x30, 0x62, 0x33, 0x31,
818*5225e6b1SAndroid Build Coastguard Worker         0x2d, 0x65, 0x61, 0x66, 0x38, 0xc0, 0x1b, 0xc0, 0x57, 0x00, 0x1c, 0x80, 0x01, 0x00, 0x00,
819*5225e6b1SAndroid Build Coastguard Worker         0x00, 0x78, 0x00, 0x10, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x21, 0x0b,
820*5225e6b1SAndroid Build Coastguard Worker         0xff, 0xfe, 0x31, 0xea, 0xf8,
821*5225e6b1SAndroid Build Coastguard Worker     ];
822*5225e6b1SAndroid Build Coastguard Worker     // Offsets to the fuchsia node name field.
823*5225e6b1SAndroid Build Coastguard Worker     const NODE_NAME_OFFSETS: &[usize; 2] = &[45, 88];
824*5225e6b1SAndroid Build Coastguard Worker     // Offset to the IPv6 address field.
825*5225e6b1SAndroid Build Coastguard Worker     const IP6_ADDR_OFFSET: usize = 124;
826*5225e6b1SAndroid Build Coastguard Worker 
827*5225e6b1SAndroid Build Coastguard Worker     if node_name.as_bytes().len() != 22 {
828*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::InvalidInput);
829*5225e6b1SAndroid Build Coastguard Worker     }
830*5225e6b1SAndroid Build Coastguard Worker 
831*5225e6b1SAndroid Build Coastguard Worker     for off in NODE_NAME_OFFSETS {
832*5225e6b1SAndroid Build Coastguard Worker         packet[*off..][..node_name.len()].clone_from_slice(node_name.as_bytes());
833*5225e6b1SAndroid Build Coastguard Worker     }
834*5225e6b1SAndroid Build Coastguard Worker     packet[IP6_ADDR_OFFSET..][..ipv6_addr.len()].clone_from_slice(ipv6_addr);
835*5225e6b1SAndroid Build Coastguard Worker     Ok(packet)
836*5225e6b1SAndroid Build Coastguard Worker }
837*5225e6b1SAndroid Build Coastguard Worker 
838*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
839*5225e6b1SAndroid Build Coastguard Worker mod test {
840*5225e6b1SAndroid Build Coastguard Worker     use super::*;
841*5225e6b1SAndroid Build Coastguard Worker     use crate::{
842*5225e6b1SAndroid Build Coastguard Worker         ops::test::{FakeGblOps, FakeGblOpsStorage},
843*5225e6b1SAndroid Build Coastguard Worker         Os,
844*5225e6b1SAndroid Build Coastguard Worker     };
845*5225e6b1SAndroid Build Coastguard Worker     use abr::{
846*5225e6b1SAndroid Build Coastguard Worker         get_and_clear_one_shot_bootloader, get_boot_slot, mark_slot_unbootable, ABR_DATA_SIZE,
847*5225e6b1SAndroid Build Coastguard Worker     };
848*5225e6b1SAndroid Build Coastguard Worker     use core::{
849*5225e6b1SAndroid Build Coastguard Worker         mem::size_of,
850*5225e6b1SAndroid Build Coastguard Worker         pin::{pin, Pin},
851*5225e6b1SAndroid Build Coastguard Worker         str::from_utf8,
852*5225e6b1SAndroid Build Coastguard Worker     };
853*5225e6b1SAndroid Build Coastguard Worker     use fastboot::{test_utils::TestUploadBuilder, MAX_RESPONSE_SIZE};
854*5225e6b1SAndroid Build Coastguard Worker     use gbl_async::{block_on, poll, poll_n_times};
855*5225e6b1SAndroid Build Coastguard Worker     use gbl_storage::GPT_GUID_LEN;
856*5225e6b1SAndroid Build Coastguard Worker     use liberror::Error;
857*5225e6b1SAndroid Build Coastguard Worker     use spin::{Mutex, MutexGuard};
858*5225e6b1SAndroid Build Coastguard Worker     use std::ffi::CString;
859*5225e6b1SAndroid Build Coastguard Worker     use std::{collections::VecDeque, io::Read};
860*5225e6b1SAndroid Build Coastguard Worker     use zerocopy::AsBytes;
861*5225e6b1SAndroid Build Coastguard Worker 
862*5225e6b1SAndroid Build Coastguard Worker     /// A test implementation of [InfoSender] and [OkaySender].
863*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
864*5225e6b1SAndroid Build Coastguard Worker     struct TestResponder {
865*5225e6b1SAndroid Build Coastguard Worker         okay_sent: Mutex<bool>,
866*5225e6b1SAndroid Build Coastguard Worker         info_messages: Mutex<Vec<String>>,
867*5225e6b1SAndroid Build Coastguard Worker     }
868*5225e6b1SAndroid Build Coastguard Worker 
869*5225e6b1SAndroid Build Coastguard Worker     impl InfoSender for &TestResponder {
send_formatted_info<F: FnOnce(&mut dyn Write)>( &mut self, cb: F, ) -> Result<(), Error>870*5225e6b1SAndroid Build Coastguard Worker         async fn send_formatted_info<F: FnOnce(&mut dyn Write)>(
871*5225e6b1SAndroid Build Coastguard Worker             &mut self,
872*5225e6b1SAndroid Build Coastguard Worker             cb: F,
873*5225e6b1SAndroid Build Coastguard Worker         ) -> Result<(), Error> {
874*5225e6b1SAndroid Build Coastguard Worker             let mut msg: String = "".into();
875*5225e6b1SAndroid Build Coastguard Worker             cb(&mut msg);
876*5225e6b1SAndroid Build Coastguard Worker             self.info_messages.try_lock().unwrap().push(msg);
877*5225e6b1SAndroid Build Coastguard Worker             Ok(())
878*5225e6b1SAndroid Build Coastguard Worker         }
879*5225e6b1SAndroid Build Coastguard Worker     }
880*5225e6b1SAndroid Build Coastguard Worker 
881*5225e6b1SAndroid Build Coastguard Worker     impl OkaySender for &TestResponder {
882*5225e6b1SAndroid Build Coastguard Worker         /// Sends a Fastboot "INFO<`msg`>" packet.
send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, _: F) -> Result<(), Error>883*5225e6b1SAndroid Build Coastguard Worker         async fn send_formatted_okay<F: FnOnce(&mut dyn Write)>(self, _: F) -> Result<(), Error> {
884*5225e6b1SAndroid Build Coastguard Worker             *self.okay_sent.try_lock().unwrap() = true;
885*5225e6b1SAndroid Build Coastguard Worker             Ok(())
886*5225e6b1SAndroid Build Coastguard Worker         }
887*5225e6b1SAndroid Build Coastguard Worker     }
888*5225e6b1SAndroid Build Coastguard Worker 
889*5225e6b1SAndroid Build Coastguard Worker     /// Helper to test fastboot variable value.
check_var(gbl_fb: &mut impl FastbootImplementation, var: &str, args: &str, expected: &str)890*5225e6b1SAndroid Build Coastguard Worker     fn check_var(gbl_fb: &mut impl FastbootImplementation, var: &str, args: &str, expected: &str) {
891*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
892*5225e6b1SAndroid Build Coastguard Worker         let args_c = args.split(':').map(|v| CString::new(v).unwrap()).collect::<Vec<_>>();
893*5225e6b1SAndroid Build Coastguard Worker         let args_c = args_c.iter().map(|v| v.as_c_str());
894*5225e6b1SAndroid Build Coastguard Worker         let var_c = CString::new(var).unwrap();
895*5225e6b1SAndroid Build Coastguard Worker         let mut out = vec![0u8; MAX_RESPONSE_SIZE];
896*5225e6b1SAndroid Build Coastguard Worker         let val =
897*5225e6b1SAndroid Build Coastguard Worker             block_on(gbl_fb.get_var_as_str(var_c.as_c_str(), args_c, &resp, &mut out[..])).unwrap();
898*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(val, expected, "var {}:{} = {} != {}", var, args, val, expected,);
899*5225e6b1SAndroid Build Coastguard Worker     }
900*5225e6b1SAndroid Build Coastguard Worker 
901*5225e6b1SAndroid Build Coastguard Worker     /// A helper to set the download content.
set_download(gbl_fb: &mut impl FastbootImplementation, data: &[u8])902*5225e6b1SAndroid Build Coastguard Worker     fn set_download(gbl_fb: &mut impl FastbootImplementation, data: &[u8]) {
903*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.get_download_buffer())[..data.len()].clone_from_slice(data);
904*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.download_complete(data.len(), &TestResponder::default())).unwrap();
905*5225e6b1SAndroid Build Coastguard Worker     }
906*5225e6b1SAndroid Build Coastguard Worker 
907*5225e6b1SAndroid Build Coastguard Worker     impl<'a> PinFutContainer<'a> for Vec<Pin<Box<dyn Future<Output = ()> + 'a>>> {
add_with<F: Future<Output = ()> + 'a>(&mut self, f: impl FnOnce() -> F)908*5225e6b1SAndroid Build Coastguard Worker         fn add_with<F: Future<Output = ()> + 'a>(&mut self, f: impl FnOnce() -> F) {
909*5225e6b1SAndroid Build Coastguard Worker             self.push(Box::pin(f()));
910*5225e6b1SAndroid Build Coastguard Worker         }
911*5225e6b1SAndroid Build Coastguard Worker 
for_each_remove_if( &mut self, mut cb: impl FnMut(&mut Pin<&mut (dyn Future<Output = ()> + 'a)>) -> bool, )912*5225e6b1SAndroid Build Coastguard Worker         fn for_each_remove_if(
913*5225e6b1SAndroid Build Coastguard Worker             &mut self,
914*5225e6b1SAndroid Build Coastguard Worker             mut cb: impl FnMut(&mut Pin<&mut (dyn Future<Output = ()> + 'a)>) -> bool,
915*5225e6b1SAndroid Build Coastguard Worker         ) {
916*5225e6b1SAndroid Build Coastguard Worker             for idx in (0..self.len()).rev() {
917*5225e6b1SAndroid Build Coastguard Worker                 cb(&mut self[idx].as_mut()).then(|| self.swap_remove(idx));
918*5225e6b1SAndroid Build Coastguard Worker             }
919*5225e6b1SAndroid Build Coastguard Worker         }
920*5225e6b1SAndroid Build Coastguard Worker     }
921*5225e6b1SAndroid Build Coastguard Worker 
922*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_get_var_gbl()923*5225e6b1SAndroid Build Coastguard Worker     fn test_get_var_gbl() {
924*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
925*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
926*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
927*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
928*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
929*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
930*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
931*5225e6b1SAndroid Build Coastguard Worker         check_var(
932*5225e6b1SAndroid Build Coastguard Worker             &mut gbl_fb,
933*5225e6b1SAndroid Build Coastguard Worker             FakeGblOps::GBL_TEST_VAR,
934*5225e6b1SAndroid Build Coastguard Worker             "arg",
935*5225e6b1SAndroid Build Coastguard Worker             format!("{}:Some(\"arg\")", FakeGblOps::GBL_TEST_VAR_VAL).as_str(),
936*5225e6b1SAndroid Build Coastguard Worker         );
937*5225e6b1SAndroid Build Coastguard Worker     }
938*5225e6b1SAndroid Build Coastguard Worker 
939*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_get_var_partition_info()940*5225e6b1SAndroid Build Coastguard Worker     fn test_get_var_partition_info() {
941*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
942*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
943*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
944*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
945*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
946*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0x55u8; 8 * 1024]);
947*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
948*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
949*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
950*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
951*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
952*5225e6b1SAndroid Build Coastguard Worker 
953*5225e6b1SAndroid Build Coastguard Worker         // Check different semantics
954*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a", "0x2000");
955*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a/", "0x2000");
956*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a//", "0x2000");
957*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a///", "0x2000");
958*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a/0", "0x2000");
959*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a/0/", "0x2000");
960*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a//0", "0x2000");
961*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a/0/0", "0x2000");
962*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a//0x1000", "0x1000");
963*5225e6b1SAndroid Build Coastguard Worker 
964*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_b/0", "0x3000");
965*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "vendor_boot_a/1", "0x1000");
966*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "vendor_boot_b/1", "0x1800");
967*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "boot_a//0x1000", "0x1000");
968*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "raw_0", "0x1000");
969*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "partition-size", "raw_1", "0x2000");
970*5225e6b1SAndroid Build Coastguard Worker 
971*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
972*5225e6b1SAndroid Build Coastguard Worker         let mut out = vec![0u8; MAX_RESPONSE_SIZE];
973*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(gbl_fb.get_var_as_str(
974*5225e6b1SAndroid Build Coastguard Worker             c"partition",
975*5225e6b1SAndroid Build Coastguard Worker             [c"non-existent"].into_iter(),
976*5225e6b1SAndroid Build Coastguard Worker             &resp,
977*5225e6b1SAndroid Build Coastguard Worker             &mut out[..],
978*5225e6b1SAndroid Build Coastguard Worker         ))
979*5225e6b1SAndroid Build Coastguard Worker         .is_err());
980*5225e6b1SAndroid Build Coastguard Worker     }
981*5225e6b1SAndroid Build Coastguard Worker 
982*5225e6b1SAndroid Build Coastguard Worker     /// `TestVarSender` implements `TestVarSender`. It stores outputs in a vector of string.
983*5225e6b1SAndroid Build Coastguard Worker     struct TestVarSender(Vec<String>);
984*5225e6b1SAndroid Build Coastguard Worker 
985*5225e6b1SAndroid Build Coastguard Worker     impl VarInfoSender for &mut TestVarSender {
send_var_info( &mut self, name: &str, args: impl IntoIterator<Item = &'_ str>, val: &str, ) -> Result<(), Error>986*5225e6b1SAndroid Build Coastguard Worker         async fn send_var_info(
987*5225e6b1SAndroid Build Coastguard Worker             &mut self,
988*5225e6b1SAndroid Build Coastguard Worker             name: &str,
989*5225e6b1SAndroid Build Coastguard Worker             args: impl IntoIterator<Item = &'_ str>,
990*5225e6b1SAndroid Build Coastguard Worker             val: &str,
991*5225e6b1SAndroid Build Coastguard Worker         ) -> Result<(), Error> {
992*5225e6b1SAndroid Build Coastguard Worker             let args = args.into_iter().collect::<Vec<_>>();
993*5225e6b1SAndroid Build Coastguard Worker             self.0.push(format!("{}:{}: {}", name, args.join(":"), val));
994*5225e6b1SAndroid Build Coastguard Worker             Ok(())
995*5225e6b1SAndroid Build Coastguard Worker         }
996*5225e6b1SAndroid Build Coastguard Worker     }
997*5225e6b1SAndroid Build Coastguard Worker 
998*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_get_var_all()999*5225e6b1SAndroid Build Coastguard Worker     fn test_get_var_all() {
1000*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1001*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1002*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1003*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1004*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
1005*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0x55u8; 8 * 1024]);
1006*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1007*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1008*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1009*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1010*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1011*5225e6b1SAndroid Build Coastguard Worker 
1012*5225e6b1SAndroid Build Coastguard Worker         let mut logger = TestVarSender(vec![]);
1013*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.get_var_all(&mut logger)).unwrap();
1014*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1015*5225e6b1SAndroid Build Coastguard Worker             logger.0,
1016*5225e6b1SAndroid Build Coastguard Worker             [
1017*5225e6b1SAndroid Build Coastguard Worker                 "version-bootloader:: 1.0",
1018*5225e6b1SAndroid Build Coastguard Worker                 "max-fetch-size:: 0xffffffffffffffff",
1019*5225e6b1SAndroid Build Coastguard Worker                 "block-device:0:total-blocks: 0x80",
1020*5225e6b1SAndroid Build Coastguard Worker                 "block-device:0:block-size: 0x200",
1021*5225e6b1SAndroid Build Coastguard Worker                 "block-device:0:status: idle",
1022*5225e6b1SAndroid Build Coastguard Worker                 "block-device:1:total-blocks: 0x100",
1023*5225e6b1SAndroid Build Coastguard Worker                 "block-device:1:block-size: 0x200",
1024*5225e6b1SAndroid Build Coastguard Worker                 "block-device:1:status: idle",
1025*5225e6b1SAndroid Build Coastguard Worker                 "block-device:2:total-blocks: 0x1000",
1026*5225e6b1SAndroid Build Coastguard Worker                 "block-device:2:block-size: 0x1",
1027*5225e6b1SAndroid Build Coastguard Worker                 "block-device:2:status: idle",
1028*5225e6b1SAndroid Build Coastguard Worker                 "block-device:3:total-blocks: 0x2000",
1029*5225e6b1SAndroid Build Coastguard Worker                 "block-device:3:block-size: 0x1",
1030*5225e6b1SAndroid Build Coastguard Worker                 "block-device:3:status: idle",
1031*5225e6b1SAndroid Build Coastguard Worker                 "gbl-default-block:: None",
1032*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:boot_a/0: 0x2000",
1033*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:boot_a/0: raw",
1034*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:boot_b/0: 0x3000",
1035*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:boot_b/0: raw",
1036*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:vendor_boot_a/1: 0x1000",
1037*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:vendor_boot_a/1: raw",
1038*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:vendor_boot_b/1: 0x1800",
1039*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:vendor_boot_b/1: raw",
1040*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:raw_0/2: 0x1000",
1041*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:raw_0/2: raw",
1042*5225e6b1SAndroid Build Coastguard Worker                 "partition-size:raw_1/3: 0x2000",
1043*5225e6b1SAndroid Build Coastguard Worker                 "partition-type:raw_1/3: raw",
1044*5225e6b1SAndroid Build Coastguard Worker                 format!("{}:1: {}:1", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
1045*5225e6b1SAndroid Build Coastguard Worker                     .as_str(),
1046*5225e6b1SAndroid Build Coastguard Worker                 format!("{}:2: {}:2", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
1047*5225e6b1SAndroid Build Coastguard Worker                     .as_str(),
1048*5225e6b1SAndroid Build Coastguard Worker             ]
1049*5225e6b1SAndroid Build Coastguard Worker         );
1050*5225e6b1SAndroid Build Coastguard Worker     }
1051*5225e6b1SAndroid Build Coastguard Worker 
1052*5225e6b1SAndroid Build Coastguard Worker     /// A helper for fetching partition from a `GblFastboot`
fetch<EOff: core::fmt::Debug, ESz: core::fmt::Debug>( fb: &mut impl FastbootImplementation, part: String, off: impl TryInto<u64, Error = EOff>, size: impl TryInto<u64, Error = ESz>, ) -> CommandResult<Vec<u8>>1053*5225e6b1SAndroid Build Coastguard Worker     fn fetch<EOff: core::fmt::Debug, ESz: core::fmt::Debug>(
1054*5225e6b1SAndroid Build Coastguard Worker         fb: &mut impl FastbootImplementation,
1055*5225e6b1SAndroid Build Coastguard Worker         part: String,
1056*5225e6b1SAndroid Build Coastguard Worker         off: impl TryInto<u64, Error = EOff>,
1057*5225e6b1SAndroid Build Coastguard Worker         size: impl TryInto<u64, Error = ESz>,
1058*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<Vec<u8>> {
1059*5225e6b1SAndroid Build Coastguard Worker         let off = off.try_into().unwrap();
1060*5225e6b1SAndroid Build Coastguard Worker         let size = size.try_into().unwrap();
1061*5225e6b1SAndroid Build Coastguard Worker         let mut upload_out = vec![0u8; usize::try_from(size).unwrap()];
1062*5225e6b1SAndroid Build Coastguard Worker         let test_uploader = TestUploadBuilder(&mut upload_out[..]);
1063*5225e6b1SAndroid Build Coastguard Worker         block_on(fb.fetch(part.as_str(), off, size, test_uploader))?;
1064*5225e6b1SAndroid Build Coastguard Worker         Ok(upload_out)
1065*5225e6b1SAndroid Build Coastguard Worker     }
1066*5225e6b1SAndroid Build Coastguard Worker 
1067*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_fetch_invalid_partition_arg()1068*5225e6b1SAndroid Build Coastguard Worker     fn test_fetch_invalid_partition_arg() {
1069*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1070*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1071*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1072*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1073*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1074*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1075*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1076*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1077*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1078*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1079*5225e6b1SAndroid Build Coastguard Worker 
1080*5225e6b1SAndroid Build Coastguard Worker         // Missing mandatory block device ID for raw block partition.
1081*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "//0/0".into(), 0, 0).is_err());
1082*5225e6b1SAndroid Build Coastguard Worker 
1083*5225e6b1SAndroid Build Coastguard Worker         // GPT partition does not exist.
1084*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "non///".into(), 0, 0).is_err());
1085*5225e6b1SAndroid Build Coastguard Worker 
1086*5225e6b1SAndroid Build Coastguard Worker         // GPT Partition is not unique.
1087*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "vendor_boot_a///".into(), 0, 0).is_err());
1088*5225e6b1SAndroid Build Coastguard Worker 
1089*5225e6b1SAndroid Build Coastguard Worker         // Offset overflows.
1090*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "boot_a//0x2001/".into(), 0, 1).is_err());
1091*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "boot_a".into(), 0x2000, 1).is_err());
1092*5225e6b1SAndroid Build Coastguard Worker 
1093*5225e6b1SAndroid Build Coastguard Worker         // Size overflows.
1094*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "boot_a///0x2001".into(), 0, 0).is_err());
1095*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "boot_a".into(), 0, 0x2001).is_err());
1096*5225e6b1SAndroid Build Coastguard Worker     }
1097*5225e6b1SAndroid Build Coastguard Worker 
1098*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing raw block upload. It verifies that data read from block device
1099*5225e6b1SAndroid Build Coastguard Worker     /// `blk_id` in range [`off`, `off`+`size`) is the same as `disk[off..][..size]`
check_blk_upload( fb: &mut impl FastbootImplementation, blk_id: u64, off: u64, size: u64, disk: &[u8], )1100*5225e6b1SAndroid Build Coastguard Worker     fn check_blk_upload(
1101*5225e6b1SAndroid Build Coastguard Worker         fb: &mut impl FastbootImplementation,
1102*5225e6b1SAndroid Build Coastguard Worker         blk_id: u64,
1103*5225e6b1SAndroid Build Coastguard Worker         off: u64,
1104*5225e6b1SAndroid Build Coastguard Worker         size: u64,
1105*5225e6b1SAndroid Build Coastguard Worker         disk: &[u8],
1106*5225e6b1SAndroid Build Coastguard Worker     ) {
1107*5225e6b1SAndroid Build Coastguard Worker         let expected = disk[off.try_into().unwrap()..][..size.try_into().unwrap()].to_vec();
1108*5225e6b1SAndroid Build Coastguard Worker         // offset/size as part of the partition string.
1109*5225e6b1SAndroid Build Coastguard Worker         let part = format!("/{:#x}/{:#x}/{:#x}", blk_id, off, size);
1110*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(fb, part, 0, size).unwrap(), expected);
1111*5225e6b1SAndroid Build Coastguard Worker         // offset/size as separate fetch arguments.
1112*5225e6b1SAndroid Build Coastguard Worker         let part = format!("/{:#x}", blk_id);
1113*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(fb, part, off, size).unwrap(), expected);
1114*5225e6b1SAndroid Build Coastguard Worker     }
1115*5225e6b1SAndroid Build Coastguard Worker 
1116*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_fetch_raw_block()1117*5225e6b1SAndroid Build Coastguard Worker     fn test_fetch_raw_block() {
1118*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1119*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1120*5225e6b1SAndroid Build Coastguard Worker         let disk_0 = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
1121*5225e6b1SAndroid Build Coastguard Worker         let disk_1 = include_bytes!("../../../libstorage/test/gpt_test_2.bin");
1122*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_0);
1123*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_1);
1124*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1125*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1126*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1127*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1128*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1129*5225e6b1SAndroid Build Coastguard Worker 
1130*5225e6b1SAndroid Build Coastguard Worker         let off = 512;
1131*5225e6b1SAndroid Build Coastguard Worker         let size = 512;
1132*5225e6b1SAndroid Build Coastguard Worker         check_blk_upload(&mut gbl_fb, 0, off, size, disk_0);
1133*5225e6b1SAndroid Build Coastguard Worker         check_blk_upload(&mut gbl_fb, 1, off, size, disk_1);
1134*5225e6b1SAndroid Build Coastguard Worker     }
1135*5225e6b1SAndroid Build Coastguard Worker 
1136*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing uploading GPT partition. It verifies that data read from GPT partition
1137*5225e6b1SAndroid Build Coastguard Worker     /// `part` at disk `blk_id` in range [`off`, `off`+`size`) is the same as
1138*5225e6b1SAndroid Build Coastguard Worker     /// `partition_data[off..][..size]`.
check_part_upload( fb: &mut impl FastbootImplementation, part: &str, off: u64, size: u64, blk_id: Option<u64>, partition_data: &[u8], )1139*5225e6b1SAndroid Build Coastguard Worker     fn check_part_upload(
1140*5225e6b1SAndroid Build Coastguard Worker         fb: &mut impl FastbootImplementation,
1141*5225e6b1SAndroid Build Coastguard Worker         part: &str,
1142*5225e6b1SAndroid Build Coastguard Worker         off: u64,
1143*5225e6b1SAndroid Build Coastguard Worker         size: u64,
1144*5225e6b1SAndroid Build Coastguard Worker         blk_id: Option<u64>,
1145*5225e6b1SAndroid Build Coastguard Worker         partition_data: &[u8],
1146*5225e6b1SAndroid Build Coastguard Worker     ) {
1147*5225e6b1SAndroid Build Coastguard Worker         let expected =
1148*5225e6b1SAndroid Build Coastguard Worker             partition_data[off.try_into().unwrap()..][..size.try_into().unwrap()].to_vec();
1149*5225e6b1SAndroid Build Coastguard Worker         let blk_id = blk_id.map_or("".to_string(), |v| format!("{:#x}", v));
1150*5225e6b1SAndroid Build Coastguard Worker         // offset/size as part of the partition string.
1151*5225e6b1SAndroid Build Coastguard Worker         let gpt_part = format!("{}/{}/{:#x}/{:#x}", part, blk_id, off, size);
1152*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(fb, gpt_part, 0, size).unwrap(), expected);
1153*5225e6b1SAndroid Build Coastguard Worker         // offset/size as separate fetch arguments.
1154*5225e6b1SAndroid Build Coastguard Worker         let gpt_part = format!("{}/{}", part, blk_id);
1155*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(fb, gpt_part, off, size).unwrap(), expected);
1156*5225e6b1SAndroid Build Coastguard Worker     }
1157*5225e6b1SAndroid Build Coastguard Worker 
1158*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_fetch_partition()1159*5225e6b1SAndroid Build Coastguard Worker     fn test_fetch_partition() {
1160*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1161*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1162*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1163*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1164*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
1165*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0x55u8; 8 * 1024]);
1166*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1167*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1168*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1169*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1170*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1171*5225e6b1SAndroid Build Coastguard Worker 
1172*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = include_bytes!("../../../libstorage/test/boot_a.bin");
1173*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_b = include_bytes!("../../../libstorage/test/boot_b.bin");
1174*5225e6b1SAndroid Build Coastguard Worker         let expect_vendor_boot_a = include_bytes!("../../../libstorage/test/vendor_boot_a.bin");
1175*5225e6b1SAndroid Build Coastguard Worker         let expect_vendor_boot_b = include_bytes!("../../../libstorage/test/vendor_boot_b.bin");
1176*5225e6b1SAndroid Build Coastguard Worker 
1177*5225e6b1SAndroid Build Coastguard Worker         let size = 512;
1178*5225e6b1SAndroid Build Coastguard Worker         let off = 512;
1179*5225e6b1SAndroid Build Coastguard Worker 
1180*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "boot_a", off, size, Some(0), expect_boot_a);
1181*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "boot_b", off, size, Some(0), expect_boot_b);
1182*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "vendor_boot_a", off, size, Some(1), expect_vendor_boot_a);
1183*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "vendor_boot_b", off, size, Some(1), expect_vendor_boot_b);
1184*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw_0", off, size, Some(2), &[0xaau8; 4 * 1024]);
1185*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw_1", off, size, Some(3), &[0x55u8; 8 * 1024]);
1186*5225e6b1SAndroid Build Coastguard Worker 
1187*5225e6b1SAndroid Build Coastguard Worker         // No block device id
1188*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "boot_a", off, size, None, expect_boot_a);
1189*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "boot_b", off, size, None, expect_boot_b);
1190*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "vendor_boot_a", off, size, None, expect_vendor_boot_a);
1191*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "vendor_boot_b", off, size, None, expect_vendor_boot_b);
1192*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw_0", off, size, None, &[0xaau8; 4 * 1024]);
1193*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw_1", off, size, None, &[0x55u8; 8 * 1024]);
1194*5225e6b1SAndroid Build Coastguard Worker     }
1195*5225e6b1SAndroid Build Coastguard Worker 
1196*5225e6b1SAndroid Build Coastguard Worker     /// A helper function to get a bit-flipped copy of the input data.
flipped_bits(data: &[u8]) -> Vec<u8>1197*5225e6b1SAndroid Build Coastguard Worker     fn flipped_bits(data: &[u8]) -> Vec<u8> {
1198*5225e6b1SAndroid Build Coastguard Worker         data.iter().map(|v| !(*v)).collect::<Vec<_>>()
1199*5225e6b1SAndroid Build Coastguard Worker     }
1200*5225e6b1SAndroid Build Coastguard Worker 
1201*5225e6b1SAndroid Build Coastguard Worker     /// A helper function to flash data to a partition
flash_part(fb: &mut impl FastbootImplementation, part: &str, data: &[u8])1202*5225e6b1SAndroid Build Coastguard Worker     fn flash_part(fb: &mut impl FastbootImplementation, part: &str, data: &[u8]) {
1203*5225e6b1SAndroid Build Coastguard Worker         // Prepare a download buffer.
1204*5225e6b1SAndroid Build Coastguard Worker         let dl_size = data.len();
1205*5225e6b1SAndroid Build Coastguard Worker         let download = data.to_vec();
1206*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1207*5225e6b1SAndroid Build Coastguard Worker         set_download(fb, &download[..]);
1208*5225e6b1SAndroid Build Coastguard Worker         block_on(fb.flash(part, &resp)).unwrap();
1209*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(fb, part.into(), 0, dl_size).unwrap(), download);
1210*5225e6b1SAndroid Build Coastguard Worker     }
1211*5225e6b1SAndroid Build Coastguard Worker 
1212*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing partition flashing.
check_flash_part(fb: &mut impl FastbootImplementation, part: &str, expected: &[u8])1213*5225e6b1SAndroid Build Coastguard Worker     fn check_flash_part(fb: &mut impl FastbootImplementation, part: &str, expected: &[u8]) {
1214*5225e6b1SAndroid Build Coastguard Worker         flash_part(fb, part, expected);
1215*5225e6b1SAndroid Build Coastguard Worker         // Also flashes bit-wise reversed version in case the initial content is the same.
1216*5225e6b1SAndroid Build Coastguard Worker         flash_part(fb, part, &flipped_bits(expected));
1217*5225e6b1SAndroid Build Coastguard Worker     }
1218*5225e6b1SAndroid Build Coastguard Worker 
1219*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_flash_partition()1220*5225e6b1SAndroid Build Coastguard Worker     fn test_flash_partition() {
1221*5225e6b1SAndroid Build Coastguard Worker         let disk_0 = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
1222*5225e6b1SAndroid Build Coastguard Worker         let disk_1 = include_bytes!("../../../libstorage/test/gpt_test_2.bin");
1223*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1224*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1225*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_0);
1226*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_1);
1227*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
1228*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0x55u8; 8 * 1024]);
1229*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1230*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1231*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1232*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1233*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1234*5225e6b1SAndroid Build Coastguard Worker 
1235*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = include_bytes!("../../../libstorage/test/boot_a.bin");
1236*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_b = include_bytes!("../../../libstorage/test/boot_b.bin");
1237*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "boot_a", expect_boot_a);
1238*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "boot_b", expect_boot_b);
1239*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "raw_0", &[0xaau8; 4 * 1024]);
1240*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "raw_1", &[0x55u8; 8 * 1024]);
1241*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "/0", disk_0);
1242*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "/1", disk_1);
1243*5225e6b1SAndroid Build Coastguard Worker 
1244*5225e6b1SAndroid Build Coastguard Worker         // Partital flash
1245*5225e6b1SAndroid Build Coastguard Worker         let off = 0x200;
1246*5225e6b1SAndroid Build Coastguard Worker         let size = 1024;
1247*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "boot_a//200", &expect_boot_a[off..size]);
1248*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "boot_b//200", &expect_boot_b[off..size]);
1249*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "/0/200", &disk_0[off..size]);
1250*5225e6b1SAndroid Build Coastguard Worker         check_flash_part(&mut gbl_fb, "/1/200", &disk_1[off..size]);
1251*5225e6b1SAndroid Build Coastguard Worker     }
1252*5225e6b1SAndroid Build Coastguard Worker 
1253*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_flash_partition_sparse()1254*5225e6b1SAndroid Build Coastguard Worker     fn test_flash_partition_sparse() {
1255*5225e6b1SAndroid Build Coastguard Worker         let raw = include_bytes!("../../testdata/sparse_test_raw.bin");
1256*5225e6b1SAndroid Build Coastguard Worker         let sparse = include_bytes!("../../testdata/sparse_test.bin");
1257*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1258*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1259*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw", vec![0u8; raw.len()]);
1260*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1261*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1262*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1263*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1264*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1265*5225e6b1SAndroid Build Coastguard Worker 
1266*5225e6b1SAndroid Build Coastguard Worker         let download = sparse.to_vec();
1267*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1268*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, &download[..]);
1269*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("/0", &resp)).unwrap();
1270*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(&mut gbl_fb, "/0".into(), 0, raw.len()).unwrap(), raw);
1271*5225e6b1SAndroid Build Coastguard Worker     }
1272*5225e6b1SAndroid Build Coastguard Worker 
1273*5225e6b1SAndroid Build Coastguard Worker     /// A helper to invoke OEM commands.
1274*5225e6b1SAndroid Build Coastguard Worker     ///
1275*5225e6b1SAndroid Build Coastguard Worker     /// Returns the result and INFO strings.
oem( fb: &mut impl FastbootImplementation, oem_cmd: &str, resp: impl InfoSender, ) -> CommandResult<String>1276*5225e6b1SAndroid Build Coastguard Worker     async fn oem(
1277*5225e6b1SAndroid Build Coastguard Worker         fb: &mut impl FastbootImplementation,
1278*5225e6b1SAndroid Build Coastguard Worker         oem_cmd: &str,
1279*5225e6b1SAndroid Build Coastguard Worker         resp: impl InfoSender,
1280*5225e6b1SAndroid Build Coastguard Worker     ) -> CommandResult<String> {
1281*5225e6b1SAndroid Build Coastguard Worker         let mut res = [0u8; MAX_RESPONSE_SIZE];
1282*5225e6b1SAndroid Build Coastguard Worker         fb.oem(oem_cmd, resp, &mut res[..]).await?;
1283*5225e6b1SAndroid Build Coastguard Worker         Ok(from_utf8(&mut res[..]).unwrap().into())
1284*5225e6b1SAndroid Build Coastguard Worker     }
1285*5225e6b1SAndroid Build Coastguard Worker 
1286*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_async_flash()1287*5225e6b1SAndroid Build Coastguard Worker     fn test_async_flash() {
1288*5225e6b1SAndroid Build Coastguard Worker         // Creates two block devices for writing raw and sparse image.
1289*5225e6b1SAndroid Build Coastguard Worker         let sparse_raw = include_bytes!("../../testdata/sparse_test_raw.bin");
1290*5225e6b1SAndroid Build Coastguard Worker         let sparse = include_bytes!("../../testdata/sparse_test.bin");
1291*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1292*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1293*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(vec![0u8; sparse_raw.len() + 67 * 512]);
1294*5225e6b1SAndroid Build Coastguard Worker         let mut gpt_builder = storage[1].gpt_builder().unwrap();
1295*5225e6b1SAndroid Build Coastguard Worker         gpt_builder.add("sparse", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, None).unwrap();
1296*5225e6b1SAndroid Build Coastguard Worker         block_on(gpt_builder.persist()).unwrap();
1297*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1298*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1299*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1300*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1301*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1302*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1303*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1304*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1305*5225e6b1SAndroid Build Coastguard Worker 
1306*5225e6b1SAndroid Build Coastguard Worker         // "oem gbl-sync-tasks" should return immediately when there is no pending IOs.
1307*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut pin!(oem(&mut gbl_fb, "gbl-sync-tasks", &resp))).unwrap().is_ok());
1308*5225e6b1SAndroid Build Coastguard Worker         // Enable async IO.
1309*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut pin!(oem(&mut gbl_fb, "gbl-enable-async-task", &resp))).unwrap().is_ok());
1310*5225e6b1SAndroid Build Coastguard Worker 
1311*5225e6b1SAndroid Build Coastguard Worker         // Flashes "boot_a".
1312*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = flipped_bits(include_bytes!("../../../libstorage/test/boot_a.bin"));
1313*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1314*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("boot_a", &resp)).unwrap();
1315*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "0:status", "IO pending");
1316*5225e6b1SAndroid Build Coastguard Worker 
1317*5225e6b1SAndroid Build Coastguard Worker         // Flashes the "sparse" partition on the different block device.
1318*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, sparse);
1319*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("sparse", &resp)).unwrap();
1320*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "1:status", "IO pending");
1321*5225e6b1SAndroid Build Coastguard Worker 
1322*5225e6b1SAndroid Build Coastguard Worker         {
1323*5225e6b1SAndroid Build Coastguard Worker             // "oem gbl-sync-tasks" should block.
1324*5225e6b1SAndroid Build Coastguard Worker             let oem_sync_blk_fut = &mut pin!(oem(&mut gbl_fb, "gbl-sync-tasks", &resp));
1325*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(oem_sync_blk_fut).is_none());
1326*5225e6b1SAndroid Build Coastguard Worker             // Schedules the disk IO tasks to completion.
1327*5225e6b1SAndroid Build Coastguard Worker             tasks.borrow_mut().run();
1328*5225e6b1SAndroid Build Coastguard Worker             // "oem gbl-sync-tasks" should now be able to finish.
1329*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(oem_sync_blk_fut).unwrap().is_ok());
1330*5225e6b1SAndroid Build Coastguard Worker         }
1331*5225e6b1SAndroid Build Coastguard Worker 
1332*5225e6b1SAndroid Build Coastguard Worker         // The two blocks should be in the idle state.
1333*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "0:status", "idle");
1334*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "1:status", "idle");
1335*5225e6b1SAndroid Build Coastguard Worker 
1336*5225e6b1SAndroid Build Coastguard Worker         // Verifies flashed image.
1337*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1338*5225e6b1SAndroid Build Coastguard Worker             fetch(&mut gbl_fb, "boot_a".into(), 0, expect_boot_a.len()).unwrap(),
1339*5225e6b1SAndroid Build Coastguard Worker             expect_boot_a
1340*5225e6b1SAndroid Build Coastguard Worker         );
1341*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(fetch(&mut gbl_fb, "sparse".into(), 0, sparse_raw.len()).unwrap(), sparse_raw);
1342*5225e6b1SAndroid Build Coastguard Worker     }
1343*5225e6b1SAndroid Build Coastguard Worker 
1344*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_async_flash_block_on_busy_blk()1345*5225e6b1SAndroid Build Coastguard Worker     fn test_async_flash_block_on_busy_blk() {
1346*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1347*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1348*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1349*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1350*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1351*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1352*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1353*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1354*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1355*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1356*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1357*5225e6b1SAndroid Build Coastguard Worker 
1358*5225e6b1SAndroid Build Coastguard Worker         // Enable async IO.
1359*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut pin!(oem(&mut gbl_fb, "gbl-enable-async-task", &resp))).unwrap().is_ok());
1360*5225e6b1SAndroid Build Coastguard Worker 
1361*5225e6b1SAndroid Build Coastguard Worker         // Flashes boot_a partition.
1362*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = flipped_bits(include_bytes!("../../../libstorage/test/boot_a.bin"));
1363*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1364*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("boot_a", &resp)).unwrap();
1365*5225e6b1SAndroid Build Coastguard Worker 
1366*5225e6b1SAndroid Build Coastguard Worker         // Flashes boot_b partition.
1367*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_b = flipped_bits(include_bytes!("../../../libstorage/test/boot_b.bin"));
1368*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_b.as_slice());
1369*5225e6b1SAndroid Build Coastguard Worker         {
1370*5225e6b1SAndroid Build Coastguard Worker             let flash_boot_b_fut = &mut pin!(gbl_fb.flash("boot_b", &resp));
1371*5225e6b1SAndroid Build Coastguard Worker             // Previous IO has not completed. Block is busy.
1372*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(flash_boot_b_fut).is_none());
1373*5225e6b1SAndroid Build Coastguard Worker             // There should only be the previous disk IO task for "boot_a".
1374*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(tasks.borrow_mut().size(), 1);
1375*5225e6b1SAndroid Build Coastguard Worker             // Schedule the disk IO task for "flash boot_a" to completion.
1376*5225e6b1SAndroid Build Coastguard Worker             tasks.borrow_mut().run();
1377*5225e6b1SAndroid Build Coastguard Worker             // The blocked "flash boot_b" should now be able to finish.
1378*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(flash_boot_b_fut).is_some());
1379*5225e6b1SAndroid Build Coastguard Worker             // There should be a disk IO task spawned for "flash boot_b".
1380*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(tasks.borrow_mut().size(), 1);
1381*5225e6b1SAndroid Build Coastguard Worker             // Schedule the disk IO tasks for "flash boot_b" to completion.
1382*5225e6b1SAndroid Build Coastguard Worker             tasks.borrow_mut().run();
1383*5225e6b1SAndroid Build Coastguard Worker         }
1384*5225e6b1SAndroid Build Coastguard Worker 
1385*5225e6b1SAndroid Build Coastguard Worker         // Verifies flashed image.
1386*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1387*5225e6b1SAndroid Build Coastguard Worker             fetch(&mut gbl_fb, "boot_a".into(), 0, expect_boot_a.len()).unwrap(),
1388*5225e6b1SAndroid Build Coastguard Worker             expect_boot_a
1389*5225e6b1SAndroid Build Coastguard Worker         );
1390*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1391*5225e6b1SAndroid Build Coastguard Worker             fetch(&mut gbl_fb, "boot_b".into(), 0, expect_boot_b.len()).unwrap(),
1392*5225e6b1SAndroid Build Coastguard Worker             expect_boot_b
1393*5225e6b1SAndroid Build Coastguard Worker         );
1394*5225e6b1SAndroid Build Coastguard Worker     }
1395*5225e6b1SAndroid Build Coastguard Worker 
1396*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_async_flash_error()1397*5225e6b1SAndroid Build Coastguard Worker     fn test_async_flash_error() {
1398*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1399*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1400*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1401*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1402*5225e6b1SAndroid Build Coastguard Worker         // Injects an error.
1403*5225e6b1SAndroid Build Coastguard Worker         storage[0].partition_io(None).unwrap().dev().io().error =
1404*5225e6b1SAndroid Build Coastguard Worker             liberror::Error::Other(None).into();
1405*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1406*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1407*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1408*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1409*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1410*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1411*5225e6b1SAndroid Build Coastguard Worker 
1412*5225e6b1SAndroid Build Coastguard Worker         // Enable async IO.
1413*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut pin!(oem(&mut gbl_fb, "gbl-enable-async-task", &resp))).unwrap().is_ok());
1414*5225e6b1SAndroid Build Coastguard Worker         // Flashes boot_a partition.
1415*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = flipped_bits(include_bytes!("../../../libstorage/test/boot_a.bin"));
1416*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1417*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("boot_a", &resp)).unwrap();
1418*5225e6b1SAndroid Build Coastguard Worker         // Schedules the disk IO tasks to completion.
1419*5225e6b1SAndroid Build Coastguard Worker         tasks.borrow_mut().run();
1420*5225e6b1SAndroid Build Coastguard Worker         // New flash to "boot_a" should fail due to previous error
1421*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1422*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(gbl_fb.flash("boot_a", &resp)).is_err());
1423*5225e6b1SAndroid Build Coastguard Worker         // "oem gbl-sync-tasks" should fail.
1424*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(oem(&mut gbl_fb, "gbl-sync-tasks", &resp)).is_err());
1425*5225e6b1SAndroid Build Coastguard Worker     }
1426*5225e6b1SAndroid Build Coastguard Worker 
1427*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_async_erase()1428*5225e6b1SAndroid Build Coastguard Worker     fn test_async_erase() {
1429*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1430*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1431*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0xaau8; 4096]);
1432*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0x55u8; 4096]);
1433*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1434*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1435*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1436*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1437*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1438*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1439*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1440*5225e6b1SAndroid Build Coastguard Worker 
1441*5225e6b1SAndroid Build Coastguard Worker         // Enable async IO.
1442*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut pin!(oem(&mut gbl_fb, "gbl-enable-async-task", &resp))).unwrap().is_ok());
1443*5225e6b1SAndroid Build Coastguard Worker 
1444*5225e6b1SAndroid Build Coastguard Worker         // Erases "raw_0".
1445*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.erase("raw_0", &resp)).unwrap();
1446*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "0:status", "IO pending");
1447*5225e6b1SAndroid Build Coastguard Worker 
1448*5225e6b1SAndroid Build Coastguard Worker         // Erases second half of "raw_1"
1449*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.erase("raw_1//800", &resp)).unwrap();
1450*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "1:status", "IO pending");
1451*5225e6b1SAndroid Build Coastguard Worker 
1452*5225e6b1SAndroid Build Coastguard Worker         {
1453*5225e6b1SAndroid Build Coastguard Worker             // "oem gbl-sync-tasks" should block.
1454*5225e6b1SAndroid Build Coastguard Worker             let oem_sync_blk_fut = &mut pin!(oem(&mut gbl_fb, "gbl-sync-tasks", &resp));
1455*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(oem_sync_blk_fut).is_none());
1456*5225e6b1SAndroid Build Coastguard Worker             // Schedules the disk IO tasks to completion.
1457*5225e6b1SAndroid Build Coastguard Worker             tasks.borrow_mut().run();
1458*5225e6b1SAndroid Build Coastguard Worker             // "oem gbl-sync-tasks" should now be able to finish.
1459*5225e6b1SAndroid Build Coastguard Worker             assert!(poll(oem_sync_blk_fut).unwrap().is_ok());
1460*5225e6b1SAndroid Build Coastguard Worker         }
1461*5225e6b1SAndroid Build Coastguard Worker 
1462*5225e6b1SAndroid Build Coastguard Worker         // The two blocks should be in the idle state.
1463*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "0:status", "idle");
1464*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "block-device", "1:status", "idle");
1465*5225e6b1SAndroid Build Coastguard Worker 
1466*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(storage[0].partition_io(None).unwrap().dev().io().storage, [0u8; 4096]);
1467*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1468*5225e6b1SAndroid Build Coastguard Worker             storage[1].partition_io(None).unwrap().dev().io().storage,
1469*5225e6b1SAndroid Build Coastguard Worker             [[0x55u8; 2048], [0u8; 2048]].concat()
1470*5225e6b1SAndroid Build Coastguard Worker         );
1471*5225e6b1SAndroid Build Coastguard Worker     }
1472*5225e6b1SAndroid Build Coastguard Worker 
1473*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_default_block()1474*5225e6b1SAndroid Build Coastguard Worker     fn test_default_block() {
1475*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 1]);
1476*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1477*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1478*5225e6b1SAndroid Build Coastguard Worker         let disk_dup = include_bytes!("../../../libstorage/test/gpt_test_2.bin");
1479*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_dup);
1480*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(disk_dup);
1481*5225e6b1SAndroid Build Coastguard Worker         let raw_a = [0xaau8; 4 * 1024];
1482*5225e6b1SAndroid Build Coastguard Worker         let raw_b = [0x55u8; 8 * 1024];
1483*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw", raw_a);
1484*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw", raw_b);
1485*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1486*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1487*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1488*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1489*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1490*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1491*5225e6b1SAndroid Build Coastguard Worker 
1492*5225e6b1SAndroid Build Coastguard Worker         let boot_a = include_bytes!("../../../libstorage/test/boot_a.bin");
1493*5225e6b1SAndroid Build Coastguard Worker         // Flips the bits on partition "vendor_boot_a" on block device #2 to make it different from
1494*5225e6b1SAndroid Build Coastguard Worker         // block #1.
1495*5225e6b1SAndroid Build Coastguard Worker         let vendor_boot_a =
1496*5225e6b1SAndroid Build Coastguard Worker             flipped_bits(include_bytes!("../../../libstorage/test/vendor_boot_a.bin"));
1497*5225e6b1SAndroid Build Coastguard Worker         flash_part(&mut gbl_fb, "vendor_boot_a/2", &vendor_boot_a);
1498*5225e6b1SAndroid Build Coastguard Worker 
1499*5225e6b1SAndroid Build Coastguard Worker         let size = 512;
1500*5225e6b1SAndroid Build Coastguard Worker         let off = 512;
1501*5225e6b1SAndroid Build Coastguard Worker 
1502*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "gbl-default-block", "", "None");
1503*5225e6b1SAndroid Build Coastguard Worker         // Sets default block to #2
1504*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-set-default-block 2", &resp)).unwrap();
1505*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "gbl-default-block", "", "0x2");
1506*5225e6b1SAndroid Build Coastguard Worker         // The following fetch should succeed and fetch from "vendor_boot_a" on block 2.
1507*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "vendor_boot_a", off, size, None, &vendor_boot_a);
1508*5225e6b1SAndroid Build Coastguard Worker 
1509*5225e6b1SAndroid Build Coastguard Worker         // Sets default block to #4 (raw_b)
1510*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-set-default-block 4", &resp)).unwrap();
1511*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "gbl-default-block", "", "0x4");
1512*5225e6b1SAndroid Build Coastguard Worker         // The following fetch should succeed and fetch from "raw" on block 4.
1513*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw", off, size, None, &raw_b);
1514*5225e6b1SAndroid Build Coastguard Worker 
1515*5225e6b1SAndroid Build Coastguard Worker         // Fetches with explicit storage ID shouldn't be affected.
1516*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "boot_a", off, size, Some(0), boot_a);
1517*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "raw", off, size, Some(3), &raw_a);
1518*5225e6b1SAndroid Build Coastguard Worker         check_blk_upload(&mut gbl_fb, 1, off, size, disk_dup);
1519*5225e6b1SAndroid Build Coastguard Worker 
1520*5225e6b1SAndroid Build Coastguard Worker         // Fetching without storage ID should use default ID and thus the following should fail.
1521*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "boot_a".into(), 0, boot_a.len()).is_err());
1522*5225e6b1SAndroid Build Coastguard Worker 
1523*5225e6b1SAndroid Build Coastguard Worker         // Sets default block to #1 (unmodified `disk_dup`)
1524*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-set-default-block 1", &resp)).unwrap();
1525*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "gbl-default-block", "", "0x1");
1526*5225e6b1SAndroid Build Coastguard Worker         // Fetches whole raw block but without block ID should use the default block.
1527*5225e6b1SAndroid Build Coastguard Worker         check_part_upload(&mut gbl_fb, "", off, size, None, disk_dup);
1528*5225e6b1SAndroid Build Coastguard Worker 
1529*5225e6b1SAndroid Build Coastguard Worker         // Unset default block
1530*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-unset-default-block", &resp)).unwrap();
1531*5225e6b1SAndroid Build Coastguard Worker         check_var(&mut gbl_fb, "gbl-default-block", "", "None");
1532*5225e6b1SAndroid Build Coastguard Worker         // Fetching non-unique partitions should now fail.
1533*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "raw".into(), 0, raw_a.len()).is_err());
1534*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "vendor_boot_a".into(), 0, vendor_boot_a.len()).is_err());
1535*5225e6b1SAndroid Build Coastguard Worker         assert!(fetch(&mut gbl_fb, "/".into(), 0, 512).is_err());
1536*5225e6b1SAndroid Build Coastguard Worker     }
1537*5225e6b1SAndroid Build Coastguard Worker 
1538*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_set_default_block_invalid_arg()1539*5225e6b1SAndroid Build Coastguard Worker     fn test_set_default_block_invalid_arg() {
1540*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1541*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
1542*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1543*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1544*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1545*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1546*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1547*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1548*5225e6b1SAndroid Build Coastguard Worker         // Missing block device ID.
1549*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(oem(&mut gbl_fb, "gbl-set-default-block ", &resp)).is_err());
1550*5225e6b1SAndroid Build Coastguard Worker         // Invalid block device ID.
1551*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(oem(&mut gbl_fb, "gbl-set-default-block zzz", &resp)).is_err());
1552*5225e6b1SAndroid Build Coastguard Worker         // Out of range block device ID. (We've added no block device).
1553*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(oem(&mut gbl_fb, "gbl-set-default-block 0", &resp)).is_err());
1554*5225e6b1SAndroid Build Coastguard Worker     }
1555*5225e6b1SAndroid Build Coastguard Worker 
1556*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_reboot_sync_all_blocks()1557*5225e6b1SAndroid Build Coastguard Worker     fn test_reboot_sync_all_blocks() {
1558*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1559*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1560*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1561*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1562*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1563*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1564*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1565*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1566*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1567*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1568*5225e6b1SAndroid Build Coastguard Worker 
1569*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-enable-async-task", &resp)).unwrap();
1570*5225e6b1SAndroid Build Coastguard Worker 
1571*5225e6b1SAndroid Build Coastguard Worker         // Flashes "boot_a".
1572*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = flipped_bits(include_bytes!("../../../libstorage/test/boot_a.bin"));
1573*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1574*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("boot_a", &resp)).unwrap();
1575*5225e6b1SAndroid Build Coastguard Worker         // Checks initial state, okay_sent=false.
1576*5225e6b1SAndroid Build Coastguard Worker         assert!(!(*resp.okay_sent.try_lock().unwrap()));
1577*5225e6b1SAndroid Build Coastguard Worker         // Performs a reboot.
1578*5225e6b1SAndroid Build Coastguard Worker         let mut reboot_fut = pin!(gbl_fb.reboot(RebootMode::Normal, &resp));
1579*5225e6b1SAndroid Build Coastguard Worker         // There is a pending flash task. Reboot should wait.
1580*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut reboot_fut).is_none());
1581*5225e6b1SAndroid Build Coastguard Worker         assert!(!(*resp.okay_sent.try_lock().unwrap()));
1582*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(resp.info_messages.try_lock().unwrap()[1], "Syncing storage...");
1583*5225e6b1SAndroid Build Coastguard Worker         // Schedules the disk IO tasks to completion.
1584*5225e6b1SAndroid Build Coastguard Worker         tasks.borrow_mut().run();
1585*5225e6b1SAndroid Build Coastguard Worker         // The reboot can now complete.
1586*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut reboot_fut).is_some());
1587*5225e6b1SAndroid Build Coastguard Worker         assert!((*resp.okay_sent.try_lock().unwrap()));
1588*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(resp.info_messages.try_lock().unwrap()[2], "Rebooting...");
1589*5225e6b1SAndroid Build Coastguard Worker     }
1590*5225e6b1SAndroid Build Coastguard Worker 
1591*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_continue_sync_all_blocks()1592*5225e6b1SAndroid Build Coastguard Worker     fn test_continue_sync_all_blocks() {
1593*5225e6b1SAndroid Build Coastguard Worker         let dl_buffers = Shared::from(vec![vec![0u8; 128 * 1024]; 2]);
1594*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1595*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
1596*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1597*5225e6b1SAndroid Build Coastguard Worker         let tasks = vec![].into();
1598*5225e6b1SAndroid Build Coastguard Worker         let parts = gbl_ops.disks();
1599*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_fb =
1600*5225e6b1SAndroid Build Coastguard Worker             GblFastboot::new(&mut gbl_ops, parts, Task::run, &tasks, &dl_buffers, &mut []);
1601*5225e6b1SAndroid Build Coastguard Worker         let tasks = gbl_fb.tasks();
1602*5225e6b1SAndroid Build Coastguard Worker         let resp: TestResponder = Default::default();
1603*5225e6b1SAndroid Build Coastguard Worker 
1604*5225e6b1SAndroid Build Coastguard Worker         block_on(oem(&mut gbl_fb, "gbl-enable-async-task", &resp)).unwrap();
1605*5225e6b1SAndroid Build Coastguard Worker 
1606*5225e6b1SAndroid Build Coastguard Worker         // Flashes "boot_a".
1607*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = flipped_bits(include_bytes!("../../../libstorage/test/boot_a.bin"));
1608*5225e6b1SAndroid Build Coastguard Worker         set_download(&mut gbl_fb, expect_boot_a.as_slice());
1609*5225e6b1SAndroid Build Coastguard Worker         block_on(gbl_fb.flash("boot_a", &resp)).unwrap();
1610*5225e6b1SAndroid Build Coastguard Worker         // Performs a continue.
1611*5225e6b1SAndroid Build Coastguard Worker         let mut continue_fut = pin!(gbl_fb.r#continue(&resp));
1612*5225e6b1SAndroid Build Coastguard Worker         // There is a pending flash task. Continue should wait.
1613*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut continue_fut).is_none());
1614*5225e6b1SAndroid Build Coastguard Worker         assert!(!(*resp.okay_sent.try_lock().unwrap()));
1615*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(resp.info_messages.try_lock().unwrap()[1], "Syncing storage...");
1616*5225e6b1SAndroid Build Coastguard Worker         // Schedules the disk IO tasks to completion.
1617*5225e6b1SAndroid Build Coastguard Worker         tasks.borrow_mut().run();
1618*5225e6b1SAndroid Build Coastguard Worker         // The continue can now complete.
1619*5225e6b1SAndroid Build Coastguard Worker         assert!(poll(&mut continue_fut).is_some());
1620*5225e6b1SAndroid Build Coastguard Worker     }
1621*5225e6b1SAndroid Build Coastguard Worker 
1622*5225e6b1SAndroid Build Coastguard Worker     /// Generates a length prefixed byte sequence.
length_prefixed(data: &[u8]) -> Vec<u8>1623*5225e6b1SAndroid Build Coastguard Worker     fn length_prefixed(data: &[u8]) -> Vec<u8> {
1624*5225e6b1SAndroid Build Coastguard Worker         [&data.len().to_be_bytes()[..], data].concat()
1625*5225e6b1SAndroid Build Coastguard Worker     }
1626*5225e6b1SAndroid Build Coastguard Worker 
1627*5225e6b1SAndroid Build Coastguard Worker     /// Used for a test implementation of [GblUsbTransport] and [GblTcpStream].
1628*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1629*5225e6b1SAndroid Build Coastguard Worker     struct TestListener {
1630*5225e6b1SAndroid Build Coastguard Worker         usb_in_queue: VecDeque<Vec<u8>>,
1631*5225e6b1SAndroid Build Coastguard Worker         usb_out_queue: VecDeque<Vec<u8>>,
1632*5225e6b1SAndroid Build Coastguard Worker 
1633*5225e6b1SAndroid Build Coastguard Worker         tcp_in_queue: VecDeque<u8>,
1634*5225e6b1SAndroid Build Coastguard Worker         tcp_out_queue: VecDeque<u8>,
1635*5225e6b1SAndroid Build Coastguard Worker     }
1636*5225e6b1SAndroid Build Coastguard Worker 
1637*5225e6b1SAndroid Build Coastguard Worker     /// A shared [TestListener].
1638*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1639*5225e6b1SAndroid Build Coastguard Worker     struct SharedTestListener(Mutex<TestListener>);
1640*5225e6b1SAndroid Build Coastguard Worker 
1641*5225e6b1SAndroid Build Coastguard Worker     impl SharedTestListener {
1642*5225e6b1SAndroid Build Coastguard Worker         /// Locks the listener
lock(&self) -> MutexGuard<TestListener>1643*5225e6b1SAndroid Build Coastguard Worker         fn lock(&self) -> MutexGuard<TestListener> {
1644*5225e6b1SAndroid Build Coastguard Worker             self.0.try_lock().unwrap()
1645*5225e6b1SAndroid Build Coastguard Worker         }
1646*5225e6b1SAndroid Build Coastguard Worker 
1647*5225e6b1SAndroid Build Coastguard Worker         /// Adds packet to USB input
add_usb_input(&self, packet: &[u8])1648*5225e6b1SAndroid Build Coastguard Worker         fn add_usb_input(&self, packet: &[u8]) {
1649*5225e6b1SAndroid Build Coastguard Worker             self.lock().usb_in_queue.push_back(packet.into());
1650*5225e6b1SAndroid Build Coastguard Worker         }
1651*5225e6b1SAndroid Build Coastguard Worker 
1652*5225e6b1SAndroid Build Coastguard Worker         /// Adds bytes to input stream.
add_tcp_input(&self, data: &[u8])1653*5225e6b1SAndroid Build Coastguard Worker         fn add_tcp_input(&self, data: &[u8]) {
1654*5225e6b1SAndroid Build Coastguard Worker             self.lock().tcp_in_queue.append(&mut data.to_vec().into());
1655*5225e6b1SAndroid Build Coastguard Worker         }
1656*5225e6b1SAndroid Build Coastguard Worker 
1657*5225e6b1SAndroid Build Coastguard Worker         /// Adds a length pre-fixed bytes stream.
add_tcp_length_prefixed_input(&self, data: &[u8])1658*5225e6b1SAndroid Build Coastguard Worker         fn add_tcp_length_prefixed_input(&self, data: &[u8]) {
1659*5225e6b1SAndroid Build Coastguard Worker             self.add_tcp_input(&length_prefixed(data));
1660*5225e6b1SAndroid Build Coastguard Worker         }
1661*5225e6b1SAndroid Build Coastguard Worker 
1662*5225e6b1SAndroid Build Coastguard Worker         /// Gets a copy of `Self::usb_out_queue`.
usb_out_queue(&self) -> VecDeque<Vec<u8>>1663*5225e6b1SAndroid Build Coastguard Worker         fn usb_out_queue(&self) -> VecDeque<Vec<u8>> {
1664*5225e6b1SAndroid Build Coastguard Worker             self.lock().usb_out_queue.clone()
1665*5225e6b1SAndroid Build Coastguard Worker         }
1666*5225e6b1SAndroid Build Coastguard Worker 
1667*5225e6b1SAndroid Build Coastguard Worker         /// Gets a copy of `Self::tcp_out_queue`.
tcp_out_queue(&self) -> VecDeque<u8>1668*5225e6b1SAndroid Build Coastguard Worker         fn tcp_out_queue(&self) -> VecDeque<u8> {
1669*5225e6b1SAndroid Build Coastguard Worker             self.lock().tcp_out_queue.clone()
1670*5225e6b1SAndroid Build Coastguard Worker         }
1671*5225e6b1SAndroid Build Coastguard Worker 
1672*5225e6b1SAndroid Build Coastguard Worker         /// A helper for decoding USB output packets as a string
dump_usb_out_queue(&self) -> String1673*5225e6b1SAndroid Build Coastguard Worker         fn dump_usb_out_queue(&self) -> String {
1674*5225e6b1SAndroid Build Coastguard Worker             let mut res = String::from("");
1675*5225e6b1SAndroid Build Coastguard Worker             for v in self.lock().usb_out_queue.iter() {
1676*5225e6b1SAndroid Build Coastguard Worker                 let v = String::from_utf8(v.clone()).unwrap_or(format!("{:?}", v));
1677*5225e6b1SAndroid Build Coastguard Worker                 res += format!("b{:?},\n", v).as_str();
1678*5225e6b1SAndroid Build Coastguard Worker             }
1679*5225e6b1SAndroid Build Coastguard Worker             res
1680*5225e6b1SAndroid Build Coastguard Worker         }
1681*5225e6b1SAndroid Build Coastguard Worker 
1682*5225e6b1SAndroid Build Coastguard Worker         /// A helper for decoding TCP output data as strings
dump_tcp_out_queue(&self) -> String1683*5225e6b1SAndroid Build Coastguard Worker         fn dump_tcp_out_queue(&self) -> String {
1684*5225e6b1SAndroid Build Coastguard Worker             let mut data = self.lock();
1685*5225e6b1SAndroid Build Coastguard Worker             let mut v;
1686*5225e6b1SAndroid Build Coastguard Worker             let (_, mut remains) = data.tcp_out_queue.make_contiguous().split_at(4);
1687*5225e6b1SAndroid Build Coastguard Worker             let mut res = String::from("");
1688*5225e6b1SAndroid Build Coastguard Worker             while !remains.is_empty() {
1689*5225e6b1SAndroid Build Coastguard Worker                 // Parses length-prefixed payload.
1690*5225e6b1SAndroid Build Coastguard Worker                 let (len, rest) = remains.split_first_chunk::<{ size_of::<u64>() }>().unwrap();
1691*5225e6b1SAndroid Build Coastguard Worker                 (v, remains) = rest.split_at(u64::from_be_bytes(*len).try_into().unwrap());
1692*5225e6b1SAndroid Build Coastguard Worker                 let s = String::from_utf8(v.to_vec()).unwrap_or(format!("{:?}", v));
1693*5225e6b1SAndroid Build Coastguard Worker                 res += format!("b{:?},\n", s).as_str();
1694*5225e6b1SAndroid Build Coastguard Worker             }
1695*5225e6b1SAndroid Build Coastguard Worker             res
1696*5225e6b1SAndroid Build Coastguard Worker         }
1697*5225e6b1SAndroid Build Coastguard Worker     }
1698*5225e6b1SAndroid Build Coastguard Worker 
1699*5225e6b1SAndroid Build Coastguard Worker     impl Transport for &SharedTestListener {
receive_packet(&mut self, out: &mut [u8]) -> Result<usize, Error>1700*5225e6b1SAndroid Build Coastguard Worker         async fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, Error> {
1701*5225e6b1SAndroid Build Coastguard Worker             match self.lock().usb_in_queue.pop_front() {
1702*5225e6b1SAndroid Build Coastguard Worker                 Some(v) => Ok((&v[..]).read(out).unwrap()),
1703*5225e6b1SAndroid Build Coastguard Worker                 _ => Err(Error::Other(Some("No more data"))),
1704*5225e6b1SAndroid Build Coastguard Worker             }
1705*5225e6b1SAndroid Build Coastguard Worker         }
1706*5225e6b1SAndroid Build Coastguard Worker 
send_packet(&mut self, packet: &[u8]) -> Result<(), Error>1707*5225e6b1SAndroid Build Coastguard Worker         async fn send_packet(&mut self, packet: &[u8]) -> Result<(), Error> {
1708*5225e6b1SAndroid Build Coastguard Worker             Ok(self.lock().usb_out_queue.push_back(packet.into()))
1709*5225e6b1SAndroid Build Coastguard Worker         }
1710*5225e6b1SAndroid Build Coastguard Worker     }
1711*5225e6b1SAndroid Build Coastguard Worker 
1712*5225e6b1SAndroid Build Coastguard Worker     impl GblUsbTransport for &SharedTestListener {
has_packet(&mut self) -> bool1713*5225e6b1SAndroid Build Coastguard Worker         fn has_packet(&mut self) -> bool {
1714*5225e6b1SAndroid Build Coastguard Worker             !self.lock().usb_in_queue.is_empty()
1715*5225e6b1SAndroid Build Coastguard Worker         }
1716*5225e6b1SAndroid Build Coastguard Worker     }
1717*5225e6b1SAndroid Build Coastguard Worker 
1718*5225e6b1SAndroid Build Coastguard Worker     impl TcpStream for &SharedTestListener {
read_exact(&mut self, out: &mut [u8]) -> Result<(), Error>1719*5225e6b1SAndroid Build Coastguard Worker         async fn read_exact(&mut self, out: &mut [u8]) -> Result<(), Error> {
1720*5225e6b1SAndroid Build Coastguard Worker             match self.lock().tcp_in_queue.read(out).unwrap() == out.len() {
1721*5225e6b1SAndroid Build Coastguard Worker                 true => Ok(()),
1722*5225e6b1SAndroid Build Coastguard Worker                 _ => Err(Error::Other(Some("No more data"))),
1723*5225e6b1SAndroid Build Coastguard Worker             }
1724*5225e6b1SAndroid Build Coastguard Worker         }
1725*5225e6b1SAndroid Build Coastguard Worker 
write_exact(&mut self, data: &[u8]) -> Result<(), Error>1726*5225e6b1SAndroid Build Coastguard Worker         async fn write_exact(&mut self, data: &[u8]) -> Result<(), Error> {
1727*5225e6b1SAndroid Build Coastguard Worker             Ok(self.lock().tcp_out_queue.append(&mut data.to_vec().into()))
1728*5225e6b1SAndroid Build Coastguard Worker         }
1729*5225e6b1SAndroid Build Coastguard Worker     }
1730*5225e6b1SAndroid Build Coastguard Worker 
1731*5225e6b1SAndroid Build Coastguard Worker     impl GblTcpStream for &SharedTestListener {
accept_new(&mut self) -> bool1732*5225e6b1SAndroid Build Coastguard Worker         fn accept_new(&mut self) -> bool {
1733*5225e6b1SAndroid Build Coastguard Worker             !self.lock().tcp_in_queue.is_empty()
1734*5225e6b1SAndroid Build Coastguard Worker         }
1735*5225e6b1SAndroid Build Coastguard Worker     }
1736*5225e6b1SAndroid Build Coastguard Worker 
1737*5225e6b1SAndroid Build Coastguard Worker     /// A helper to make an expected stream of USB output.
make_expected_usb_out(data: &[&[u8]]) -> VecDeque<Vec<u8>>1738*5225e6b1SAndroid Build Coastguard Worker     fn make_expected_usb_out(data: &[&[u8]]) -> VecDeque<Vec<u8>> {
1739*5225e6b1SAndroid Build Coastguard Worker         VecDeque::from(data.iter().map(|v| v.to_vec()).collect::<Vec<_>>())
1740*5225e6b1SAndroid Build Coastguard Worker     }
1741*5225e6b1SAndroid Build Coastguard Worker 
1742*5225e6b1SAndroid Build Coastguard Worker     /// A helper to make an expected stream of TCP output.
make_expected_tcp_out(data: &[&[u8]]) -> VecDeque<u8>1743*5225e6b1SAndroid Build Coastguard Worker     fn make_expected_tcp_out(data: &[&[u8]]) -> VecDeque<u8> {
1744*5225e6b1SAndroid Build Coastguard Worker         let mut res = VecDeque::<u8>::from(b"FB01".to_vec());
1745*5225e6b1SAndroid Build Coastguard Worker         data.iter().for_each(|v| res.append(&mut length_prefixed(v).into()));
1746*5225e6b1SAndroid Build Coastguard Worker         res
1747*5225e6b1SAndroid Build Coastguard Worker     }
1748*5225e6b1SAndroid Build Coastguard Worker 
1749*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot()1750*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot() {
1751*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
1752*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1753*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1754*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1755*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1756*5225e6b1SAndroid Build Coastguard Worker 
1757*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:version-bootloader");
1758*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_input(b"FB01");
1759*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_length_prefixed_input(b"getvar:max-download-size");
1760*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_length_prefixed_input(b"continue");
1761*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1762*5225e6b1SAndroid Build Coastguard Worker 
1763*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1764*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
1765*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[b"OKAY1.0"]),
1766*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
1767*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
1768*5225e6b1SAndroid Build Coastguard Worker         );
1769*5225e6b1SAndroid Build Coastguard Worker 
1770*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1771*5225e6b1SAndroid Build Coastguard Worker             listener.tcp_out_queue(),
1772*5225e6b1SAndroid Build Coastguard Worker             make_expected_tcp_out(&[b"OKAY0x20000", b"INFOSyncing storage...", b"OKAY"]),
1773*5225e6b1SAndroid Build Coastguard Worker             "\nActual TCP output:\n{}",
1774*5225e6b1SAndroid Build Coastguard Worker             listener.dump_tcp_out_queue()
1775*5225e6b1SAndroid Build Coastguard Worker         );
1776*5225e6b1SAndroid Build Coastguard Worker     }
1777*5225e6b1SAndroid Build Coastguard Worker 
1778*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_parallel_task()1779*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_parallel_task() {
1780*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1781*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0u8; 4 * 1024]);
1782*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_1", [0u8; 8 * 1024]);
1783*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1784*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1785*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1786*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1787*5225e6b1SAndroid Build Coastguard Worker         let mut fb_fut =
1788*5225e6b1SAndroid Build Coastguard Worker             pin!(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1789*5225e6b1SAndroid Build Coastguard Worker 
1790*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem gbl-enable-async-task");
1791*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 4 * 1024).as_bytes());
1792*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(&[0x55u8; 4 * 1024]);
1793*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:raw_0");
1794*5225e6b1SAndroid Build Coastguard Worker 
1795*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_input(b"FB01");
1796*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_length_prefixed_input(format!("download:{:#x}", 8 * 1024).as_bytes());
1797*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_length_prefixed_input(&[0xaau8; 8 * 1024]);
1798*5225e6b1SAndroid Build Coastguard Worker         listener.add_tcp_length_prefixed_input(b"flash:raw_1");
1799*5225e6b1SAndroid Build Coastguard Worker 
1800*5225e6b1SAndroid Build Coastguard Worker         assert!(poll_n_times(&mut fb_fut, 100).is_none());
1801*5225e6b1SAndroid Build Coastguard Worker 
1802*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1803*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
1804*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
1805*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1806*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00001000",
1807*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1808*5225e6b1SAndroid Build Coastguard Worker                 b"INFOAn IO task is launched. To sync manually, run \"oem gbl-sync-tasks\".",
1809*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1810*5225e6b1SAndroid Build Coastguard Worker             ]),
1811*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
1812*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
1813*5225e6b1SAndroid Build Coastguard Worker         );
1814*5225e6b1SAndroid Build Coastguard Worker 
1815*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1816*5225e6b1SAndroid Build Coastguard Worker             listener.tcp_out_queue(),
1817*5225e6b1SAndroid Build Coastguard Worker             make_expected_tcp_out(&[
1818*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00002000",
1819*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1820*5225e6b1SAndroid Build Coastguard Worker                 b"INFOAn IO task is launched. To sync manually, run \"oem gbl-sync-tasks\".",
1821*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1822*5225e6b1SAndroid Build Coastguard Worker             ]),
1823*5225e6b1SAndroid Build Coastguard Worker             "\nActual TCP output:\n{}",
1824*5225e6b1SAndroid Build Coastguard Worker             listener.dump_tcp_out_queue()
1825*5225e6b1SAndroid Build Coastguard Worker         );
1826*5225e6b1SAndroid Build Coastguard Worker 
1827*5225e6b1SAndroid Build Coastguard Worker         // Verifies flashed image on raw_0.
1828*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(storage[0].partition_io(None).unwrap().dev().io().storage, [0x55u8; 4 * 1024]);
1829*5225e6b1SAndroid Build Coastguard Worker 
1830*5225e6b1SAndroid Build Coastguard Worker         // Verifies flashed image on raw_1.
1831*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(storage[1].partition_io(None).unwrap().dev().io().storage, [0xaau8; 8 * 1024]);
1832*5225e6b1SAndroid Build Coastguard Worker     }
1833*5225e6b1SAndroid Build Coastguard Worker 
1834*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_add_staged_bootloader_file()1835*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_add_staged_bootloader_file() {
1836*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
1837*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1838*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1839*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.get_zbi_bootloader_files_buffer().unwrap().fill(0);
1840*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1841*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1842*5225e6b1SAndroid Build Coastguard Worker 
1843*5225e6b1SAndroid Build Coastguard Worker         // Stages two zbi files.
1844*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 3).as_bytes());
1845*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"foo");
1846*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem add-staged-bootloader-file file_1");
1847*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 3).as_bytes());
1848*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"bar");
1849*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem add-staged-bootloader-file file_2");
1850*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
1851*5225e6b1SAndroid Build Coastguard Worker 
1852*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1853*5225e6b1SAndroid Build Coastguard Worker 
1854*5225e6b1SAndroid Build Coastguard Worker         let buffer = gbl_ops.get_zbi_bootloader_files_buffer_aligned().unwrap();
1855*5225e6b1SAndroid Build Coastguard Worker         let container = ZbiContainer::parse(&buffer[..]).unwrap();
1856*5225e6b1SAndroid Build Coastguard Worker         let mut iter = container.iter();
1857*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(iter.next().unwrap().payload.as_bytes(), b"\x06file_1foo");
1858*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(iter.next().unwrap().payload.as_bytes(), b"\x06file_2bar");
1859*5225e6b1SAndroid Build Coastguard Worker         assert!(iter.next().is_none());
1860*5225e6b1SAndroid Build Coastguard Worker     }
1861*5225e6b1SAndroid Build Coastguard Worker 
1862*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_add_staged_bootloader_file_missing_file_name()1863*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_add_staged_bootloader_file_missing_file_name() {
1864*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
1865*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1866*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1867*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1868*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1869*5225e6b1SAndroid Build Coastguard Worker 
1870*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 3).as_bytes());
1871*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"foo");
1872*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem add-staged-bootloader-file");
1873*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
1874*5225e6b1SAndroid Build Coastguard Worker 
1875*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1876*5225e6b1SAndroid Build Coastguard Worker 
1877*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1878*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
1879*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
1880*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00000003",
1881*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1882*5225e6b1SAndroid Build Coastguard Worker                 b"FAILMissing file name",
1883*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
1884*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
1885*5225e6b1SAndroid Build Coastguard Worker             ]),
1886*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
1887*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
1888*5225e6b1SAndroid Build Coastguard Worker         )
1889*5225e6b1SAndroid Build Coastguard Worker     }
1890*5225e6b1SAndroid Build Coastguard Worker 
1891*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_add_staged_bootloader_file_missing_download()1892*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_add_staged_bootloader_file_missing_download() {
1893*5225e6b1SAndroid Build Coastguard Worker         let storage = FakeGblOpsStorage::default();
1894*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1895*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1896*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1897*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1898*5225e6b1SAndroid Build Coastguard Worker 
1899*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem add-staged-bootloader-file file1");
1900*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
1901*5225e6b1SAndroid Build Coastguard Worker 
1902*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1903*5225e6b1SAndroid Build Coastguard Worker 
1904*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1905*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
1906*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[b"FAILNo file staged", b"INFOSyncing storage...", b"OKAY",]),
1907*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
1908*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
1909*5225e6b1SAndroid Build Coastguard Worker         );
1910*5225e6b1SAndroid Build Coastguard Worker     }
1911*5225e6b1SAndroid Build Coastguard Worker 
1912*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_fuchsia_fastboot_mdns_packet()1913*5225e6b1SAndroid Build Coastguard Worker     fn test_fuchsia_fastboot_mdns_packet() {
1914*5225e6b1SAndroid Build Coastguard Worker         let expected = [
1915*5225e6b1SAndroid Build Coastguard Worker             0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x09, 0x5f,
1916*5225e6b1SAndroid Build Coastguard Worker             0x66, 0x61, 0x73, 0x74, 0x62, 0x6f, 0x6f, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05,
1917*5225e6b1SAndroid Build Coastguard Worker             0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78,
1918*5225e6b1SAndroid Build Coastguard Worker             0x00, 0x19, 0x16, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2d, 0x35, 0x32, 0x35,
1919*5225e6b1SAndroid Build Coastguard Worker             0x34, 0x2d, 0x30, 0x30, 0x31, 0x32, 0x2d, 0x33, 0x34, 0x35, 0x36, 0xc0, 0x0c, 0xc0,
1920*5225e6b1SAndroid Build Coastguard Worker             0x2c, 0x00, 0x21, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x1f, 0x00, 0x00, 0x00,
1921*5225e6b1SAndroid Build Coastguard Worker             0x00, 0x15, 0xb2, 0x16, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2d, 0x35, 0x32,
1922*5225e6b1SAndroid Build Coastguard Worker             0x35, 0x34, 0x2d, 0x30, 0x30, 0x31, 0x32, 0x2d, 0x33, 0x34, 0x35, 0x36, 0xc0, 0x1b,
1923*5225e6b1SAndroid Build Coastguard Worker             0xc0, 0x57, 0x00, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x10, 0xfe, 0x80,
1924*5225e6b1SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x54, 0x00, 0xff, 0xfe, 0x12, 0x34, 0x56,
1925*5225e6b1SAndroid Build Coastguard Worker         ];
1926*5225e6b1SAndroid Build Coastguard Worker         let ip6_addr = &[
1927*5225e6b1SAndroid Build Coastguard Worker             0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x54, 0x00, 0xff, 0xfe, 0x12,
1928*5225e6b1SAndroid Build Coastguard Worker             0x34, 0x56,
1929*5225e6b1SAndroid Build Coastguard Worker         ];
1930*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1931*5225e6b1SAndroid Build Coastguard Worker             fuchsia_fastboot_mdns_packet("fuchsia-5254-0012-3456", ip6_addr).unwrap(),
1932*5225e6b1SAndroid Build Coastguard Worker             expected
1933*5225e6b1SAndroid Build Coastguard Worker         );
1934*5225e6b1SAndroid Build Coastguard Worker     }
1935*5225e6b1SAndroid Build Coastguard Worker 
1936*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_fuchsia_fastboot_mdns_packet_invalid_node_name()1937*5225e6b1SAndroid Build Coastguard Worker     fn test_fuchsia_fastboot_mdns_packet_invalid_node_name() {
1938*5225e6b1SAndroid Build Coastguard Worker         let ip6_addr = &[
1939*5225e6b1SAndroid Build Coastguard Worker             0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x54, 0x00, 0xff, 0xfe, 0x12,
1940*5225e6b1SAndroid Build Coastguard Worker             0x34, 0x56,
1941*5225e6b1SAndroid Build Coastguard Worker         ];
1942*5225e6b1SAndroid Build Coastguard Worker         assert!(fuchsia_fastboot_mdns_packet("fuchsia-5254-0012-345", ip6_addr).is_err());
1943*5225e6b1SAndroid Build Coastguard Worker         assert!(fuchsia_fastboot_mdns_packet("fuchsia-5254-0012-34567", ip6_addr).is_err());
1944*5225e6b1SAndroid Build Coastguard Worker     }
1945*5225e6b1SAndroid Build Coastguard Worker 
1946*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt()1947*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt() {
1948*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
1949*5225e6b1SAndroid Build Coastguard Worker         // Erase the primary and secondary header.
1950*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1951*5225e6b1SAndroid Build Coastguard Worker         disk[512..][..512].fill(0);
1952*5225e6b1SAndroid Build Coastguard Worker         disk.last_chunk_mut::<512>().unwrap().fill(0);
1953*5225e6b1SAndroid Build Coastguard Worker 
1954*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
1955*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk);
1956*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
1957*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
1958*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
1959*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
1960*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
1961*5225e6b1SAndroid Build Coastguard Worker 
1962*5225e6b1SAndroid Build Coastguard Worker         // Checks that there is no valid partitions for block #0.
1963*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_a");
1964*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_b");
1965*5225e6b1SAndroid Build Coastguard Worker         // No partitions on block #0 should show up in `getvar:all` despite being a GPT device,
1966*5225e6b1SAndroid Build Coastguard Worker         // since the GPTs are corrupted.
1967*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:all");
1968*5225e6b1SAndroid Build Coastguard Worker         // Download a GPT
1969*5225e6b1SAndroid Build Coastguard Worker         let gpt = &disk_orig[..34 * 512];
1970*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", gpt.len()).as_bytes());
1971*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(gpt);
1972*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/0");
1973*5225e6b1SAndroid Build Coastguard Worker         // Checks that we can get partition info now.
1974*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_a");
1975*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_b");
1976*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:all");
1977*5225e6b1SAndroid Build Coastguard Worker 
1978*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
1979*5225e6b1SAndroid Build Coastguard Worker 
1980*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
1981*5225e6b1SAndroid Build Coastguard Worker 
1982*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1983*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
1984*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
1985*5225e6b1SAndroid Build Coastguard Worker                 b"FAILNotFound",
1986*5225e6b1SAndroid Build Coastguard Worker                 b"FAILNotFound",
1987*5225e6b1SAndroid Build Coastguard Worker                 b"INFOmax-download-size: 0x20000",
1988*5225e6b1SAndroid Build Coastguard Worker                 b"INFOversion-bootloader: 1.0",
1989*5225e6b1SAndroid Build Coastguard Worker                 b"INFOmax-fetch-size: 0xffffffffffffffff",
1990*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:total-blocks: 0x80",
1991*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:block-size: 0x200",
1992*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:status: idle",
1993*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:total-blocks: 0x100",
1994*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:block-size: 0x200",
1995*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:status: idle",
1996*5225e6b1SAndroid Build Coastguard Worker                 b"INFOgbl-default-block: None",
1997*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:vendor_boot_a/1: 0x1000",
1998*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:vendor_boot_a/1: raw",
1999*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:vendor_boot_b/1: 0x1800",
2000*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:vendor_boot_b/1: raw",
2001*5225e6b1SAndroid Build Coastguard Worker                 format!("INFO{}:1: {}:1", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
2002*5225e6b1SAndroid Build Coastguard Worker                     .as_bytes(),
2003*5225e6b1SAndroid Build Coastguard Worker                 format!("INFO{}:2: {}:2", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
2004*5225e6b1SAndroid Build Coastguard Worker                     .as_bytes(),
2005*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2006*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00004400",
2007*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2008*5225e6b1SAndroid Build Coastguard Worker                 b"INFOUpdating GPT...",
2009*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2010*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x2000",
2011*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x3000",
2012*5225e6b1SAndroid Build Coastguard Worker                 b"INFOmax-download-size: 0x20000",
2013*5225e6b1SAndroid Build Coastguard Worker                 b"INFOversion-bootloader: 1.0",
2014*5225e6b1SAndroid Build Coastguard Worker                 b"INFOmax-fetch-size: 0xffffffffffffffff",
2015*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:total-blocks: 0x80",
2016*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:block-size: 0x200",
2017*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:0:status: idle",
2018*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:total-blocks: 0x100",
2019*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:block-size: 0x200",
2020*5225e6b1SAndroid Build Coastguard Worker                 b"INFOblock-device:1:status: idle",
2021*5225e6b1SAndroid Build Coastguard Worker                 b"INFOgbl-default-block: None",
2022*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:boot_a/0: 0x2000",
2023*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:boot_a/0: raw",
2024*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:boot_b/0: 0x3000",
2025*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:boot_b/0: raw",
2026*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:vendor_boot_a/1: 0x1000",
2027*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:vendor_boot_a/1: raw",
2028*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-size:vendor_boot_b/1: 0x1800",
2029*5225e6b1SAndroid Build Coastguard Worker                 b"INFOpartition-type:vendor_boot_b/1: raw",
2030*5225e6b1SAndroid Build Coastguard Worker                 format!("INFO{}:1: {}:1", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
2031*5225e6b1SAndroid Build Coastguard Worker                     .as_bytes(),
2032*5225e6b1SAndroid Build Coastguard Worker                 format!("INFO{}:2: {}:2", FakeGblOps::GBL_TEST_VAR, FakeGblOps::GBL_TEST_VAR_VAL)
2033*5225e6b1SAndroid Build Coastguard Worker                     .as_bytes(),
2034*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2035*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2036*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2037*5225e6b1SAndroid Build Coastguard Worker             ]),
2038*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2039*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2040*5225e6b1SAndroid Build Coastguard Worker         );
2041*5225e6b1SAndroid Build Coastguard Worker     }
2042*5225e6b1SAndroid Build Coastguard Worker 
2043*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt_resize()2044*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt_resize() {
2045*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
2046*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
2047*5225e6b1SAndroid Build Coastguard Worker         // Doubles the size of the disk
2048*5225e6b1SAndroid Build Coastguard Worker         disk.resize(disk_orig.len() * 2, 0);
2049*5225e6b1SAndroid Build Coastguard Worker 
2050*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2051*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
2052*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk);
2053*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2054*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2055*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2056*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2057*5225e6b1SAndroid Build Coastguard Worker 
2058*5225e6b1SAndroid Build Coastguard Worker         // Checks current size of last partition `boot_b`.
2059*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_b");
2060*5225e6b1SAndroid Build Coastguard Worker         // Sets a default block.
2061*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem gbl-set-default-block 1");
2062*5225e6b1SAndroid Build Coastguard Worker         let gpt = &disk_orig[..34 * 512];
2063*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", gpt.len()).as_bytes());
2064*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(gpt);
2065*5225e6b1SAndroid Build Coastguard Worker         // No need to specify block device index
2066*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt//resize");
2067*5225e6b1SAndroid Build Coastguard Worker         // Checks updated size of last partition `boot_b`.
2068*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_b");
2069*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2070*5225e6b1SAndroid Build Coastguard Worker 
2071*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2072*5225e6b1SAndroid Build Coastguard Worker 
2073*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2074*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2075*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2076*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x3000",
2077*5225e6b1SAndroid Build Coastguard Worker                 b"INFODefault block device: 0x1",
2078*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2079*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00004400",
2080*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2081*5225e6b1SAndroid Build Coastguard Worker                 b"INFOUpdating GPT...",
2082*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2083*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x15a00",
2084*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2085*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2086*5225e6b1SAndroid Build Coastguard Worker             ]),
2087*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2088*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2089*5225e6b1SAndroid Build Coastguard Worker         );
2090*5225e6b1SAndroid Build Coastguard Worker     }
2091*5225e6b1SAndroid Build Coastguard Worker 
2092*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt_no_downloaded_gpt()2093*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt_no_downloaded_gpt() {
2094*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
2095*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2096*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk);
2097*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2098*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2099*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2100*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2101*5225e6b1SAndroid Build Coastguard Worker 
2102*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/0");
2103*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2104*5225e6b1SAndroid Build Coastguard Worker 
2105*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2106*5225e6b1SAndroid Build Coastguard Worker 
2107*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2108*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2109*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[b"FAILNo GPT downloaded", b"INFOSyncing storage...", b"OKAY",]),
2110*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2111*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2112*5225e6b1SAndroid Build Coastguard Worker         );
2113*5225e6b1SAndroid Build Coastguard Worker     }
2114*5225e6b1SAndroid Build Coastguard Worker 
2115*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt_bad_gpt()2116*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt_bad_gpt() {
2117*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
2118*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2119*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk);
2120*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2121*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2122*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2123*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2124*5225e6b1SAndroid Build Coastguard Worker         // Download a bad GPT.
2125*5225e6b1SAndroid Build Coastguard Worker         let mut gpt = disk[..34 * 512].to_vec();
2126*5225e6b1SAndroid Build Coastguard Worker         gpt[512] = !gpt[512];
2127*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", gpt.len()).as_bytes());
2128*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(&gpt);
2129*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/0");
2130*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2131*5225e6b1SAndroid Build Coastguard Worker 
2132*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2133*5225e6b1SAndroid Build Coastguard Worker 
2134*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2135*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2136*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2137*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00004400",
2138*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2139*5225e6b1SAndroid Build Coastguard Worker                 b"INFOUpdating GPT...",
2140*5225e6b1SAndroid Build Coastguard Worker                 b"FAILGptError(\n    IncorrectMagic(\n        6075990659671082682,\n    ),\n)",
2141*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2142*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2143*5225e6b1SAndroid Build Coastguard Worker             ]),
2144*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2145*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2146*5225e6b1SAndroid Build Coastguard Worker         );
2147*5225e6b1SAndroid Build Coastguard Worker     }
2148*5225e6b1SAndroid Build Coastguard Worker 
2149*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt_invalid_input()2150*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt_invalid_input() {
2151*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
2152*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2153*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk_orig);
2154*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(&disk_orig);
2155*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2156*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2157*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2158*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2159*5225e6b1SAndroid Build Coastguard Worker 
2160*5225e6b1SAndroid Build Coastguard Worker         let gpt = &disk_orig[..34 * 512];
2161*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", gpt.len()).as_bytes());
2162*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(gpt);
2163*5225e6b1SAndroid Build Coastguard Worker         // Missing block device ID.
2164*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt");
2165*5225e6b1SAndroid Build Coastguard Worker         // Out of range block device ID.
2166*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/2");
2167*5225e6b1SAndroid Build Coastguard Worker         // Invalid option.
2168*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/0/invalid-arg");
2169*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2170*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2171*5225e6b1SAndroid Build Coastguard Worker 
2172*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2173*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2174*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2175*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00004400",
2176*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2177*5225e6b1SAndroid Build Coastguard Worker                 b"FAILBlock ID is required for flashing GPT",
2178*5225e6b1SAndroid Build Coastguard Worker                 b"FAILInvalid block ID",
2179*5225e6b1SAndroid Build Coastguard Worker                 b"FAILUnknown argument",
2180*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2181*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2182*5225e6b1SAndroid Build Coastguard Worker             ]),
2183*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2184*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2185*5225e6b1SAndroid Build Coastguard Worker         );
2186*5225e6b1SAndroid Build Coastguard Worker     }
2187*5225e6b1SAndroid Build Coastguard Worker 
2188*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_update_gpt_fail_on_raw_blk()2189*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_update_gpt_fail_on_raw_blk() {
2190*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../../../libstorage/test/gpt_test_1.bin");
2191*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2192*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0u8; 1024 * 1024]);
2193*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2194*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2195*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2196*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2197*5225e6b1SAndroid Build Coastguard Worker 
2198*5225e6b1SAndroid Build Coastguard Worker         let gpt = &disk_orig[..34 * 512];
2199*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", gpt.len()).as_bytes());
2200*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(gpt);
2201*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:gpt/0");
2202*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2203*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2204*5225e6b1SAndroid Build Coastguard Worker 
2205*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2206*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2207*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2208*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00004400",
2209*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2210*5225e6b1SAndroid Build Coastguard Worker                 b"INFOUpdating GPT...",
2211*5225e6b1SAndroid Build Coastguard Worker                 b"FAILBlock device is not for GPT",
2212*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2213*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2214*5225e6b1SAndroid Build Coastguard Worker             ]),
2215*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2216*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2217*5225e6b1SAndroid Build Coastguard Worker         );
2218*5225e6b1SAndroid Build Coastguard Worker     }
2219*5225e6b1SAndroid Build Coastguard Worker 
2220*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_erase_gpt()2221*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_erase_gpt() {
2222*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2223*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_1.bin"));
2224*5225e6b1SAndroid Build Coastguard Worker         storage.add_gpt_device(include_bytes!("../../../libstorage/test/gpt_test_2.bin"));
2225*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2226*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2227*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2228*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2229*5225e6b1SAndroid Build Coastguard Worker 
2230*5225e6b1SAndroid Build Coastguard Worker         // Erases the GPT on disk #0.
2231*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"erase:gpt/0");
2232*5225e6b1SAndroid Build Coastguard Worker         // Checks that we can no longer get partition info on disk #0.
2233*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_a");
2234*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:boot_b");
2235*5225e6b1SAndroid Build Coastguard Worker         // Checks that we can still get partition info on disk #1.
2236*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:vendor_boot_a");
2237*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"getvar:partition-size:vendor_boot_b");
2238*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2239*5225e6b1SAndroid Build Coastguard Worker 
2240*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2241*5225e6b1SAndroid Build Coastguard Worker 
2242*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2243*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2244*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2245*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2246*5225e6b1SAndroid Build Coastguard Worker                 b"FAILNotFound",
2247*5225e6b1SAndroid Build Coastguard Worker                 b"FAILNotFound",
2248*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x1000",
2249*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY0x1800",
2250*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2251*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2252*5225e6b1SAndroid Build Coastguard Worker             ]),
2253*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2254*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2255*5225e6b1SAndroid Build Coastguard Worker         );
2256*5225e6b1SAndroid Build Coastguard Worker     }
2257*5225e6b1SAndroid Build Coastguard Worker 
2258*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_oem_erase_gpt_fail_on_raw_blk()2259*5225e6b1SAndroid Build Coastguard Worker     fn test_oem_erase_gpt_fail_on_raw_blk() {
2260*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2261*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"raw_0", [0u8; 1024 * 1024]);
2262*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2263*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2264*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2265*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2266*5225e6b1SAndroid Build Coastguard Worker 
2267*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"erase:gpt/0");
2268*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2269*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2270*5225e6b1SAndroid Build Coastguard Worker 
2271*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2272*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2273*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2274*5225e6b1SAndroid Build Coastguard Worker                 b"FAILBlock device is not for GPT",
2275*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2276*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2277*5225e6b1SAndroid Build Coastguard Worker             ]),
2278*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2279*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2280*5225e6b1SAndroid Build Coastguard Worker         );
2281*5225e6b1SAndroid Build Coastguard Worker     }
2282*5225e6b1SAndroid Build Coastguard Worker 
2283*5225e6b1SAndroid Build Coastguard Worker     /// Helper for testing fastboot set_active in fuchsia A/B/R mode.
test_run_gbl_fastboot_set_active_fuchsia_abr(cmd: &str, slot: SlotIndex)2284*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_set_active_fuchsia_abr(cmd: &str, slot: SlotIndex) {
2285*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2286*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"durable_boot", [0x00u8; 4 * 1024]);
2287*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2288*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2289*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.os = Some(Os::Fuchsia);
2290*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2291*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2292*5225e6b1SAndroid Build Coastguard Worker 
2293*5225e6b1SAndroid Build Coastguard Worker         mark_slot_unbootable(&mut GblAbrOps(&mut gbl_ops), SlotIndex::A).unwrap();
2294*5225e6b1SAndroid Build Coastguard Worker         mark_slot_unbootable(&mut GblAbrOps(&mut gbl_ops), SlotIndex::B).unwrap();
2295*5225e6b1SAndroid Build Coastguard Worker 
2296*5225e6b1SAndroid Build Coastguard Worker         // Flash some data to `durable_boot` after A/B/R metadata. This is for testing that sync
2297*5225e6b1SAndroid Build Coastguard Worker         // storage is done first.
2298*5225e6b1SAndroid Build Coastguard Worker         let data = vec![0x55u8; 4 * 1024 - ABR_DATA_SIZE];
2299*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"oem gbl-enable-async-task");
2300*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 4 * 1024 - ABR_DATA_SIZE).as_bytes());
2301*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(&data);
2302*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("flash:durable_boot//{:#x}", ABR_DATA_SIZE).as_bytes());
2303*5225e6b1SAndroid Build Coastguard Worker         // Issues set_active commands
2304*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(cmd.as_bytes());
2305*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2306*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2307*5225e6b1SAndroid Build Coastguard Worker 
2308*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2309*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2310*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2311*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2312*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00000fe0",
2313*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2314*5225e6b1SAndroid Build Coastguard Worker                 b"INFOAn IO task is launched. To sync manually, run \"oem gbl-sync-tasks\".",
2315*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2316*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2317*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2318*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2319*5225e6b1SAndroid Build Coastguard Worker             ]),
2320*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2321*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2322*5225e6b1SAndroid Build Coastguard Worker         );
2323*5225e6b1SAndroid Build Coastguard Worker 
2324*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(get_boot_slot(&mut GblAbrOps(&mut gbl_ops), true), (slot, false));
2325*5225e6b1SAndroid Build Coastguard Worker         // Verifies storage sync
2326*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2327*5225e6b1SAndroid Build Coastguard Worker             storage[0].partition_io(None).unwrap().dev().io().storage[ABR_DATA_SIZE..],
2328*5225e6b1SAndroid Build Coastguard Worker             data
2329*5225e6b1SAndroid Build Coastguard Worker         );
2330*5225e6b1SAndroid Build Coastguard Worker     }
2331*5225e6b1SAndroid Build Coastguard Worker 
2332*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_set_active_fuchsia_abr_a()2333*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_set_active_fuchsia_abr_a() {
2334*5225e6b1SAndroid Build Coastguard Worker         test_run_gbl_fastboot_set_active_fuchsia_abr("set_active:a", SlotIndex::A);
2335*5225e6b1SAndroid Build Coastguard Worker     }
2336*5225e6b1SAndroid Build Coastguard Worker 
2337*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_set_active_fuchsia_abr_b()2338*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_set_active_fuchsia_abr_b() {
2339*5225e6b1SAndroid Build Coastguard Worker         test_run_gbl_fastboot_set_active_fuchsia_abr("set_active:b", SlotIndex::B);
2340*5225e6b1SAndroid Build Coastguard Worker     }
2341*5225e6b1SAndroid Build Coastguard Worker 
2342*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_set_active_fuchsia_abr_invalid_slot()2343*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_set_active_fuchsia_abr_invalid_slot() {
2344*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2345*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"durable_boot", [0x00u8; 4 * 1024]);
2346*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2347*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2348*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.os = Some(Os::Fuchsia);
2349*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2350*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2351*5225e6b1SAndroid Build Coastguard Worker 
2352*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"set_active:r");
2353*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2354*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2355*5225e6b1SAndroid Build Coastguard Worker 
2356*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2357*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2358*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2359*5225e6b1SAndroid Build Coastguard Worker                 b"FAILInvalid slot index for Fuchsia A/B/R",
2360*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2361*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2362*5225e6b1SAndroid Build Coastguard Worker             ]),
2363*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2364*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2365*5225e6b1SAndroid Build Coastguard Worker         );
2366*5225e6b1SAndroid Build Coastguard Worker     }
2367*5225e6b1SAndroid Build Coastguard Worker 
2368*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_fuchsia_reboot_bootloader_abr()2369*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_fuchsia_reboot_bootloader_abr() {
2370*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2371*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"durable_boot", [0x00u8; 4 * 1024]);
2372*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2373*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2374*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.os = Some(Os::Fuchsia);
2375*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2376*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2377*5225e6b1SAndroid Build Coastguard Worker 
2378*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"reboot-bootloader");
2379*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2380*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2381*5225e6b1SAndroid Build Coastguard Worker 
2382*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2383*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2384*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2385*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2386*5225e6b1SAndroid Build Coastguard Worker                 b"INFORebooting to bootloader...",
2387*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2388*5225e6b1SAndroid Build Coastguard Worker                 b"FAILUnknown",
2389*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2390*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2391*5225e6b1SAndroid Build Coastguard Worker             ]),
2392*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2393*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2394*5225e6b1SAndroid Build Coastguard Worker         );
2395*5225e6b1SAndroid Build Coastguard Worker 
2396*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(get_and_clear_one_shot_bootloader(&mut GblAbrOps(&mut gbl_ops)), Ok(true));
2397*5225e6b1SAndroid Build Coastguard Worker     }
2398*5225e6b1SAndroid Build Coastguard Worker 
2399*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_run_gbl_fastboot_fuchsia_reboot_recovery_abr()2400*5225e6b1SAndroid Build Coastguard Worker     fn test_run_gbl_fastboot_fuchsia_reboot_recovery_abr() {
2401*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2402*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"durable_boot", [0x00u8; 4 * 1024]);
2403*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2404*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2405*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.os = Some(Os::Fuchsia);
2406*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2407*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2408*5225e6b1SAndroid Build Coastguard Worker 
2409*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"reboot-recovery");
2410*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2411*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2412*5225e6b1SAndroid Build Coastguard Worker 
2413*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2414*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2415*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2416*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2417*5225e6b1SAndroid Build Coastguard Worker                 b"INFORebooting to recovery...",
2418*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2419*5225e6b1SAndroid Build Coastguard Worker                 b"FAILUnknown",
2420*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2421*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2422*5225e6b1SAndroid Build Coastguard Worker             ]),
2423*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2424*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2425*5225e6b1SAndroid Build Coastguard Worker         );
2426*5225e6b1SAndroid Build Coastguard Worker 
2427*5225e6b1SAndroid Build Coastguard Worker         // One shot recovery is set.
2428*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(get_boot_slot(&mut GblAbrOps(&mut gbl_ops), true), (SlotIndex::R, false));
2429*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(get_boot_slot(&mut GblAbrOps(&mut gbl_ops), true), (SlotIndex::A, false));
2430*5225e6b1SAndroid Build Coastguard Worker     }
2431*5225e6b1SAndroid Build Coastguard Worker 
2432*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_legacy_fvm_partition_aliase()2433*5225e6b1SAndroid Build Coastguard Worker     fn test_legacy_fvm_partition_aliase() {
2434*5225e6b1SAndroid Build Coastguard Worker         let mut storage = FakeGblOpsStorage::default();
2435*5225e6b1SAndroid Build Coastguard Worker         storage.add_raw_device(c"fuchsia-fvm", [0x00u8; 4 * 1024]);
2436*5225e6b1SAndroid Build Coastguard Worker         let buffers = vec![vec![0u8; 128 * 1024]; 2];
2437*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&storage);
2438*5225e6b1SAndroid Build Coastguard Worker         gbl_ops.os = Some(Os::Fuchsia);
2439*5225e6b1SAndroid Build Coastguard Worker         let listener: SharedTestListener = Default::default();
2440*5225e6b1SAndroid Build Coastguard Worker         let (usb, tcp) = (&listener, &listener);
2441*5225e6b1SAndroid Build Coastguard Worker 
2442*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(format!("download:{:#x}", 4 * 1024).as_bytes());
2443*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(&[0xaau8; 4 * 1024]);
2444*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"flash:fvm");
2445*5225e6b1SAndroid Build Coastguard Worker         listener.add_usb_input(b"continue");
2446*5225e6b1SAndroid Build Coastguard Worker         block_on(run_gbl_fastboot_stack::<2>(&mut gbl_ops, buffers, Some(usb), Some(tcp), &mut []));
2447*5225e6b1SAndroid Build Coastguard Worker 
2448*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
2449*5225e6b1SAndroid Build Coastguard Worker             listener.usb_out_queue(),
2450*5225e6b1SAndroid Build Coastguard Worker             make_expected_usb_out(&[
2451*5225e6b1SAndroid Build Coastguard Worker                 b"DATA00001000",
2452*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2453*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2454*5225e6b1SAndroid Build Coastguard Worker                 b"INFOSyncing storage...",
2455*5225e6b1SAndroid Build Coastguard Worker                 b"OKAY",
2456*5225e6b1SAndroid Build Coastguard Worker             ]),
2457*5225e6b1SAndroid Build Coastguard Worker             "\nActual USB output:\n{}",
2458*5225e6b1SAndroid Build Coastguard Worker             listener.dump_usb_out_queue()
2459*5225e6b1SAndroid Build Coastguard Worker         );
2460*5225e6b1SAndroid Build Coastguard Worker     }
2461*5225e6b1SAndroid Build Coastguard Worker }
2462