• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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