1 /* 2 * Copyright (C) 2023 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 //! package table module defines the package table file format and methods for serialization 18 //! and deserialization 19 20 use crate::{ 21 get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u64_from_bytes, 22 read_u8_from_bytes, 23 }; 24 use crate::{AconfigStorageError, StorageFileType}; 25 use anyhow::anyhow; 26 use serde::{Deserialize, Serialize}; 27 use std::fmt; 28 29 /// Package table header struct 30 #[derive(PartialEq, Serialize, Deserialize)] 31 pub struct PackageTableHeader { 32 pub version: u32, 33 pub container: String, 34 pub file_type: u8, 35 pub file_size: u32, 36 pub num_packages: 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 PackageTableHeader { 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 Packages: {}, Bucket Offset:{}, Node Offset: {}", 55 self.num_packages, self.bucket_offset, self.node_offset 56 )?; 57 Ok(()) 58 } 59 } 60 61 impl PackageTableHeader { 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_packages.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_packages: 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::PackageMap as u8 { 90 return Err(AconfigStorageError::BytesParseFail(anyhow!( 91 "binary file is not a package map" 92 ))); 93 } 94 Ok(table) 95 } 96 } 97 98 /// Package table node struct 99 #[derive(PartialEq, Serialize, Deserialize)] 100 pub struct PackageTableNode { 101 pub package_name: String, 102 pub package_id: u32, 103 pub fingerprint: u64, 104 // The index of the first boolean flag in this aconfig package among all boolean 105 // flags in this container. 106 pub boolean_start_index: u32, 107 pub next_offset: Option<u32>, 108 } 109 110 /// Implement debug print trait for node 111 impl fmt::Debug for PackageTableNode { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 113 writeln!( 114 f, 115 "Package: {}, Id: {}, Fingerprint: {}, Boolean flag start index: {}, Next: {:?}", 116 self.package_name, 117 self.package_id, 118 self.fingerprint, 119 self.boolean_start_index, 120 self.next_offset 121 )?; 122 Ok(()) 123 } 124 } 125 126 impl PackageTableNode { 127 /// Serialize to bytes into_bytes(&self, version: u32) -> Vec<u8>128 pub fn into_bytes(&self, version: u32) -> Vec<u8> { 129 match version { 130 1 => Self::into_bytes_v1(self), 131 2 => Self::into_bytes_v2(self), 132 // TODO(b/316357686): into_bytes should return a Result. 133 _ => Self::into_bytes_v2(&self), 134 } 135 } 136 into_bytes_v1(&self) -> Vec<u8>137 fn into_bytes_v1(&self) -> Vec<u8> { 138 let mut result = Vec::new(); 139 let name_bytes = self.package_name.as_bytes(); 140 result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes()); 141 result.extend_from_slice(name_bytes); 142 result.extend_from_slice(&self.package_id.to_le_bytes()); 143 result.extend_from_slice(&self.boolean_start_index.to_le_bytes()); 144 result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes()); 145 result 146 } 147 into_bytes_v2(&self) -> Vec<u8>148 fn into_bytes_v2(&self) -> Vec<u8> { 149 let mut result = Vec::new(); 150 let name_bytes = self.package_name.as_bytes(); 151 result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes()); 152 result.extend_from_slice(name_bytes); 153 result.extend_from_slice(&self.package_id.to_le_bytes()); 154 result.extend_from_slice(&self.fingerprint.to_le_bytes()); 155 result.extend_from_slice(&self.boolean_start_index.to_le_bytes()); 156 result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes()); 157 result 158 } 159 160 /// Deserialize from bytes based on file version. from_bytes(bytes: &[u8], version: u32) -> Result<Self, AconfigStorageError>161 pub fn from_bytes(bytes: &[u8], version: u32) -> Result<Self, AconfigStorageError> { 162 match version { 163 1 => Self::from_bytes_v1(bytes), 164 2 => Self::from_bytes_v2(bytes), 165 _ => { 166 return Err(AconfigStorageError::BytesParseFail(anyhow!( 167 "Binary file is an unsupported version: {}", 168 version 169 ))) 170 } 171 } 172 } 173 from_bytes_v1(bytes: &[u8]) -> Result<Self, AconfigStorageError>174 fn from_bytes_v1(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 175 let mut head = 0; 176 let package_name = read_str_from_bytes(bytes, &mut head)?; 177 let package_id = read_u32_from_bytes(bytes, &mut head)?; 178 // v1 does not have fingerprint, so just set to 0. 179 let fingerprint: u64 = 0; 180 let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?; 181 let next_offset = match read_u32_from_bytes(bytes, &mut head)? { 182 0 => None, 183 val => Some(val), 184 }; 185 186 let node = Self { package_name, package_id, fingerprint, boolean_start_index, next_offset }; 187 Ok(node) 188 } 189 from_bytes_v2(bytes: &[u8]) -> Result<Self, AconfigStorageError>190 fn from_bytes_v2(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 191 let mut head = 0; 192 let package_name = read_str_from_bytes(bytes, &mut head)?; 193 let package_id = read_u32_from_bytes(bytes, &mut head)?; 194 let fingerprint = read_u64_from_bytes(bytes, &mut head)?; 195 let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?; 196 let next_offset = match read_u32_from_bytes(bytes, &mut head)? { 197 0 => None, 198 val => Some(val), 199 }; 200 201 let node = Self { package_name, package_id, fingerprint, boolean_start_index, next_offset }; 202 Ok(node) 203 } 204 205 /// Get the bucket index for a package table node, defined it here so the 206 /// construction side (aconfig binary) and consumption side (flag read lib) 207 /// use the same method of hashing find_bucket_index(package: &str, num_buckets: u32) -> u32208 pub fn find_bucket_index(package: &str, num_buckets: u32) -> u32 { 209 get_bucket_index(package.as_bytes(), num_buckets) 210 } 211 } 212 213 /// Package table struct 214 #[derive(PartialEq, Serialize, Deserialize)] 215 pub struct PackageTable { 216 pub header: PackageTableHeader, 217 pub buckets: Vec<Option<u32>>, 218 pub nodes: Vec<PackageTableNode>, 219 } 220 221 /// Implement debug print trait for package table 222 impl fmt::Debug for PackageTable { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 224 writeln!(f, "Header:")?; 225 write!(f, "{:?}", self.header)?; 226 writeln!(f, "Buckets:")?; 227 writeln!(f, "{:?}", self.buckets)?; 228 writeln!(f, "Nodes:")?; 229 for node in self.nodes.iter() { 230 write!(f, "{:?}", node)?; 231 } 232 Ok(()) 233 } 234 } 235 236 impl PackageTable { 237 /// Serialize to bytes into_bytes(&self) -> Vec<u8>238 pub fn into_bytes(&self) -> Vec<u8> { 239 [ 240 self.header.into_bytes(), 241 self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(), 242 self.nodes 243 .iter() 244 .map(|v| v.into_bytes(self.header.version)) 245 .collect::<Vec<_>>() 246 .concat(), 247 ] 248 .concat() 249 } 250 251 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>252 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 253 let header = PackageTableHeader::from_bytes(bytes)?; 254 let num_packages = header.num_packages; 255 let num_buckets = crate::get_table_size(num_packages)?; 256 let mut head = header.into_bytes().len(); 257 let buckets = (0..num_buckets) 258 .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() { 259 0 => None, 260 val => Some(val), 261 }) 262 .collect(); 263 let nodes = (0..num_packages) 264 .map(|_| { 265 let node = PackageTableNode::from_bytes(&bytes[head..], header.version)?; 266 head += node.into_bytes(header.version).len(); 267 Ok(node) 268 }) 269 .collect::<Result<Vec<_>, AconfigStorageError>>() 270 .map_err(|errmsg| { 271 AconfigStorageError::BytesParseFail(anyhow!( 272 "fail to parse package table: {}", 273 errmsg 274 )) 275 })?; 276 277 let table = Self { header, buckets, nodes }; 278 Ok(table) 279 } 280 } 281 282 #[cfg(test)] 283 mod tests { 284 use super::*; 285 use crate::test_utils::create_test_package_table; 286 use crate::{read_u32_from_start_of_bytes, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION}; 287 288 #[test] 289 // this test point locks down the table serialization test_serialization()290 fn test_serialization() { 291 for file_version in 1..=MAX_SUPPORTED_FILE_VERSION { 292 let package_table = create_test_package_table(file_version); 293 let header: &PackageTableHeader = &package_table.header; 294 let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes()); 295 assert!(reinterpreted_header.is_ok()); 296 assert_eq!(header, &reinterpreted_header.unwrap()); 297 298 let nodes: &Vec<PackageTableNode> = &package_table.nodes; 299 for node in nodes.iter() { 300 let reinterpreted_node = 301 PackageTableNode::from_bytes(&node.into_bytes(header.version), header.version) 302 .unwrap(); 303 assert_eq!(node, &reinterpreted_node); 304 } 305 306 let package_table_bytes = package_table.into_bytes(); 307 let reinterpreted_table = PackageTable::from_bytes(&package_table_bytes); 308 assert!(reinterpreted_table.is_ok()); 309 assert_eq!(&package_table, &reinterpreted_table.unwrap()); 310 assert_eq!(package_table_bytes.len() as u32, header.file_size); 311 } 312 } 313 314 #[test] 315 // this test point locks down that version number should be at the top of serialized 316 // bytes test_version_number()317 fn test_version_number() { 318 let package_table = create_test_package_table(DEFAULT_FILE_VERSION); 319 let bytes = &package_table.into_bytes(); 320 let unpacked_version = read_u32_from_start_of_bytes(bytes).unwrap(); 321 assert_eq!(unpacked_version, DEFAULT_FILE_VERSION); 322 } 323 324 #[test] test_round_trip_default()325 fn test_round_trip_default() { 326 let table: PackageTable = create_test_package_table(DEFAULT_FILE_VERSION); 327 let table_bytes = table.into_bytes(); 328 329 let reinterpreted_table = PackageTable::from_bytes(&table_bytes).unwrap(); 330 331 assert_eq!(table, reinterpreted_table); 332 } 333 334 #[test] test_round_trip_max()335 fn test_round_trip_max() { 336 let table: PackageTable = create_test_package_table(MAX_SUPPORTED_FILE_VERSION); 337 let table_bytes = table.into_bytes(); 338 339 let reinterpreted_table = PackageTable::from_bytes(&table_bytes).unwrap(); 340 341 assert_eq!(table, reinterpreted_table); 342 } 343 344 #[test] 345 // this test point locks down file type check test_file_type_check()346 fn test_file_type_check() { 347 let mut package_table = create_test_package_table(DEFAULT_FILE_VERSION); 348 package_table.header.file_type = 123u8; 349 let error = PackageTable::from_bytes(&package_table.into_bytes()).unwrap_err(); 350 assert_eq!( 351 format!("{:?}", error), 352 format!("BytesParseFail(binary file is not a package map)") 353 ); 354 } 355 } 356