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 extern crate bitflags; 16*5225e6b1SAndroid Build Coastguard Worker extern crate crc32fast; 17*5225e6b1SAndroid Build Coastguard Worker extern crate zerocopy; 18*5225e6b1SAndroid Build Coastguard Worker 19*5225e6b1SAndroid Build Coastguard Worker use super::partition::{MetadataBytes, SlotBlock}; 20*5225e6b1SAndroid Build Coastguard Worker use super::{ 21*5225e6b1SAndroid Build Coastguard Worker BootTarget, BootToken, Bootability, Manager, OneShot, RecoveryTarget, Slot, SlotIterator, 22*5225e6b1SAndroid Build Coastguard Worker Suffix, UnbootableReason, 23*5225e6b1SAndroid Build Coastguard Worker }; 24*5225e6b1SAndroid Build Coastguard Worker use bitflags::bitflags; 25*5225e6b1SAndroid Build Coastguard Worker use core::iter::zip; 26*5225e6b1SAndroid Build Coastguard Worker use core::mem::size_of; 27*5225e6b1SAndroid Build Coastguard Worker use crc32fast::Hasher; 28*5225e6b1SAndroid Build Coastguard Worker use liberror::Error; 29*5225e6b1SAndroid Build Coastguard Worker use zerocopy::byteorder::big_endian::U32 as BigEndianU32; 30*5225e6b1SAndroid Build Coastguard Worker use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref}; 31*5225e6b1SAndroid Build Coastguard Worker 32*5225e6b1SAndroid Build Coastguard Worker const DEFAULT_PRIORITY: u8 = 15; 33*5225e6b1SAndroid Build Coastguard Worker const DEFAULT_RETRIES: u8 = 7; 34*5225e6b1SAndroid Build Coastguard Worker 35*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)] 36*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)] 37*5225e6b1SAndroid Build Coastguard Worker struct AbrSlotData { 38*5225e6b1SAndroid Build Coastguard Worker priority: u8, 39*5225e6b1SAndroid Build Coastguard Worker tries: u8, 40*5225e6b1SAndroid Build Coastguard Worker successful: u8, 41*5225e6b1SAndroid Build Coastguard Worker unbootable_reason: u8, 42*5225e6b1SAndroid Build Coastguard Worker } 43*5225e6b1SAndroid Build Coastguard Worker 44*5225e6b1SAndroid Build Coastguard Worker impl Default for AbrSlotData { default() -> Self45*5225e6b1SAndroid Build Coastguard Worker fn default() -> Self { 46*5225e6b1SAndroid Build Coastguard Worker Self { 47*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY, 48*5225e6b1SAndroid Build Coastguard Worker tries: DEFAULT_RETRIES, 49*5225e6b1SAndroid Build Coastguard Worker successful: 0, 50*5225e6b1SAndroid Build Coastguard Worker unbootable_reason: 0, 51*5225e6b1SAndroid Build Coastguard Worker } 52*5225e6b1SAndroid Build Coastguard Worker } 53*5225e6b1SAndroid Build Coastguard Worker } 54*5225e6b1SAndroid Build Coastguard Worker 55*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)] 56*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)] 57*5225e6b1SAndroid Build Coastguard Worker struct OneShotFlags(u8); 58*5225e6b1SAndroid Build Coastguard Worker 59*5225e6b1SAndroid Build Coastguard Worker bitflags! { 60*5225e6b1SAndroid Build Coastguard Worker impl OneShotFlags: u8 { 61*5225e6b1SAndroid Build Coastguard Worker /// No oneshot specified 62*5225e6b1SAndroid Build Coastguard Worker const NONE = 0; 63*5225e6b1SAndroid Build Coastguard Worker /// Oneshot boot to recovery mode 64*5225e6b1SAndroid Build Coastguard Worker const RECOVERY = 1 << 0; 65*5225e6b1SAndroid Build Coastguard Worker /// Oneshot boot to fastboot 66*5225e6b1SAndroid Build Coastguard Worker const BOOTLOADER = 1 << 1; 67*5225e6b1SAndroid Build Coastguard Worker } 68*5225e6b1SAndroid Build Coastguard Worker } 69*5225e6b1SAndroid Build Coastguard Worker 70*5225e6b1SAndroid Build Coastguard Worker impl From<OneShotFlags> for Option<OneShot> { from(flags: OneShotFlags) -> Self71*5225e6b1SAndroid Build Coastguard Worker fn from(flags: OneShotFlags) -> Self { 72*5225e6b1SAndroid Build Coastguard Worker match flags { 73*5225e6b1SAndroid Build Coastguard Worker OneShotFlags::RECOVERY => Some(OneShot::Continue(RecoveryTarget::Dedicated)), 74*5225e6b1SAndroid Build Coastguard Worker OneShotFlags::BOOTLOADER => Some(OneShot::Bootloader), 75*5225e6b1SAndroid Build Coastguard Worker _ => None, 76*5225e6b1SAndroid Build Coastguard Worker } 77*5225e6b1SAndroid Build Coastguard Worker } 78*5225e6b1SAndroid Build Coastguard Worker } 79*5225e6b1SAndroid Build Coastguard Worker 80*5225e6b1SAndroid Build Coastguard Worker impl From<Option<OneShot>> for OneShotFlags { from(oneshot: Option<OneShot>) -> Self81*5225e6b1SAndroid Build Coastguard Worker fn from(oneshot: Option<OneShot>) -> Self { 82*5225e6b1SAndroid Build Coastguard Worker if let Some(target) = oneshot { 83*5225e6b1SAndroid Build Coastguard Worker match target { 84*5225e6b1SAndroid Build Coastguard Worker OneShot::Bootloader => Self::BOOTLOADER, 85*5225e6b1SAndroid Build Coastguard Worker OneShot::Continue(RecoveryTarget::Dedicated) => Self::RECOVERY, 86*5225e6b1SAndroid Build Coastguard Worker _ => Self::NONE, 87*5225e6b1SAndroid Build Coastguard Worker } 88*5225e6b1SAndroid Build Coastguard Worker } else { 89*5225e6b1SAndroid Build Coastguard Worker Self::NONE 90*5225e6b1SAndroid Build Coastguard Worker } 91*5225e6b1SAndroid Build Coastguard Worker } 92*5225e6b1SAndroid Build Coastguard Worker } 93*5225e6b1SAndroid Build Coastguard Worker 94*5225e6b1SAndroid Build Coastguard Worker const ABR_MAGIC: &[u8; 4] = b"\0AB0"; 95*5225e6b1SAndroid Build Coastguard Worker const ABR_VERSION_MAJOR: u8 = 2; 96*5225e6b1SAndroid Build Coastguard Worker const ABR_VERSION_MINOR: u8 = 3; 97*5225e6b1SAndroid Build Coastguard Worker 98*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)] 99*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)] 100*5225e6b1SAndroid Build Coastguard Worker struct AbrData { 101*5225e6b1SAndroid Build Coastguard Worker magic: [u8; 4], 102*5225e6b1SAndroid Build Coastguard Worker version_major: u8, 103*5225e6b1SAndroid Build Coastguard Worker version_minor: u8, 104*5225e6b1SAndroid Build Coastguard Worker reserved: [u8; 2], 105*5225e6b1SAndroid Build Coastguard Worker slot_data: [AbrSlotData; 2], 106*5225e6b1SAndroid Build Coastguard Worker oneshot_flag: OneShotFlags, 107*5225e6b1SAndroid Build Coastguard Worker reserved2: [u8; 11], 108*5225e6b1SAndroid Build Coastguard Worker crc32: BigEndianU32, 109*5225e6b1SAndroid Build Coastguard Worker } 110*5225e6b1SAndroid Build Coastguard Worker 111*5225e6b1SAndroid Build Coastguard Worker impl AbrData { calculate_crc32(&self) -> u32112*5225e6b1SAndroid Build Coastguard Worker fn calculate_crc32(&self) -> u32 { 113*5225e6b1SAndroid Build Coastguard Worker let mut hasher = Hasher::new(); 114*5225e6b1SAndroid Build Coastguard Worker // Note: core::offset_of isn't stable yet, 115*5225e6b1SAndroid Build Coastguard Worker // and size_of_val isn't permitted on unaligned structs. 116*5225e6b1SAndroid Build Coastguard Worker hasher.update(&self.as_bytes()[..(size_of::<Self>() - size_of::<BigEndianU32>())]); 117*5225e6b1SAndroid Build Coastguard Worker hasher.finalize() 118*5225e6b1SAndroid Build Coastguard Worker } 119*5225e6b1SAndroid Build Coastguard Worker } 120*5225e6b1SAndroid Build Coastguard Worker 121*5225e6b1SAndroid Build Coastguard Worker impl MetadataBytes for AbrData { validate<B: ByteSlice>(buffer: B) -> Result<Ref<B, AbrData>, Error>122*5225e6b1SAndroid Build Coastguard Worker fn validate<B: ByteSlice>(buffer: B) -> Result<Ref<B, AbrData>, Error> { 123*5225e6b1SAndroid Build Coastguard Worker let abr_data = Ref::<B, AbrData>::new_from_prefix(buffer) 124*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::BufferTooSmall(Some(size_of::<AbrData>())))? 125*5225e6b1SAndroid Build Coastguard Worker .0; 126*5225e6b1SAndroid Build Coastguard Worker 127*5225e6b1SAndroid Build Coastguard Worker if abr_data.magic != *ABR_MAGIC { 128*5225e6b1SAndroid Build Coastguard Worker return Err(Error::BadMagic); 129*5225e6b1SAndroid Build Coastguard Worker } 130*5225e6b1SAndroid Build Coastguard Worker if abr_data.version_major > ABR_VERSION_MAJOR { 131*5225e6b1SAndroid Build Coastguard Worker return Err(Error::UnsupportedVersion); 132*5225e6b1SAndroid Build Coastguard Worker } 133*5225e6b1SAndroid Build Coastguard Worker if abr_data.crc32.get() != abr_data.calculate_crc32() { 134*5225e6b1SAndroid Build Coastguard Worker return Err(Error::BadChecksum); 135*5225e6b1SAndroid Build Coastguard Worker } 136*5225e6b1SAndroid Build Coastguard Worker 137*5225e6b1SAndroid Build Coastguard Worker Ok(abr_data) 138*5225e6b1SAndroid Build Coastguard Worker } 139*5225e6b1SAndroid Build Coastguard Worker prepare_for_sync(&mut self)140*5225e6b1SAndroid Build Coastguard Worker fn prepare_for_sync(&mut self) { 141*5225e6b1SAndroid Build Coastguard Worker self.version_minor = ABR_VERSION_MINOR; 142*5225e6b1SAndroid Build Coastguard Worker self.crc32 = self.calculate_crc32().into(); 143*5225e6b1SAndroid Build Coastguard Worker } 144*5225e6b1SAndroid Build Coastguard Worker } 145*5225e6b1SAndroid Build Coastguard Worker 146*5225e6b1SAndroid Build Coastguard Worker impl Default for AbrData { default() -> Self147*5225e6b1SAndroid Build Coastguard Worker fn default() -> Self { 148*5225e6b1SAndroid Build Coastguard Worker let mut data = Self { 149*5225e6b1SAndroid Build Coastguard Worker magic: *ABR_MAGIC, 150*5225e6b1SAndroid Build Coastguard Worker version_major: ABR_VERSION_MAJOR, 151*5225e6b1SAndroid Build Coastguard Worker version_minor: ABR_VERSION_MINOR, 152*5225e6b1SAndroid Build Coastguard Worker reserved: Default::default(), 153*5225e6b1SAndroid Build Coastguard Worker slot_data: Default::default(), 154*5225e6b1SAndroid Build Coastguard Worker oneshot_flag: OneShotFlags::NONE, 155*5225e6b1SAndroid Build Coastguard Worker reserved2: Default::default(), 156*5225e6b1SAndroid Build Coastguard Worker crc32: BigEndianU32::ZERO, 157*5225e6b1SAndroid Build Coastguard Worker }; 158*5225e6b1SAndroid Build Coastguard Worker data.crc32.set(data.calculate_crc32()); 159*5225e6b1SAndroid Build Coastguard Worker data 160*5225e6b1SAndroid Build Coastguard Worker } 161*5225e6b1SAndroid Build Coastguard Worker } 162*5225e6b1SAndroid Build Coastguard Worker 163*5225e6b1SAndroid Build Coastguard Worker impl super::private::SlotGet for SlotBlock<AbrData> { get_slot_by_number(&self, number: usize) -> Result<Slot, Error>164*5225e6b1SAndroid Build Coastguard Worker fn get_slot_by_number(&self, number: usize) -> Result<Slot, Error> { 165*5225e6b1SAndroid Build Coastguard Worker let lower_ascii_suffixes = ('a'..='z').map(Suffix); 166*5225e6b1SAndroid Build Coastguard Worker let (suffix, &abr_slot) = zip(lower_ascii_suffixes, self.get_data().slot_data.iter()) 167*5225e6b1SAndroid Build Coastguard Worker .nth(number) 168*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::BadIndex(number))?; 169*5225e6b1SAndroid Build Coastguard Worker 170*5225e6b1SAndroid Build Coastguard Worker let bootability = match (abr_slot.successful, abr_slot.tries) { 171*5225e6b1SAndroid Build Coastguard Worker (s, _) if s != 0 => Bootability::Successful, 172*5225e6b1SAndroid Build Coastguard Worker (0, t) if t > 0 => Bootability::Retriable(t.into()), 173*5225e6b1SAndroid Build Coastguard Worker (_, _) => Bootability::Unbootable(abr_slot.unbootable_reason.into()), 174*5225e6b1SAndroid Build Coastguard Worker }; 175*5225e6b1SAndroid Build Coastguard Worker 176*5225e6b1SAndroid Build Coastguard Worker Ok(Slot { suffix, priority: abr_slot.priority.into(), bootability }) 177*5225e6b1SAndroid Build Coastguard Worker } 178*5225e6b1SAndroid Build Coastguard Worker } 179*5225e6b1SAndroid Build Coastguard Worker 180*5225e6b1SAndroid Build Coastguard Worker impl Manager for SlotBlock<AbrData> { get_boot_target(&self) -> Result<BootTarget, Error>181*5225e6b1SAndroid Build Coastguard Worker fn get_boot_target(&self) -> Result<BootTarget, Error> { 182*5225e6b1SAndroid Build Coastguard Worker Ok(self 183*5225e6b1SAndroid Build Coastguard Worker .slots_iter() 184*5225e6b1SAndroid Build Coastguard Worker .filter(Slot::is_bootable) 185*5225e6b1SAndroid Build Coastguard Worker .max_by_key(|slot| (slot.priority, slot.suffix.rank())) 186*5225e6b1SAndroid Build Coastguard Worker .map_or(BootTarget::Recovery(RecoveryTarget::Dedicated), BootTarget::NormalBoot)) 187*5225e6b1SAndroid Build Coastguard Worker } 188*5225e6b1SAndroid Build Coastguard Worker slots_iter(&self) -> SlotIterator189*5225e6b1SAndroid Build Coastguard Worker fn slots_iter(&self) -> SlotIterator { 190*5225e6b1SAndroid Build Coastguard Worker SlotIterator::new(self) 191*5225e6b1SAndroid Build Coastguard Worker } 192*5225e6b1SAndroid Build Coastguard Worker set_slot_unbootable( &mut self, slot_suffix: Suffix, reason: UnbootableReason, ) -> Result<(), Error>193*5225e6b1SAndroid Build Coastguard Worker fn set_slot_unbootable( 194*5225e6b1SAndroid Build Coastguard Worker &mut self, 195*5225e6b1SAndroid Build Coastguard Worker slot_suffix: Suffix, 196*5225e6b1SAndroid Build Coastguard Worker reason: UnbootableReason, 197*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error> { 198*5225e6b1SAndroid Build Coastguard Worker let (idx, slot) = self.get_index_and_slot_with_suffix(slot_suffix)?; 199*5225e6b1SAndroid Build Coastguard Worker if slot.bootability == Bootability::Unbootable(reason) { 200*5225e6b1SAndroid Build Coastguard Worker return Ok(()); 201*5225e6b1SAndroid Build Coastguard Worker } 202*5225e6b1SAndroid Build Coastguard Worker 203*5225e6b1SAndroid Build Coastguard Worker let abr_data = self.get_mut_data(); 204*5225e6b1SAndroid Build Coastguard Worker let slot_data = &mut abr_data.slot_data[idx]; 205*5225e6b1SAndroid Build Coastguard Worker slot_data.unbootable_reason = reason.into(); 206*5225e6b1SAndroid Build Coastguard Worker slot_data.tries = 0; 207*5225e6b1SAndroid Build Coastguard Worker slot_data.successful = 0; 208*5225e6b1SAndroid Build Coastguard Worker 209*5225e6b1SAndroid Build Coastguard Worker Ok(()) 210*5225e6b1SAndroid Build Coastguard Worker } 211*5225e6b1SAndroid Build Coastguard Worker mark_boot_attempt(&mut self) -> Result<BootToken, Error>212*5225e6b1SAndroid Build Coastguard Worker fn mark_boot_attempt(&mut self) -> Result<BootToken, Error> { 213*5225e6b1SAndroid Build Coastguard Worker let target = if let Some(OneShot::Continue(r)) = self.get_oneshot_status() { 214*5225e6b1SAndroid Build Coastguard Worker BootTarget::Recovery(r) 215*5225e6b1SAndroid Build Coastguard Worker } else { 216*5225e6b1SAndroid Build Coastguard Worker self.get_boot_target()? 217*5225e6b1SAndroid Build Coastguard Worker }; 218*5225e6b1SAndroid Build Coastguard Worker let target_slot = match target { 219*5225e6b1SAndroid Build Coastguard Worker BootTarget::NormalBoot(slot) => slot, 220*5225e6b1SAndroid Build Coastguard Worker BootTarget::Recovery(RecoveryTarget::Slotted(_)) => Err(Error::OperationProhibited)?, 221*5225e6b1SAndroid Build Coastguard Worker BootTarget::Recovery(RecoveryTarget::Dedicated) => { 222*5225e6b1SAndroid Build Coastguard Worker // Even though boot to recovery does not cause a metadata update, 223*5225e6b1SAndroid Build Coastguard Worker // we still need to gate access to the boot token. 224*5225e6b1SAndroid Build Coastguard Worker return self.take_boot_token().ok_or(Error::OperationProhibited); 225*5225e6b1SAndroid Build Coastguard Worker } 226*5225e6b1SAndroid Build Coastguard Worker }; 227*5225e6b1SAndroid Build Coastguard Worker 228*5225e6b1SAndroid Build Coastguard Worker let (idx, slot) = self.get_index_and_slot_with_suffix(target_slot.suffix)?; 229*5225e6b1SAndroid Build Coastguard Worker 230*5225e6b1SAndroid Build Coastguard Worker match slot.bootability { 231*5225e6b1SAndroid Build Coastguard Worker Bootability::Unbootable(_) => Err(Error::OperationProhibited), 232*5225e6b1SAndroid Build Coastguard Worker Bootability::Retriable(_) => { 233*5225e6b1SAndroid Build Coastguard Worker let abr_slot = &mut self.get_mut_data().slot_data[idx]; 234*5225e6b1SAndroid Build Coastguard Worker abr_slot.tries -= 1; 235*5225e6b1SAndroid Build Coastguard Worker if abr_slot.tries == 0 { 236*5225e6b1SAndroid Build Coastguard Worker abr_slot.unbootable_reason = UnbootableReason::NoMoreTries.into(); 237*5225e6b1SAndroid Build Coastguard Worker } 238*5225e6b1SAndroid Build Coastguard Worker let token = self.take_boot_token().ok_or(Error::OperationProhibited)?; 239*5225e6b1SAndroid Build Coastguard Worker Ok(token) 240*5225e6b1SAndroid Build Coastguard Worker } 241*5225e6b1SAndroid Build Coastguard Worker Bootability::Successful => { 242*5225e6b1SAndroid Build Coastguard Worker let token = self.take_boot_token().ok_or(Error::OperationProhibited)?; 243*5225e6b1SAndroid Build Coastguard Worker Ok(token) 244*5225e6b1SAndroid Build Coastguard Worker } 245*5225e6b1SAndroid Build Coastguard Worker } 246*5225e6b1SAndroid Build Coastguard Worker } 247*5225e6b1SAndroid Build Coastguard Worker set_active_slot(&mut self, slot_suffix: Suffix) -> Result<(), Error>248*5225e6b1SAndroid Build Coastguard Worker fn set_active_slot(&mut self, slot_suffix: Suffix) -> Result<(), Error> { 249*5225e6b1SAndroid Build Coastguard Worker let (idx, _) = self.get_index_and_slot_with_suffix(slot_suffix)?; 250*5225e6b1SAndroid Build Coastguard Worker 251*5225e6b1SAndroid Build Coastguard Worker let abr_data = self.get_mut_data(); 252*5225e6b1SAndroid Build Coastguard Worker for (i, slot) in abr_data.slot_data.iter_mut().enumerate() { 253*5225e6b1SAndroid Build Coastguard Worker if i == idx { 254*5225e6b1SAndroid Build Coastguard Worker *slot = Default::default(); 255*5225e6b1SAndroid Build Coastguard Worker } else { 256*5225e6b1SAndroid Build Coastguard Worker slot.priority = DEFAULT_PRIORITY - 1; 257*5225e6b1SAndroid Build Coastguard Worker } 258*5225e6b1SAndroid Build Coastguard Worker } 259*5225e6b1SAndroid Build Coastguard Worker Ok(()) 260*5225e6b1SAndroid Build Coastguard Worker } 261*5225e6b1SAndroid Build Coastguard Worker get_oneshot_status(&self) -> Option<OneShot>262*5225e6b1SAndroid Build Coastguard Worker fn get_oneshot_status(&self) -> Option<OneShot> { 263*5225e6b1SAndroid Build Coastguard Worker self.get_data().oneshot_flag.into() 264*5225e6b1SAndroid Build Coastguard Worker } 265*5225e6b1SAndroid Build Coastguard Worker set_oneshot_status(&mut self, oneshot: OneShot) -> Result<(), Error>266*5225e6b1SAndroid Build Coastguard Worker fn set_oneshot_status(&mut self, oneshot: OneShot) -> Result<(), Error> { 267*5225e6b1SAndroid Build Coastguard Worker if Some(oneshot) == self.get_oneshot_status() { 268*5225e6b1SAndroid Build Coastguard Worker return Ok(()); 269*5225e6b1SAndroid Build Coastguard Worker } 270*5225e6b1SAndroid Build Coastguard Worker 271*5225e6b1SAndroid Build Coastguard Worker let oneshot_flag = OneShotFlags::from(Some(oneshot)); 272*5225e6b1SAndroid Build Coastguard Worker if oneshot_flag == OneShotFlags::NONE { 273*5225e6b1SAndroid Build Coastguard Worker Err(Error::OperationProhibited) 274*5225e6b1SAndroid Build Coastguard Worker } else { 275*5225e6b1SAndroid Build Coastguard Worker self.get_mut_data().oneshot_flag = oneshot_flag; 276*5225e6b1SAndroid Build Coastguard Worker Ok(()) 277*5225e6b1SAndroid Build Coastguard Worker } 278*5225e6b1SAndroid Build Coastguard Worker } 279*5225e6b1SAndroid Build Coastguard Worker clear_oneshot_status(&mut self)280*5225e6b1SAndroid Build Coastguard Worker fn clear_oneshot_status(&mut self) { 281*5225e6b1SAndroid Build Coastguard Worker if self.get_oneshot_status().is_some() { 282*5225e6b1SAndroid Build Coastguard Worker self.get_mut_data().oneshot_flag = OneShotFlags::NONE; 283*5225e6b1SAndroid Build Coastguard Worker } 284*5225e6b1SAndroid Build Coastguard Worker } 285*5225e6b1SAndroid Build Coastguard Worker write_back(&mut self, persist: &mut dyn FnMut(&mut [u8]) -> Result<(), Error>)286*5225e6b1SAndroid Build Coastguard Worker fn write_back(&mut self, persist: &mut dyn FnMut(&mut [u8]) -> Result<(), Error>) { 287*5225e6b1SAndroid Build Coastguard Worker self.sync_to_disk(persist); 288*5225e6b1SAndroid Build Coastguard Worker } 289*5225e6b1SAndroid Build Coastguard Worker } 290*5225e6b1SAndroid Build Coastguard Worker 291*5225e6b1SAndroid Build Coastguard Worker impl<'a> SlotBlock<AbrData> { get_index_and_slot_with_suffix(&self, slot_suffix: Suffix) -> Result<(usize, Slot), Error>292*5225e6b1SAndroid Build Coastguard Worker fn get_index_and_slot_with_suffix(&self, slot_suffix: Suffix) -> Result<(usize, Slot), Error> { 293*5225e6b1SAndroid Build Coastguard Worker self.slots_iter() 294*5225e6b1SAndroid Build Coastguard Worker .enumerate() 295*5225e6b1SAndroid Build Coastguard Worker .find(|(_, s)| s.suffix == slot_suffix) 296*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::InvalidInput) 297*5225e6b1SAndroid Build Coastguard Worker } 298*5225e6b1SAndroid Build Coastguard Worker } 299*5225e6b1SAndroid Build Coastguard Worker 300*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)] 301*5225e6b1SAndroid Build Coastguard Worker mod test { 302*5225e6b1SAndroid Build Coastguard Worker use super::*; 303*5225e6b1SAndroid Build Coastguard Worker use crate::slots::{partition::CacheStatus, Cursor}; 304*5225e6b1SAndroid Build Coastguard Worker use gbl_async::block_on; 305*5225e6b1SAndroid Build Coastguard Worker use gbl_storage::{new_gpt_max, Disk, RamBlockIo}; 306*5225e6b1SAndroid Build Coastguard Worker 307*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_defaults()308*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_defaults() { 309*5225e6b1SAndroid Build Coastguard Worker let sb: SlotBlock<AbrData> = Default::default(); 310*5225e6b1SAndroid Build Coastguard Worker let expected: Vec<Slot> = vec![ 311*5225e6b1SAndroid Build Coastguard Worker Slot { 312*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 313*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 314*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable(sb.get_max_retries().unwrap()), 315*5225e6b1SAndroid Build Coastguard Worker }, 316*5225e6b1SAndroid Build Coastguard Worker Slot { 317*5225e6b1SAndroid Build Coastguard Worker suffix: 'b'.into(), 318*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 319*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable(sb.get_max_retries().unwrap()), 320*5225e6b1SAndroid Build Coastguard Worker }, 321*5225e6b1SAndroid Build Coastguard Worker ]; 322*5225e6b1SAndroid Build Coastguard Worker let actual: Vec<Slot> = sb.slots_iter().collect(); 323*5225e6b1SAndroid Build Coastguard Worker assert_eq!(actual, expected); 324*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_oneshot_status(), None); 325*5225e6b1SAndroid Build Coastguard Worker } 326*5225e6b1SAndroid Build Coastguard Worker 327*5225e6b1SAndroid Build Coastguard Worker #[test] test_suffix()328*5225e6b1SAndroid Build Coastguard Worker fn test_suffix() { 329*5225e6b1SAndroid Build Coastguard Worker let slot = Slot { suffix: 'a'.into(), ..Default::default() }; 330*5225e6b1SAndroid Build Coastguard Worker assert_eq!(BootTarget::Recovery(RecoveryTarget::Dedicated).suffix(), 'r'.into()); 331*5225e6b1SAndroid Build Coastguard Worker assert_eq!(BootTarget::Recovery(RecoveryTarget::Slotted(slot)).suffix(), slot.suffix); 332*5225e6b1SAndroid Build Coastguard Worker assert_eq!(BootTarget::NormalBoot(slot).suffix(), slot.suffix); 333*5225e6b1SAndroid Build Coastguard Worker } 334*5225e6b1SAndroid Build Coastguard Worker 335*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_parse()336*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_parse() { 337*5225e6b1SAndroid Build Coastguard Worker let abr: AbrData = Default::default(); 338*5225e6b1SAndroid Build Coastguard Worker assert_eq!(AbrData::validate(abr.as_bytes()), Ok(Ref::new(abr.as_bytes()).unwrap())); 339*5225e6b1SAndroid Build Coastguard Worker } 340*5225e6b1SAndroid Build Coastguard Worker 341*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_parse_buffer_too_small()342*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_parse_buffer_too_small() { 343*5225e6b1SAndroid Build Coastguard Worker let buffer: [u8; 0] = Default::default(); 344*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 345*5225e6b1SAndroid Build Coastguard Worker AbrData::validate(&buffer[..]), 346*5225e6b1SAndroid Build Coastguard Worker Err(Error::BufferTooSmall(Some(size_of::<AbrData>()))), 347*5225e6b1SAndroid Build Coastguard Worker ); 348*5225e6b1SAndroid Build Coastguard Worker } 349*5225e6b1SAndroid Build Coastguard Worker 350*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_parse_bad_magic()351*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_parse_bad_magic() { 352*5225e6b1SAndroid Build Coastguard Worker let mut abr: AbrData = Default::default(); 353*5225e6b1SAndroid Build Coastguard Worker abr.magic[0] += 1; 354*5225e6b1SAndroid Build Coastguard Worker assert_eq!(AbrData::validate(abr.as_bytes()), Err(Error::BadMagic)); 355*5225e6b1SAndroid Build Coastguard Worker } 356*5225e6b1SAndroid Build Coastguard Worker 357*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_parse_bad_version_major()358*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_parse_bad_version_major() { 359*5225e6b1SAndroid Build Coastguard Worker let mut abr: AbrData = Default::default(); 360*5225e6b1SAndroid Build Coastguard Worker abr.version_major = 15; 361*5225e6b1SAndroid Build Coastguard Worker assert_eq!(AbrData::validate(abr.as_bytes()), Err(Error::UnsupportedVersion)); 362*5225e6b1SAndroid Build Coastguard Worker } 363*5225e6b1SAndroid Build Coastguard Worker 364*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_block_parse_bad_crc()365*5225e6b1SAndroid Build Coastguard Worker fn test_slot_block_parse_bad_crc() { 366*5225e6b1SAndroid Build Coastguard Worker let mut abr: AbrData = Default::default(); 367*5225e6b1SAndroid Build Coastguard Worker let bad_crc = abr.crc32.get() ^ BigEndianU32::MAX_VALUE.get(); 368*5225e6b1SAndroid Build Coastguard Worker abr.crc32 = bad_crc.into(); 369*5225e6b1SAndroid Build Coastguard Worker assert_eq!(AbrData::validate(abr.as_bytes()), Err(Error::BadChecksum)); 370*5225e6b1SAndroid Build Coastguard Worker } 371*5225e6b1SAndroid Build Coastguard Worker 372*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_boot_attempt()373*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_boot_attempt() { 374*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 375*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 376*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 377*5225e6b1SAndroid Build Coastguard Worker sb.slots_iter().next().unwrap(), 378*5225e6b1SAndroid Build Coastguard Worker Slot { 379*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 380*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 381*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable((DEFAULT_RETRIES - 1).into()) 382*5225e6b1SAndroid Build Coastguard Worker } 383*5225e6b1SAndroid Build Coastguard Worker ); 384*5225e6b1SAndroid Build Coastguard Worker 385*5225e6b1SAndroid Build Coastguard Worker // Make sure we can call exactly once 386*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Err(Error::OperationProhibited)); 387*5225e6b1SAndroid Build Coastguard Worker } 388*5225e6b1SAndroid Build Coastguard Worker 389*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_boot_attempt_tracks_active()390*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_boot_attempt_tracks_active() { 391*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 392*5225e6b1SAndroid Build Coastguard Worker assert!(sb.set_active_slot('b'.into()).is_ok()); 393*5225e6b1SAndroid Build Coastguard Worker 394*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 395*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 396*5225e6b1SAndroid Build Coastguard Worker sb.get_boot_target().unwrap(), 397*5225e6b1SAndroid Build Coastguard Worker BootTarget::NormalBoot(Slot { 398*5225e6b1SAndroid Build Coastguard Worker suffix: 'b'.into(), 399*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 400*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable((DEFAULT_RETRIES - 1).into()) 401*5225e6b1SAndroid Build Coastguard Worker }) 402*5225e6b1SAndroid Build Coastguard Worker ); 403*5225e6b1SAndroid Build Coastguard Worker } 404*5225e6b1SAndroid Build Coastguard Worker 405*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_boot_attempt_no_more_tries()406*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_boot_attempt_no_more_tries() { 407*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 408*5225e6b1SAndroid Build Coastguard Worker sb.get_mut_data().slot_data[0].tries = 1; 409*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 410*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 411*5225e6b1SAndroid Build Coastguard Worker sb.slots_iter().next().unwrap(), 412*5225e6b1SAndroid Build Coastguard Worker Slot { 413*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 414*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 415*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Unbootable(UnbootableReason::NoMoreTries) 416*5225e6b1SAndroid Build Coastguard Worker } 417*5225e6b1SAndroid Build Coastguard Worker ); 418*5225e6b1SAndroid Build Coastguard Worker } 419*5225e6b1SAndroid Build Coastguard Worker 420*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_boot_attempt_successful()421*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_boot_attempt_successful() { 422*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 423*5225e6b1SAndroid Build Coastguard Worker sb.get_mut_data().slot_data[0].successful = 1; 424*5225e6b1SAndroid Build Coastguard Worker let target = BootTarget::NormalBoot(Slot { 425*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 426*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 427*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Successful, 428*5225e6b1SAndroid Build Coastguard Worker }); 429*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 430*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target().unwrap(), target); 431*5225e6b1SAndroid Build Coastguard Worker } 432*5225e6b1SAndroid Build Coastguard Worker 433*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_tried_recovery()434*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_tried_recovery() { 435*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 436*5225e6b1SAndroid Build Coastguard Worker assert!(sb.set_slot_unbootable('a'.into(), UnbootableReason::UserRequested).is_ok()); 437*5225e6b1SAndroid Build Coastguard Worker assert!(sb.set_slot_unbootable('b'.into(), UnbootableReason::UserRequested).is_ok()); 438*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 439*5225e6b1SAndroid Build Coastguard Worker 440*5225e6b1SAndroid Build Coastguard Worker // Make sure a second attempt fails due to the moved boot token 441*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Err(Error::OperationProhibited)); 442*5225e6b1SAndroid Build Coastguard Worker } 443*5225e6b1SAndroid Build Coastguard Worker 444*5225e6b1SAndroid Build Coastguard Worker #[test] test_slot_mark_tried_recovery_oneshot()445*5225e6b1SAndroid Build Coastguard Worker fn test_slot_mark_tried_recovery_oneshot() { 446*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 447*5225e6b1SAndroid Build Coastguard Worker let tgt = sb.get_boot_target(); 448*5225e6b1SAndroid Build Coastguard Worker assert!(sb.set_oneshot_status(OneShot::Continue(RecoveryTarget::Dedicated)).is_ok()); 449*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.mark_boot_attempt(), Ok(BootToken(()))); 450*5225e6b1SAndroid Build Coastguard Worker 451*5225e6b1SAndroid Build Coastguard Worker // Verify that tries weren't decremented 452*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target(), tgt); 453*5225e6b1SAndroid Build Coastguard Worker } 454*5225e6b1SAndroid Build Coastguard Worker 455*5225e6b1SAndroid Build Coastguard Worker macro_rules! set_unbootable_tests { 456*5225e6b1SAndroid Build Coastguard Worker ($($name:ident: $value:expr,)*) => { 457*5225e6b1SAndroid Build Coastguard Worker $( 458*5225e6b1SAndroid Build Coastguard Worker #[test] 459*5225e6b1SAndroid Build Coastguard Worker fn $name() { 460*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 461*5225e6b1SAndroid Build Coastguard Worker let suffix: Suffix = 'a'.into(); 462*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_slot_unbootable(suffix, $value), Ok(())); 463*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.slots_iter() 464*5225e6b1SAndroid Build Coastguard Worker .find(|s| s.suffix == suffix) 465*5225e6b1SAndroid Build Coastguard Worker .unwrap() 466*5225e6b1SAndroid Build Coastguard Worker .bootability, 467*5225e6b1SAndroid Build Coastguard Worker Bootability::Unbootable($value) 468*5225e6b1SAndroid Build Coastguard Worker ); 469*5225e6b1SAndroid Build Coastguard Worker } 470*5225e6b1SAndroid Build Coastguard Worker )* 471*5225e6b1SAndroid Build Coastguard Worker } 472*5225e6b1SAndroid Build Coastguard Worker } 473*5225e6b1SAndroid Build Coastguard Worker 474*5225e6b1SAndroid Build Coastguard Worker use UnbootableReason::*; 475*5225e6b1SAndroid Build Coastguard Worker set_unbootable_tests! { 476*5225e6b1SAndroid Build Coastguard Worker test_set_unbootable_no_more_tries: NoMoreTries, 477*5225e6b1SAndroid Build Coastguard Worker test_set_unbootable_system_update: SystemUpdate, 478*5225e6b1SAndroid Build Coastguard Worker test_set_unbootable_user_requested: UserRequested, 479*5225e6b1SAndroid Build Coastguard Worker test_set_unbootable_verification_failure: VerificationFailure, 480*5225e6b1SAndroid Build Coastguard Worker test_set_unbootable_unknown: Unknown, 481*5225e6b1SAndroid Build Coastguard Worker } 482*5225e6b1SAndroid Build Coastguard Worker 483*5225e6b1SAndroid Build Coastguard Worker #[test] test_no_bootable_slots_boot_recovery()484*5225e6b1SAndroid Build Coastguard Worker fn test_no_bootable_slots_boot_recovery() { 485*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 486*5225e6b1SAndroid Build Coastguard Worker let v: Vec<Slot> = sb.slots_iter().collect(); 487*5225e6b1SAndroid Build Coastguard Worker for slot in v { 488*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 489*5225e6b1SAndroid Build Coastguard Worker sb.set_slot_unbootable(slot.suffix, UnbootableReason::UserRequested), 490*5225e6b1SAndroid Build Coastguard Worker Ok(()) 491*5225e6b1SAndroid Build Coastguard Worker ); 492*5225e6b1SAndroid Build Coastguard Worker } 493*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target().unwrap(), BootTarget::Recovery(RecoveryTarget::Dedicated)); 494*5225e6b1SAndroid Build Coastguard Worker } 495*5225e6b1SAndroid Build Coastguard Worker 496*5225e6b1SAndroid Build Coastguard Worker #[test] test_set_active_slot()497*5225e6b1SAndroid Build Coastguard Worker fn test_set_active_slot() { 498*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 499*5225e6b1SAndroid Build Coastguard Worker let v: Vec<Slot> = sb.slots_iter().collect(); 500*5225e6b1SAndroid Build Coastguard Worker 501*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target().unwrap(), BootTarget::NormalBoot(v[0])); 502*5225e6b1SAndroid Build Coastguard Worker for slot in v.iter() { 503*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_active_slot(slot.suffix), Ok(())); 504*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target().unwrap(), BootTarget::NormalBoot(*slot)); 505*5225e6b1SAndroid Build Coastguard Worker } 506*5225e6b1SAndroid Build Coastguard Worker } 507*5225e6b1SAndroid Build Coastguard Worker 508*5225e6b1SAndroid Build Coastguard Worker #[test] test_set_active_slot_no_such_slot()509*5225e6b1SAndroid Build Coastguard Worker fn test_set_active_slot_no_such_slot() { 510*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 511*5225e6b1SAndroid Build Coastguard Worker let bad_suffix: Suffix = '$'.into(); 512*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_active_slot(bad_suffix), Err(Error::InvalidInput)); 513*5225e6b1SAndroid Build Coastguard Worker } 514*5225e6b1SAndroid Build Coastguard Worker 515*5225e6b1SAndroid Build Coastguard Worker #[test] test_get_slot_last_set_active()516*5225e6b1SAndroid Build Coastguard Worker fn test_get_slot_last_set_active() { 517*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 518*5225e6b1SAndroid Build Coastguard Worker let v: Vec<Slot> = sb.slots_iter().collect(); 519*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_active_slot(v[0].suffix), Ok(())); 520*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_slot_last_set_active().unwrap(), v[0]); 521*5225e6b1SAndroid Build Coastguard Worker for slot in v.iter() { 522*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_slot_unbootable(slot.suffix, NoMoreTries), Ok(())); 523*5225e6b1SAndroid Build Coastguard Worker } 524*5225e6b1SAndroid Build Coastguard Worker 525*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_slot_last_set_active().unwrap(), sb.slots_iter().next().unwrap()); 526*5225e6b1SAndroid Build Coastguard Worker } 527*5225e6b1SAndroid Build Coastguard Worker 528*5225e6b1SAndroid Build Coastguard Worker macro_rules! set_oneshot_tests { 529*5225e6b1SAndroid Build Coastguard Worker ($($name:ident: $value:expr,)*) => { 530*5225e6b1SAndroid Build Coastguard Worker $( 531*5225e6b1SAndroid Build Coastguard Worker #[test] 532*5225e6b1SAndroid Build Coastguard Worker fn $name(){ 533*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 534*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_oneshot_status($value), Ok(())); 535*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_oneshot_status(), Some($value)); 536*5225e6b1SAndroid Build Coastguard Worker 537*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_boot_target().unwrap(), 538*5225e6b1SAndroid Build Coastguard Worker BootTarget::NormalBoot( 539*5225e6b1SAndroid Build Coastguard Worker Slot{ 540*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 541*5225e6b1SAndroid Build Coastguard Worker priority: DEFAULT_PRIORITY.into(), 542*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable(sb.get_max_retries().unwrap()), 543*5225e6b1SAndroid Build Coastguard Worker }, 544*5225e6b1SAndroid Build Coastguard Worker )); 545*5225e6b1SAndroid Build Coastguard Worker } 546*5225e6b1SAndroid Build Coastguard Worker )* 547*5225e6b1SAndroid Build Coastguard Worker } 548*5225e6b1SAndroid Build Coastguard Worker } 549*5225e6b1SAndroid Build Coastguard Worker 550*5225e6b1SAndroid Build Coastguard Worker set_oneshot_tests! { 551*5225e6b1SAndroid Build Coastguard Worker test_set_oneshot_bootloader: OneShot::Bootloader, 552*5225e6b1SAndroid Build Coastguard Worker test_set_oneshot_recovery: OneShot::Continue(RecoveryTarget::Dedicated), 553*5225e6b1SAndroid Build Coastguard Worker } 554*5225e6b1SAndroid Build Coastguard Worker 555*5225e6b1SAndroid Build Coastguard Worker #[test] test_clear_oneshot_status()556*5225e6b1SAndroid Build Coastguard Worker fn test_clear_oneshot_status() { 557*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 558*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_oneshot_status(OneShot::Bootloader), Ok(())); 559*5225e6b1SAndroid Build Coastguard Worker sb.clear_oneshot_status(); 560*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.get_oneshot_status(), None); 561*5225e6b1SAndroid Build Coastguard Worker } 562*5225e6b1SAndroid Build Coastguard Worker 563*5225e6b1SAndroid Build Coastguard Worker #[test] test_set_oneshot_mistaken_recovery_slotted()564*5225e6b1SAndroid Build Coastguard Worker fn test_set_oneshot_mistaken_recovery_slotted() { 565*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 566*5225e6b1SAndroid Build Coastguard Worker let slot = sb.slots_iter().next().unwrap(); 567*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 568*5225e6b1SAndroid Build Coastguard Worker sb.set_oneshot_status(OneShot::Continue(RecoveryTarget::Slotted(slot))), 569*5225e6b1SAndroid Build Coastguard Worker Err(Error::OperationProhibited) 570*5225e6b1SAndroid Build Coastguard Worker ); 571*5225e6b1SAndroid Build Coastguard Worker } 572*5225e6b1SAndroid Build Coastguard Worker 573*5225e6b1SAndroid Build Coastguard Worker #[test] test_deserialize_default_to_dirty_cache()574*5225e6b1SAndroid Build Coastguard Worker fn test_deserialize_default_to_dirty_cache() { 575*5225e6b1SAndroid Build Coastguard Worker let mut abr_data: AbrData = Default::default(); 576*5225e6b1SAndroid Build Coastguard Worker // Changing the success both invalidates the crc 577*5225e6b1SAndroid Build Coastguard Worker // and lets us verify that the deserialized slot block 578*5225e6b1SAndroid Build Coastguard Worker // uses defaulted backing bytes instead of the provided bytes. 579*5225e6b1SAndroid Build Coastguard Worker abr_data.slot_data[0].successful = 1; 580*5225e6b1SAndroid Build Coastguard Worker let sb = SlotBlock::<AbrData>::deserialize(abr_data.as_bytes(), BootToken(())); 581*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.cache_status(), CacheStatus::Dirty); 582*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 583*5225e6b1SAndroid Build Coastguard Worker sb.slots_iter().next().unwrap().bootability, 584*5225e6b1SAndroid Build Coastguard Worker Bootability::Retriable(DEFAULT_RETRIES.into()) 585*5225e6b1SAndroid Build Coastguard Worker ); 586*5225e6b1SAndroid Build Coastguard Worker } 587*5225e6b1SAndroid Build Coastguard Worker 588*5225e6b1SAndroid Build Coastguard Worker #[test] test_deserialize_modified_to_clean_cache()589*5225e6b1SAndroid Build Coastguard Worker fn test_deserialize_modified_to_clean_cache() { 590*5225e6b1SAndroid Build Coastguard Worker let mut abr_data: AbrData = Default::default(); 591*5225e6b1SAndroid Build Coastguard Worker abr_data.slot_data[0].successful = 1; 592*5225e6b1SAndroid Build Coastguard Worker // If we recalculate the crc, 593*5225e6b1SAndroid Build Coastguard Worker // that just means we have a metadata block that stores 594*5225e6b1SAndroid Build Coastguard Worker // relevant, non-default information. 595*5225e6b1SAndroid Build Coastguard Worker abr_data.crc32.set(abr_data.calculate_crc32()); 596*5225e6b1SAndroid Build Coastguard Worker let sb = SlotBlock::<AbrData>::deserialize(abr_data.as_bytes(), BootToken(())); 597*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.cache_status(), CacheStatus::Clean); 598*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.slots_iter().next().unwrap().bootability, Bootability::Successful); 599*5225e6b1SAndroid Build Coastguard Worker } 600*5225e6b1SAndroid Build Coastguard Worker 601*5225e6b1SAndroid Build Coastguard Worker type TestDisk = Disk<RamBlockIo<Vec<u8>>, Vec<u8>>; 602*5225e6b1SAndroid Build Coastguard Worker 603*5225e6b1SAndroid Build Coastguard Worker #[test] test_writeback()604*5225e6b1SAndroid Build Coastguard Worker fn test_writeback() { 605*5225e6b1SAndroid Build Coastguard Worker const PARTITION: &str = "test_partition"; 606*5225e6b1SAndroid Build Coastguard Worker const OFFSET: u64 = 2112; // Deliberately wrong to test propagation of parameter. 607*5225e6b1SAndroid Build Coastguard Worker let disk = include_bytes!("../../testdata/writeback_test_disk.bin").to_vec(); 608*5225e6b1SAndroid Build Coastguard Worker let mut blk = TestDisk::new_ram_alloc(512, 512, disk).unwrap(); 609*5225e6b1SAndroid Build Coastguard Worker let mut gpt = new_gpt_max(); 610*5225e6b1SAndroid Build Coastguard Worker block_on(blk.sync_gpt(&mut gpt)).unwrap(); 611*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 612*5225e6b1SAndroid Build Coastguard Worker let mut read_buffer: [u8; size_of::<AbrData>()] = Default::default(); 613*5225e6b1SAndroid Build Coastguard Worker 614*5225e6b1SAndroid Build Coastguard Worker // Clean cache, write_back is a no-op 615*5225e6b1SAndroid Build Coastguard Worker sb.write_back(&mut |data: &mut [u8]| { 616*5225e6b1SAndroid Build Coastguard Worker Ok(block_on(blk.write_gpt_partition(&mut gpt, PARTITION, OFFSET, data))?) 617*5225e6b1SAndroid Build Coastguard Worker }); 618*5225e6b1SAndroid Build Coastguard Worker let res = 619*5225e6b1SAndroid Build Coastguard Worker block_on(blk.read_gpt_partition(&mut gpt, PARTITION, OFFSET, &mut read_buffer[..])); 620*5225e6b1SAndroid Build Coastguard Worker assert!(res.is_ok()); 621*5225e6b1SAndroid Build Coastguard Worker assert_eq!(read_buffer, [0; std::mem::size_of::<AbrData>()]); 622*5225e6b1SAndroid Build Coastguard Worker 623*5225e6b1SAndroid Build Coastguard Worker // Make a change, write_back writes back to the defined partition 624*5225e6b1SAndroid Build Coastguard Worker // at the defined offset. 625*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.set_oneshot_status(OneShot::Bootloader), Ok(())); 626*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.cache_status(), CacheStatus::Dirty); 627*5225e6b1SAndroid Build Coastguard Worker 628*5225e6b1SAndroid Build Coastguard Worker sb.write_back(&mut |data: &mut [u8]| { 629*5225e6b1SAndroid Build Coastguard Worker Ok(block_on(blk.write_gpt_partition(&mut gpt, PARTITION, OFFSET, data))?) 630*5225e6b1SAndroid Build Coastguard Worker }); 631*5225e6b1SAndroid Build Coastguard Worker let res = 632*5225e6b1SAndroid Build Coastguard Worker block_on(blk.read_gpt_partition(&mut gpt, PARTITION, OFFSET, &mut read_buffer[..])); 633*5225e6b1SAndroid Build Coastguard Worker assert!(res.is_ok()); 634*5225e6b1SAndroid Build Coastguard Worker assert_eq!(read_buffer, sb.get_data().as_bytes()); 635*5225e6b1SAndroid Build Coastguard Worker assert_eq!(sb.cache_status(), CacheStatus::Clean); 636*5225e6b1SAndroid Build Coastguard Worker } 637*5225e6b1SAndroid Build Coastguard Worker 638*5225e6b1SAndroid Build Coastguard Worker #[test] test_writeback_with_cursor()639*5225e6b1SAndroid Build Coastguard Worker fn test_writeback_with_cursor() { 640*5225e6b1SAndroid Build Coastguard Worker const PARTITION: &str = "test_partition"; 641*5225e6b1SAndroid Build Coastguard Worker const OFFSET: u64 = 2112; // Deliberately wrong to test propagation of parameter. 642*5225e6b1SAndroid Build Coastguard Worker let disk = include_bytes!("../../testdata/writeback_test_disk.bin").to_vec(); 643*5225e6b1SAndroid Build Coastguard Worker let mut blk = TestDisk::new_ram_alloc(512, 512, disk).unwrap(); 644*5225e6b1SAndroid Build Coastguard Worker let mut gpt = new_gpt_max(); 645*5225e6b1SAndroid Build Coastguard Worker block_on(blk.sync_gpt(&mut gpt)).unwrap(); 646*5225e6b1SAndroid Build Coastguard Worker let mut read_buffer: [u8; size_of::<AbrData>()] = Default::default(); 647*5225e6b1SAndroid Build Coastguard Worker 648*5225e6b1SAndroid Build Coastguard Worker let mut sb: SlotBlock<AbrData> = Default::default(); 649*5225e6b1SAndroid Build Coastguard Worker 650*5225e6b1SAndroid Build Coastguard Worker // New block to trigger drop on the cursor. 651*5225e6b1SAndroid Build Coastguard Worker { 652*5225e6b1SAndroid Build Coastguard Worker let mut persist = |data: &mut [u8]| { 653*5225e6b1SAndroid Build Coastguard Worker Ok(block_on(blk.write_gpt_partition(&mut gpt, PARTITION, OFFSET, data))?) 654*5225e6b1SAndroid Build Coastguard Worker }; 655*5225e6b1SAndroid Build Coastguard Worker let cursor = Cursor { ctx: &mut sb, persist: &mut persist }; 656*5225e6b1SAndroid Build Coastguard Worker assert!(cursor.ctx.set_active_slot('b'.into()).is_ok()); 657*5225e6b1SAndroid Build Coastguard Worker } 658*5225e6b1SAndroid Build Coastguard Worker 659*5225e6b1SAndroid Build Coastguard Worker let res = 660*5225e6b1SAndroid Build Coastguard Worker block_on(blk.read_gpt_partition(&mut gpt, PARTITION, OFFSET, &mut read_buffer[..])); 661*5225e6b1SAndroid Build Coastguard Worker assert!(res.is_ok()); 662*5225e6b1SAndroid Build Coastguard Worker assert_eq!(read_buffer, sb.get_data().as_bytes()); 663*5225e6b1SAndroid Build Coastguard Worker } 664*5225e6b1SAndroid Build Coastguard Worker } 665