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 table module defines the flag table file format and methods for serialization 18 //! and deserialization 19 20 use crate::{ 21 get_bucket_index, read_str_from_bytes, read_u16_from_bytes, read_u32_from_bytes, 22 read_u8_from_bytes, 23 }; 24 use crate::{AconfigStorageError, StorageFileType, StoredFlagType}; 25 use anyhow::anyhow; 26 use serde::{Deserialize, Serialize}; 27 use std::fmt; 28 29 /// Flag table header struct 30 #[derive(PartialEq, Serialize, Deserialize)] 31 pub struct FlagTableHeader { 32 pub version: u32, 33 pub container: String, 34 pub file_type: u8, 35 pub file_size: u32, 36 pub num_flags: u32, 37 pub bucket_offset: u32, 38 pub node_offset: u32, 39 } 40 41 /// Implement debug print trait for header 42 impl fmt::Debug for FlagTableHeader { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 writeln!( 45 f, 46 "Version: {}, Container: {}, File Type: {:?}, File Size: {}", 47 self.version, 48 self.container, 49 StorageFileType::try_from(self.file_type), 50 self.file_size 51 )?; 52 writeln!( 53 f, 54 "Num of Flags: {}, Bucket Offset:{}, Node Offset: {}", 55 self.num_flags, self.bucket_offset, self.node_offset 56 )?; 57 Ok(()) 58 } 59 } 60 61 impl FlagTableHeader { 62 /// Serialize to bytes into_bytes(&self) -> Vec<u8>63 pub fn into_bytes(&self) -> Vec<u8> { 64 let mut result = Vec::new(); 65 result.extend_from_slice(&self.version.to_le_bytes()); 66 let container_bytes = self.container.as_bytes(); 67 result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes()); 68 result.extend_from_slice(container_bytes); 69 result.extend_from_slice(&self.file_type.to_le_bytes()); 70 result.extend_from_slice(&self.file_size.to_le_bytes()); 71 result.extend_from_slice(&self.num_flags.to_le_bytes()); 72 result.extend_from_slice(&self.bucket_offset.to_le_bytes()); 73 result.extend_from_slice(&self.node_offset.to_le_bytes()); 74 result 75 } 76 77 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>78 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 79 let mut head = 0; 80 let table = Self { 81 version: read_u32_from_bytes(bytes, &mut head)?, 82 container: read_str_from_bytes(bytes, &mut head)?, 83 file_type: read_u8_from_bytes(bytes, &mut head)?, 84 file_size: read_u32_from_bytes(bytes, &mut head)?, 85 num_flags: read_u32_from_bytes(bytes, &mut head)?, 86 bucket_offset: read_u32_from_bytes(bytes, &mut head)?, 87 node_offset: read_u32_from_bytes(bytes, &mut head)?, 88 }; 89 if table.file_type != StorageFileType::FlagMap as u8 { 90 return Err(AconfigStorageError::BytesParseFail(anyhow!( 91 "binary file is not a flag map" 92 ))); 93 } 94 Ok(table) 95 } 96 } 97 98 /// Flag table node struct 99 #[derive(PartialEq, Clone, Serialize, Deserialize)] 100 pub struct FlagTableNode { 101 pub package_id: u32, 102 pub flag_name: String, 103 pub flag_type: StoredFlagType, 104 // within package flag index of this flag type 105 pub flag_index: u16, 106 pub next_offset: Option<u32>, 107 } 108 109 /// Implement debug print trait for node 110 impl fmt::Debug for FlagTableNode { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 112 writeln!( 113 f, 114 "Package Id: {}, Flag: {}, Type: {:?}, Index: {}, Next: {:?}", 115 self.package_id, self.flag_name, self.flag_type, self.flag_index, self.next_offset 116 )?; 117 Ok(()) 118 } 119 } 120 121 impl FlagTableNode { 122 /// Serialize to bytes into_bytes(&self) -> Vec<u8>123 pub fn into_bytes(&self) -> Vec<u8> { 124 let mut result = Vec::new(); 125 result.extend_from_slice(&self.package_id.to_le_bytes()); 126 let name_bytes = self.flag_name.as_bytes(); 127 result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes()); 128 result.extend_from_slice(name_bytes); 129 result.extend_from_slice(&(self.flag_type as u16).to_le_bytes()); 130 result.extend_from_slice(&self.flag_index.to_le_bytes()); 131 result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes()); 132 result 133 } 134 135 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>136 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 137 let mut head = 0; 138 let node = Self { 139 package_id: read_u32_from_bytes(bytes, &mut head)?, 140 flag_name: read_str_from_bytes(bytes, &mut head)?, 141 flag_type: StoredFlagType::try_from(read_u16_from_bytes(bytes, &mut head)?)?, 142 flag_index: read_u16_from_bytes(bytes, &mut head)?, 143 next_offset: match read_u32_from_bytes(bytes, &mut head)? { 144 0 => None, 145 val => Some(val), 146 }, 147 }; 148 Ok(node) 149 } 150 151 /// Calculate node bucket index find_bucket_index(package_id: u32, flag_name: &str, num_buckets: u32) -> u32152 pub fn find_bucket_index(package_id: u32, flag_name: &str, num_buckets: u32) -> u32 { 153 let full_flag_name = package_id.to_string() + "/" + flag_name; 154 get_bucket_index(full_flag_name.as_bytes(), num_buckets) 155 } 156 } 157 158 #[derive(PartialEq, Serialize, Deserialize)] 159 pub struct FlagTable { 160 pub header: FlagTableHeader, 161 pub buckets: Vec<Option<u32>>, 162 pub nodes: Vec<FlagTableNode>, 163 } 164 165 /// Implement debug print trait for flag table 166 impl fmt::Debug for FlagTable { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 168 writeln!(f, "Header:")?; 169 write!(f, "{:?}", self.header)?; 170 writeln!(f, "Buckets:")?; 171 writeln!(f, "{:?}", self.buckets)?; 172 writeln!(f, "Nodes:")?; 173 for node in self.nodes.iter() { 174 write!(f, "{:?}", node)?; 175 } 176 Ok(()) 177 } 178 } 179 180 /// Flag table struct 181 impl FlagTable { 182 /// Serialize to bytes into_bytes(&self) -> Vec<u8>183 pub fn into_bytes(&self) -> Vec<u8> { 184 [ 185 self.header.into_bytes(), 186 self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(), 187 self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(), 188 ] 189 .concat() 190 } 191 192 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>193 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 194 let header = FlagTableHeader::from_bytes(bytes)?; 195 let num_flags = header.num_flags; 196 let num_buckets = crate::get_table_size(num_flags)?; 197 let mut head = header.into_bytes().len(); 198 let buckets = (0..num_buckets) 199 .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() { 200 0 => None, 201 val => Some(val), 202 }) 203 .collect(); 204 let nodes = (0..num_flags) 205 .map(|_| { 206 let node = FlagTableNode::from_bytes(&bytes[head..])?; 207 head += node.into_bytes().len(); 208 Ok(node) 209 }) 210 .collect::<Result<Vec<_>, AconfigStorageError>>() 211 .map_err(|errmsg| { 212 AconfigStorageError::BytesParseFail(anyhow!("fail to parse flag table: {}", errmsg)) 213 })?; 214 215 let table = Self { header, buckets, nodes }; 216 Ok(table) 217 } 218 } 219 220 #[cfg(test)] 221 mod tests { 222 use super::*; 223 use crate::{ 224 test_utils::create_test_flag_table, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION, 225 }; 226 227 // this test point locks down the table serialization 228 #[test] test_serialization()229 fn test_serialization() { 230 for file_version in 1..=MAX_SUPPORTED_FILE_VERSION { 231 let flag_table = create_test_flag_table(file_version); 232 233 let header: &FlagTableHeader = &flag_table.header; 234 let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes()); 235 assert!(reinterpreted_header.is_ok()); 236 assert_eq!(header, &reinterpreted_header.unwrap()); 237 238 let nodes: &Vec<FlagTableNode> = &flag_table.nodes; 239 for node in nodes.iter() { 240 let reinterpreted_node = FlagTableNode::from_bytes(&node.into_bytes()).unwrap(); 241 assert_eq!(node, &reinterpreted_node); 242 } 243 244 let flag_table_bytes = flag_table.into_bytes(); 245 let reinterpreted_table = FlagTable::from_bytes(&flag_table_bytes); 246 assert!(reinterpreted_table.is_ok()); 247 assert_eq!(&flag_table, &reinterpreted_table.unwrap()); 248 assert_eq!(flag_table_bytes.len() as u32, header.file_size); 249 } 250 } 251 252 // this test point locks down that version number should be at the top of serialized 253 // bytes 254 #[test] test_version_number()255 fn test_version_number() { 256 let flag_table = create_test_flag_table(DEFAULT_FILE_VERSION); 257 let bytes = &flag_table.into_bytes(); 258 let mut head = 0; 259 let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap(); 260 assert_eq!(version_from_file, DEFAULT_FILE_VERSION); 261 } 262 263 // this test point locks down file type check 264 #[test] test_file_type_check()265 fn test_file_type_check() { 266 let mut flag_table = create_test_flag_table(DEFAULT_FILE_VERSION); 267 flag_table.header.file_type = 123u8; 268 let error = FlagTable::from_bytes(&flag_table.into_bytes()).unwrap_err(); 269 assert_eq!( 270 format!("{:?}", error), 271 format!("BytesParseFail(binary file is not a flag map)") 272 ); 273 } 274 } 275