xref: /aosp_15_r20/bootable/libbootloader/gbl/libbootparams/src/bootconfig.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, 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 //! Module for constructing bootconfig. See the following for more details:
16*5225e6b1SAndroid Build Coastguard Worker //!
17*5225e6b1SAndroid Build Coastguard Worker //! https://source.android.com/docs/core/architecture/bootloader/implementing-bootconfig#bootloader-changes
18*5225e6b1SAndroid Build Coastguard Worker 
19*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
20*5225e6b1SAndroid Build Coastguard Worker 
21*5225e6b1SAndroid Build Coastguard Worker /// A class for constructing bootconfig section.
22*5225e6b1SAndroid Build Coastguard Worker pub struct BootConfigBuilder<'a> {
23*5225e6b1SAndroid Build Coastguard Worker     current_size: usize,
24*5225e6b1SAndroid Build Coastguard Worker     buffer: &'a mut [u8],
25*5225e6b1SAndroid Build Coastguard Worker }
26*5225e6b1SAndroid Build Coastguard Worker 
27*5225e6b1SAndroid Build Coastguard Worker const BOOTCONFIG_MAGIC: &str = "#BOOTCONFIG\n";
28*5225e6b1SAndroid Build Coastguard Worker // Trailer structure:
29*5225e6b1SAndroid Build Coastguard Worker // struct {
30*5225e6b1SAndroid Build Coastguard Worker //     config_size: u32,
31*5225e6b1SAndroid Build Coastguard Worker //     checksum: u32,
32*5225e6b1SAndroid Build Coastguard Worker //     bootconfig_magic: [u8]
33*5225e6b1SAndroid Build Coastguard Worker // }
34*5225e6b1SAndroid Build Coastguard Worker const BOOTCONFIG_TRAILER_SIZE: usize = 4 + 4 + BOOTCONFIG_MAGIC.len();
35*5225e6b1SAndroid Build Coastguard Worker 
36*5225e6b1SAndroid Build Coastguard Worker impl<'a> BootConfigBuilder<'a> {
37*5225e6b1SAndroid Build Coastguard Worker     /// Initialize with a given buffer.
new(buffer: &'a mut [u8]) -> Result<Self>38*5225e6b1SAndroid Build Coastguard Worker     pub fn new(buffer: &'a mut [u8]) -> Result<Self> {
39*5225e6b1SAndroid Build Coastguard Worker         if buffer.len() < BOOTCONFIG_TRAILER_SIZE {
40*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::BufferTooSmall(Some(BOOTCONFIG_TRAILER_SIZE)));
41*5225e6b1SAndroid Build Coastguard Worker         }
42*5225e6b1SAndroid Build Coastguard Worker         let mut ret = Self { current_size: 0, buffer: buffer };
43*5225e6b1SAndroid Build Coastguard Worker         ret.update_trailer()?;
44*5225e6b1SAndroid Build Coastguard Worker         Ok(ret)
45*5225e6b1SAndroid Build Coastguard Worker     }
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker     /// Get the remaining capacity for adding new bootconfig.
remaining_capacity(&self) -> usize48*5225e6b1SAndroid Build Coastguard Worker     pub fn remaining_capacity(&self) -> usize {
49*5225e6b1SAndroid Build Coastguard Worker         self.buffer
50*5225e6b1SAndroid Build Coastguard Worker             .len()
51*5225e6b1SAndroid Build Coastguard Worker             .checked_sub(self.current_size)
52*5225e6b1SAndroid Build Coastguard Worker             .unwrap()
53*5225e6b1SAndroid Build Coastguard Worker             .checked_sub(BOOTCONFIG_TRAILER_SIZE)
54*5225e6b1SAndroid Build Coastguard Worker             .unwrap()
55*5225e6b1SAndroid Build Coastguard Worker     }
56*5225e6b1SAndroid Build Coastguard Worker 
57*5225e6b1SAndroid Build Coastguard Worker     /// Get the whole config bytes including trailer.
config_bytes(&self) -> &[u8]58*5225e6b1SAndroid Build Coastguard Worker     pub fn config_bytes(&self) -> &[u8] {
59*5225e6b1SAndroid Build Coastguard Worker         // Arithmetic not expected to fail.
60*5225e6b1SAndroid Build Coastguard Worker         &self.buffer[..self.current_size.checked_add(BOOTCONFIG_TRAILER_SIZE).unwrap()]
61*5225e6b1SAndroid Build Coastguard Worker     }
62*5225e6b1SAndroid Build Coastguard Worker 
63*5225e6b1SAndroid Build Coastguard Worker     /// Append a new config via a reader callback.
64*5225e6b1SAndroid Build Coastguard Worker     ///
65*5225e6b1SAndroid Build Coastguard Worker     /// A `&mut [u8]` that covers the remaining space is passed to the callback for reading the
66*5225e6b1SAndroid Build Coastguard Worker     /// config bytes. It should return the total size read if operation is successful or
67*5225e6b1SAndroid Build Coastguard Worker     /// `Error::BufferTooSmall(Some(<minimum_buffer_size>))`. Attempting to return a size
68*5225e6b1SAndroid Build Coastguard Worker     /// greater than the input will cause it to panic. Empty read is allowed. It's up to the caller
69*5225e6b1SAndroid Build Coastguard Worker     /// to make sure the read content will eventually form a valid boot config. The API is for
70*5225e6b1SAndroid Build Coastguard Worker     /// situations where configs are read from sources such as disk and separate buffer allocation
71*5225e6b1SAndroid Build Coastguard Worker     /// is not possible or desired.
add_with<F>(&mut self, reader: F) -> Result<()> where F: FnOnce(&[u8], &mut [u8]) -> Result<usize>,72*5225e6b1SAndroid Build Coastguard Worker     pub fn add_with<F>(&mut self, reader: F) -> Result<()>
73*5225e6b1SAndroid Build Coastguard Worker     where
74*5225e6b1SAndroid Build Coastguard Worker         F: FnOnce(&[u8], &mut [u8]) -> Result<usize>,
75*5225e6b1SAndroid Build Coastguard Worker     {
76*5225e6b1SAndroid Build Coastguard Worker         let remains = self.remaining_capacity();
77*5225e6b1SAndroid Build Coastguard Worker         let (current_buffer, remains_buffer) = self.buffer.split_at_mut(self.current_size);
78*5225e6b1SAndroid Build Coastguard Worker         let size = reader(&current_buffer[..], &mut remains_buffer[..remains])?;
79*5225e6b1SAndroid Build Coastguard Worker         assert!(size <= remains);
80*5225e6b1SAndroid Build Coastguard Worker         self.current_size += size;
81*5225e6b1SAndroid Build Coastguard Worker         // Content may have been modified. Re-compute trailer.
82*5225e6b1SAndroid Build Coastguard Worker         self.update_trailer()
83*5225e6b1SAndroid Build Coastguard Worker     }
84*5225e6b1SAndroid Build Coastguard Worker 
85*5225e6b1SAndroid Build Coastguard Worker     /// Append a new config from string.
add(&mut self, config: &str) -> Result<()>86*5225e6b1SAndroid Build Coastguard Worker     pub fn add(&mut self, config: &str) -> Result<()> {
87*5225e6b1SAndroid Build Coastguard Worker         if self.remaining_capacity() < config.len() {
88*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::BufferTooSmall(Some(config.len())));
89*5225e6b1SAndroid Build Coastguard Worker         }
90*5225e6b1SAndroid Build Coastguard Worker         self.add_with(|_, out| {
91*5225e6b1SAndroid Build Coastguard Worker             out[..config.len()].clone_from_slice(config.as_bytes());
92*5225e6b1SAndroid Build Coastguard Worker             Ok(config.len())
93*5225e6b1SAndroid Build Coastguard Worker         })
94*5225e6b1SAndroid Build Coastguard Worker     }
95*5225e6b1SAndroid Build Coastguard Worker 
96*5225e6b1SAndroid Build Coastguard Worker     /// Update the boot config trailer at the end of parameter list.
97*5225e6b1SAndroid Build Coastguard Worker     /// See specification at:
98*5225e6b1SAndroid Build Coastguard Worker     /// https://source.android.com/docs/core/architecture/bootloader/implementing-bootconfig#bootloader-changes
update_trailer(&mut self) -> Result<()>99*5225e6b1SAndroid Build Coastguard Worker     fn update_trailer(&mut self) -> Result<()> {
100*5225e6b1SAndroid Build Coastguard Worker         // Config size
101*5225e6b1SAndroid Build Coastguard Worker         let size: u32 = self.current_size.try_into().or(Err(Error::Other(None)))?;
102*5225e6b1SAndroid Build Coastguard Worker         // Check sum.
103*5225e6b1SAndroid Build Coastguard Worker         let checksum = self.checksum();
104*5225e6b1SAndroid Build Coastguard Worker         let trailer = &mut self.buffer[self.current_size..];
105*5225e6b1SAndroid Build Coastguard Worker         trailer[..4].clone_from_slice(&size.to_le_bytes());
106*5225e6b1SAndroid Build Coastguard Worker         trailer[4..8].clone_from_slice(&checksum.to_le_bytes());
107*5225e6b1SAndroid Build Coastguard Worker         trailer[8..][..BOOTCONFIG_MAGIC.len()].clone_from_slice(BOOTCONFIG_MAGIC.as_bytes());
108*5225e6b1SAndroid Build Coastguard Worker         Ok(())
109*5225e6b1SAndroid Build Coastguard Worker     }
110*5225e6b1SAndroid Build Coastguard Worker 
111*5225e6b1SAndroid Build Coastguard Worker     /// Compute the checksum value.
checksum(&self) -> u32112*5225e6b1SAndroid Build Coastguard Worker     fn checksum(&self) -> u32 {
113*5225e6b1SAndroid Build Coastguard Worker         self.buffer[..self.current_size]
114*5225e6b1SAndroid Build Coastguard Worker             .iter()
115*5225e6b1SAndroid Build Coastguard Worker             .map(|v| *v as u32)
116*5225e6b1SAndroid Build Coastguard Worker             .reduce(|acc, v| acc.overflowing_add(v).0)
117*5225e6b1SAndroid Build Coastguard Worker             .unwrap_or(0)
118*5225e6b1SAndroid Build Coastguard Worker     }
119*5225e6b1SAndroid Build Coastguard Worker }
120*5225e6b1SAndroid Build Coastguard Worker 
121*5225e6b1SAndroid Build Coastguard Worker impl core::fmt::Display for BootConfigBuilder<'_> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result122*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123*5225e6b1SAndroid Build Coastguard Worker         let bytes = self.config_bytes();
124*5225e6b1SAndroid Build Coastguard Worker         for val in &bytes[..bytes.len().checked_sub(BOOTCONFIG_TRAILER_SIZE).unwrap()] {
125*5225e6b1SAndroid Build Coastguard Worker             write!(f, "{}", core::ascii::escape_default(*val))?;
126*5225e6b1SAndroid Build Coastguard Worker         }
127*5225e6b1SAndroid Build Coastguard Worker         Ok(())
128*5225e6b1SAndroid Build Coastguard Worker     }
129*5225e6b1SAndroid Build Coastguard Worker }
130*5225e6b1SAndroid Build Coastguard Worker 
131*5225e6b1SAndroid Build Coastguard Worker impl core::fmt::Write for BootConfigBuilder<'_> {
write_str(&mut self, s: &str) -> core::fmt::Result132*5225e6b1SAndroid Build Coastguard Worker     fn write_str(&mut self, s: &str) -> core::fmt::Result {
133*5225e6b1SAndroid Build Coastguard Worker         self.add_with(|_, out| {
134*5225e6b1SAndroid Build Coastguard Worker             out.get_mut(..s.len())
135*5225e6b1SAndroid Build Coastguard Worker                 .ok_or(Error::BufferTooSmall(Some(s.len())))?
136*5225e6b1SAndroid Build Coastguard Worker                 .clone_from_slice(s.as_bytes());
137*5225e6b1SAndroid Build Coastguard Worker             Ok(s.len())
138*5225e6b1SAndroid Build Coastguard Worker         })
139*5225e6b1SAndroid Build Coastguard Worker         .map_err(|_| core::fmt::Error)?;
140*5225e6b1SAndroid Build Coastguard Worker         Ok(())
141*5225e6b1SAndroid Build Coastguard Worker     }
142*5225e6b1SAndroid Build Coastguard Worker }
143*5225e6b1SAndroid Build Coastguard Worker 
144*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
145*5225e6b1SAndroid Build Coastguard Worker mod test {
146*5225e6b1SAndroid Build Coastguard Worker     use super::*;
147*5225e6b1SAndroid Build Coastguard Worker     use core::fmt::Write;
148*5225e6b1SAndroid Build Coastguard Worker 
149*5225e6b1SAndroid Build Coastguard Worker     // Taken from Cuttlefish on QEMU aarch64.
150*5225e6b1SAndroid Build Coastguard Worker     const TEST_CONFIG: &str = "androidboot.hardware=cutf_cvm
151*5225e6b1SAndroid Build Coastguard Worker kernel.mac80211_hwsim.radios=0
152*5225e6b1SAndroid Build Coastguard Worker kernel.vmw_vsock_virtio_transport_common.virtio_transport_max_vsock_pkt_buf_size=16384
153*5225e6b1SAndroid Build Coastguard Worker androidboot.vendor.apex.com.google.emulated.camera.provider.hal=com.google.emulated.camera.provider.hal
154*5225e6b1SAndroid Build Coastguard Worker androidboot.slot_suffix=_a
155*5225e6b1SAndroid Build Coastguard Worker androidboot.force_normal_boot=1
156*5225e6b1SAndroid Build Coastguard Worker androidboot.hw_timeout_multiplier=50
157*5225e6b1SAndroid Build Coastguard Worker androidboot.fstab_suffix=cf.f2fs.hctr2
158*5225e6b1SAndroid Build Coastguard Worker androidboot.hypervisor.protected_vm.supported=0
159*5225e6b1SAndroid Build Coastguard Worker androidboot.modem_simulator_ports=9600
160*5225e6b1SAndroid Build Coastguard Worker androidboot.vsock_lights_port=6900
161*5225e6b1SAndroid Build Coastguard Worker androidboot.lcd_density=320
162*5225e6b1SAndroid Build Coastguard Worker androidboot.vendor.audiocontrol.server.port=9410
163*5225e6b1SAndroid Build Coastguard Worker androidboot.vendor.audiocontrol.server.cid=3
164*5225e6b1SAndroid Build Coastguard Worker androidboot.cuttlefish_config_server_port=6800
165*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.gralloc=minigbm
166*5225e6b1SAndroid Build Coastguard Worker androidboot.vsock_lights_cid=3
167*5225e6b1SAndroid Build Coastguard Worker androidboot.enable_confirmationui=0
168*5225e6b1SAndroid Build Coastguard Worker androidboot.hypervisor.vm.supported=0
169*5225e6b1SAndroid Build Coastguard Worker androidboot.setupwizard_mode=DISABLED
170*5225e6b1SAndroid Build Coastguard Worker androidboot.serialno=CUTTLEFISHCVD011
171*5225e6b1SAndroid Build Coastguard Worker androidboot.enable_bootanimation=1
172*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.hwcomposer.display_finder_mode=drm
173*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.angle_feature_overrides_enabled=preferLinearFilterForYUV:mapUnspecifiedColorSpaceToPassThrough
174*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.egl=mesa
175*5225e6b1SAndroid Build Coastguard Worker androidboot.boot_devices=4010000000.pcie
176*5225e6b1SAndroid Build Coastguard Worker androidboot.opengles.version=196608
177*5225e6b1SAndroid Build Coastguard Worker androidboot.wifi_mac_prefix=5554
178*5225e6b1SAndroid Build Coastguard Worker androidboot.vsock_tombstone_port=6600
179*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.hwcomposer=ranchu
180*5225e6b1SAndroid Build Coastguard Worker androidboot.hardware.hwcomposer.mode=client
181*5225e6b1SAndroid Build Coastguard Worker androidboot.console=ttyAMA0
182*5225e6b1SAndroid Build Coastguard Worker androidboot.ddr_size=4915MB
183*5225e6b1SAndroid Build Coastguard Worker androidboot.cpuvulkan.version=0
184*5225e6b1SAndroid Build Coastguard Worker androidboot.serialconsole=1
185*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.device=PARTUUID=2b7e273a-42a1-654b-bbad-8cb6ab2b6911
186*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.avb_version=1.1
187*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.device_state=unlocked
188*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.hash_alg=sha256
189*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.size=23040
190*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.digest=6d6cdbad779475dd945ed79e6bd79c0574541d34ff488fa5aeeb024d739dd0d2
191*5225e6b1SAndroid Build Coastguard Worker androidboot.vbmeta.invalidate_on_error=yes
192*5225e6b1SAndroid Build Coastguard Worker androidboot.veritymode=enforcing
193*5225e6b1SAndroid Build Coastguard Worker androidboot.verifiedbootstate=orange
194*5225e6b1SAndroid Build Coastguard Worker ";
195*5225e6b1SAndroid Build Coastguard Worker 
196*5225e6b1SAndroid Build Coastguard Worker     const TEST_CONFIG_TRAILER: &[u8; BOOTCONFIG_TRAILER_SIZE] =
197*5225e6b1SAndroid Build Coastguard Worker         b"i\x07\x00\x00\xf9\xc4\x02\x00#BOOTCONFIG\n";
198*5225e6b1SAndroid Build Coastguard Worker 
199*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add()200*5225e6b1SAndroid Build Coastguard Worker     fn test_add() {
201*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; TEST_CONFIG.len() + TEST_CONFIG_TRAILER.len()];
202*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
203*5225e6b1SAndroid Build Coastguard Worker         builder.add(TEST_CONFIG).unwrap();
204*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
205*5225e6b1SAndroid Build Coastguard Worker             builder.config_bytes().to_vec(),
206*5225e6b1SAndroid Build Coastguard Worker             [TEST_CONFIG.as_bytes(), TEST_CONFIG_TRAILER].concat().to_vec()
207*5225e6b1SAndroid Build Coastguard Worker         );
208*5225e6b1SAndroid Build Coastguard Worker     }
209*5225e6b1SAndroid Build Coastguard Worker 
210*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_incremental()211*5225e6b1SAndroid Build Coastguard Worker     fn test_add_incremental() {
212*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; TEST_CONFIG.len() + TEST_CONFIG_TRAILER.len()];
213*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
214*5225e6b1SAndroid Build Coastguard Worker         for ele in TEST_CONFIG.strip_suffix('\n').unwrap().split('\n') {
215*5225e6b1SAndroid Build Coastguard Worker             let config = std::string::String::from(ele) + "\n";
216*5225e6b1SAndroid Build Coastguard Worker             builder.add(config.as_str()).unwrap();
217*5225e6b1SAndroid Build Coastguard Worker         }
218*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
219*5225e6b1SAndroid Build Coastguard Worker             builder.config_bytes().to_vec(),
220*5225e6b1SAndroid Build Coastguard Worker             [TEST_CONFIG.as_bytes(), TEST_CONFIG_TRAILER].concat().to_vec()
221*5225e6b1SAndroid Build Coastguard Worker         );
222*5225e6b1SAndroid Build Coastguard Worker     }
223*5225e6b1SAndroid Build Coastguard Worker 
224*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_with_incremental()225*5225e6b1SAndroid Build Coastguard Worker     fn test_add_with_incremental() {
226*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; TEST_CONFIG.len() + TEST_CONFIG_TRAILER.len()];
227*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
228*5225e6b1SAndroid Build Coastguard Worker 
229*5225e6b1SAndroid Build Coastguard Worker         let mut offset = 0;
230*5225e6b1SAndroid Build Coastguard Worker         for ele in TEST_CONFIG.strip_suffix('\n').unwrap().split('\n') {
231*5225e6b1SAndroid Build Coastguard Worker             let config = std::string::String::from(ele) + "\n";
232*5225e6b1SAndroid Build Coastguard Worker 
233*5225e6b1SAndroid Build Coastguard Worker             builder
234*5225e6b1SAndroid Build Coastguard Worker                 .add_with(|current, out| {
235*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(current, &TEST_CONFIG.as_bytes()[..offset]);
236*5225e6b1SAndroid Build Coastguard Worker 
237*5225e6b1SAndroid Build Coastguard Worker                     out[..config.len()].copy_from_slice(config.as_bytes());
238*5225e6b1SAndroid Build Coastguard Worker                     Ok(config.len())
239*5225e6b1SAndroid Build Coastguard Worker                 })
240*5225e6b1SAndroid Build Coastguard Worker                 .unwrap();
241*5225e6b1SAndroid Build Coastguard Worker 
242*5225e6b1SAndroid Build Coastguard Worker             offset += config.len();
243*5225e6b1SAndroid Build Coastguard Worker         }
244*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
245*5225e6b1SAndroid Build Coastguard Worker             builder.config_bytes().to_vec(),
246*5225e6b1SAndroid Build Coastguard Worker             [TEST_CONFIG.as_bytes(), TEST_CONFIG_TRAILER].concat().to_vec()
247*5225e6b1SAndroid Build Coastguard Worker         );
248*5225e6b1SAndroid Build Coastguard Worker     }
249*5225e6b1SAndroid Build Coastguard Worker 
250*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_incremental_via_fmt_write()251*5225e6b1SAndroid Build Coastguard Worker     fn test_add_incremental_via_fmt_write() {
252*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; TEST_CONFIG.len() + TEST_CONFIG_TRAILER.len()];
253*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
254*5225e6b1SAndroid Build Coastguard Worker         for ele in TEST_CONFIG.strip_suffix('\n').unwrap().split('\n') {
255*5225e6b1SAndroid Build Coastguard Worker             write!(builder, "{}\n", ele).unwrap();
256*5225e6b1SAndroid Build Coastguard Worker         }
257*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
258*5225e6b1SAndroid Build Coastguard Worker             builder.config_bytes().to_vec(),
259*5225e6b1SAndroid Build Coastguard Worker             [TEST_CONFIG.as_bytes(), TEST_CONFIG_TRAILER].concat().to_vec()
260*5225e6b1SAndroid Build Coastguard Worker         );
261*5225e6b1SAndroid Build Coastguard Worker     }
262*5225e6b1SAndroid Build Coastguard Worker 
263*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_new_buffer_too_small()264*5225e6b1SAndroid Build Coastguard Worker     fn test_new_buffer_too_small() {
265*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; BOOTCONFIG_TRAILER_SIZE - 1];
266*5225e6b1SAndroid Build Coastguard Worker         assert!(BootConfigBuilder::new(&mut buffer[..]).is_err());
267*5225e6b1SAndroid Build Coastguard Worker     }
268*5225e6b1SAndroid Build Coastguard Worker 
269*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_buffer_too_small()270*5225e6b1SAndroid Build Coastguard Worker     fn test_add_buffer_too_small() {
271*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; BOOTCONFIG_TRAILER_SIZE + 1];
272*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
273*5225e6b1SAndroid Build Coastguard Worker         assert!(builder.add("a\n").is_err());
274*5225e6b1SAndroid Build Coastguard Worker     }
275*5225e6b1SAndroid Build Coastguard Worker 
276*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_empty_string()277*5225e6b1SAndroid Build Coastguard Worker     fn test_add_empty_string() {
278*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; BOOTCONFIG_TRAILER_SIZE + 1];
279*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
280*5225e6b1SAndroid Build Coastguard Worker         builder.add("").unwrap();
281*5225e6b1SAndroid Build Coastguard Worker     }
282*5225e6b1SAndroid Build Coastguard Worker 
283*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_add_with_error()284*5225e6b1SAndroid Build Coastguard Worker     fn test_add_with_error() {
285*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = [0u8; BOOTCONFIG_TRAILER_SIZE + 1];
286*5225e6b1SAndroid Build Coastguard Worker         let mut builder = BootConfigBuilder::new(&mut buffer[..]).unwrap();
287*5225e6b1SAndroid Build Coastguard Worker         assert!(builder.add_with(|_, _| Err(Error::Other(None))).is_err());
288*5225e6b1SAndroid Build Coastguard Worker     }
289*5225e6b1SAndroid Build Coastguard Worker }
290