1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //! flag value module defines the flag value file format and methods for serialization 18 //! and deserialization 19 20 use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes}; 21 use crate::{AconfigStorageError, StorageFileType}; 22 use anyhow::anyhow; 23 use serde::{Deserialize, Serialize}; 24 use std::fmt; 25 26 /// Flag value header struct 27 #[derive(PartialEq, Serialize, Deserialize)] 28 pub struct FlagValueHeader { 29 pub version: u32, 30 pub container: String, 31 pub file_type: u8, 32 pub file_size: u32, 33 pub num_flags: u32, 34 pub boolean_value_offset: u32, 35 } 36 37 /// Implement debug print trait for header 38 impl fmt::Debug for FlagValueHeader { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 40 writeln!( 41 f, 42 "Version: {}, Container: {}, File Type: {:?}, File Size: {}", 43 self.version, 44 self.container, 45 StorageFileType::try_from(self.file_type), 46 self.file_size 47 )?; 48 writeln!( 49 f, 50 "Num of Flags: {}, Value Offset:{}", 51 self.num_flags, self.boolean_value_offset 52 )?; 53 Ok(()) 54 } 55 } 56 57 impl FlagValueHeader { 58 /// Serialize to bytes into_bytes(&self) -> Vec<u8>59 pub fn into_bytes(&self) -> Vec<u8> { 60 let mut result = Vec::new(); 61 result.extend_from_slice(&self.version.to_le_bytes()); 62 let container_bytes = self.container.as_bytes(); 63 result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes()); 64 result.extend_from_slice(container_bytes); 65 result.extend_from_slice(&self.file_type.to_le_bytes()); 66 result.extend_from_slice(&self.file_size.to_le_bytes()); 67 result.extend_from_slice(&self.num_flags.to_le_bytes()); 68 result.extend_from_slice(&self.boolean_value_offset.to_le_bytes()); 69 result 70 } 71 72 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>73 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 74 let mut head = 0; 75 let list = Self { 76 version: read_u32_from_bytes(bytes, &mut head)?, 77 container: read_str_from_bytes(bytes, &mut head)?, 78 file_type: read_u8_from_bytes(bytes, &mut head)?, 79 file_size: read_u32_from_bytes(bytes, &mut head)?, 80 num_flags: read_u32_from_bytes(bytes, &mut head)?, 81 boolean_value_offset: read_u32_from_bytes(bytes, &mut head)?, 82 }; 83 if list.file_type != StorageFileType::FlagVal as u8 { 84 return Err(AconfigStorageError::BytesParseFail(anyhow!( 85 "binary file is not a flag value file" 86 ))); 87 } 88 Ok(list) 89 } 90 } 91 92 /// Flag value list struct 93 #[derive(PartialEq, Serialize, Deserialize)] 94 pub struct FlagValueList { 95 pub header: FlagValueHeader, 96 pub booleans: Vec<bool>, 97 } 98 99 /// Implement debug print trait for flag value 100 impl fmt::Debug for FlagValueList { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 102 writeln!(f, "Header:")?; 103 write!(f, "{:?}", self.header)?; 104 writeln!(f, "Values:")?; 105 writeln!(f, "{:?}", self.booleans)?; 106 Ok(()) 107 } 108 } 109 110 impl FlagValueList { 111 /// Serialize to bytes into_bytes(&self) -> Vec<u8>112 pub fn into_bytes(&self) -> Vec<u8> { 113 [ 114 self.header.into_bytes(), 115 self.booleans.iter().map(|&v| u8::from(v).to_le_bytes()).collect::<Vec<_>>().concat(), 116 ] 117 .concat() 118 } 119 120 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>121 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 122 let header = FlagValueHeader::from_bytes(bytes)?; 123 let num_flags = header.num_flags; 124 let mut head = header.into_bytes().len(); 125 let booleans = 126 (0..num_flags).map(|_| read_u8_from_bytes(bytes, &mut head).unwrap() == 1).collect(); 127 let list = Self { header, booleans }; 128 Ok(list) 129 } 130 } 131 132 #[cfg(test)] 133 mod tests { 134 use super::*; 135 use crate::{ 136 test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION, 137 }; 138 139 #[test] 140 // this test point locks down the value list serialization 141 // TODO: b/376108268 - Use parameterized tests. test_serialization_default()142 fn test_serialization_default() { 143 let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION); 144 145 let header: &FlagValueHeader = &flag_value_list.header; 146 let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes()); 147 assert!(reinterpreted_header.is_ok()); 148 assert_eq!(header, &reinterpreted_header.unwrap()); 149 150 let flag_value_bytes = flag_value_list.into_bytes(); 151 let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes); 152 assert!(reinterpreted_value_list.is_ok()); 153 assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap()); 154 assert_eq!(flag_value_bytes.len() as u32, header.file_size); 155 } 156 157 #[test] 158 // this test point locks down the value list serialization test_serialization_max()159 fn test_serialization_max() { 160 let flag_value_list = create_test_flag_value_list(MAX_SUPPORTED_FILE_VERSION); 161 162 let header: &FlagValueHeader = &flag_value_list.header; 163 let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes()); 164 assert!(reinterpreted_header.is_ok()); 165 assert_eq!(header, &reinterpreted_header.unwrap()); 166 167 let flag_value_bytes = flag_value_list.into_bytes(); 168 let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes); 169 assert!(reinterpreted_value_list.is_ok()); 170 assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap()); 171 assert_eq!(flag_value_bytes.len() as u32, header.file_size); 172 } 173 174 #[test] 175 // this test point locks down that version number should be at the top of serialized 176 // bytes test_version_number()177 fn test_version_number() { 178 let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION); 179 let bytes = &flag_value_list.into_bytes(); 180 let mut head = 0; 181 let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap(); 182 assert_eq!(version_from_file, DEFAULT_FILE_VERSION); 183 } 184 185 #[test] 186 // this test point locks down file type check test_file_type_check()187 fn test_file_type_check() { 188 let mut flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION); 189 flag_value_list.header.file_type = 123u8; 190 let error = FlagValueList::from_bytes(&flag_value_list.into_bytes()).unwrap_err(); 191 assert_eq!( 192 format!("{:?}", error), 193 format!("BytesParseFail(binary file is not a flag value file)") 194 ); 195 } 196 } 197