xref: /aosp_15_r20/build/make/tools/aconfig/aconfig_storage_file/src/flag_info.rs (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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 info module defines the flag info 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 info header struct
27 #[derive(PartialEq, Serialize, Deserialize)]
28 pub struct FlagInfoHeader {
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_flag_offset: u32,
35 }
36 
37 /// Implement debug print trait for header
38 impl fmt::Debug for FlagInfoHeader {
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: {}, Boolean Flag Offset:{}",
51             self.num_flags, self.boolean_flag_offset
52         )?;
53         Ok(())
54     }
55 }
56 
57 impl FlagInfoHeader {
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_flag_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_flag_offset: read_u32_from_bytes(bytes, &mut head)?,
82         };
83         if list.file_type != StorageFileType::FlagInfo as u8 {
84             return Err(AconfigStorageError::BytesParseFail(anyhow!(
85                 "binary file is not a flag info file"
86             )));
87         }
88         Ok(list)
89     }
90 }
91 
92 /// bit field for flag info
93 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
94 pub enum FlagInfoBit {
95     HasServerOverride = 1 << 0,
96     IsReadWrite = 1 << 1,
97     HasLocalOverride = 1 << 2,
98 }
99 
100 /// Flag info node struct
101 #[derive(PartialEq, Clone, Serialize, Deserialize)]
102 pub struct FlagInfoNode {
103     pub attributes: u8,
104 }
105 
106 /// Implement debug print trait for node
107 impl fmt::Debug for FlagInfoNode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result108     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109         writeln!(
110             f,
111             "readwrite: {}, server override: {}, local override: {}",
112             self.attributes & (FlagInfoBit::IsReadWrite as u8) != 0,
113             self.attributes & (FlagInfoBit::HasServerOverride as u8) != 0,
114             self.attributes & (FlagInfoBit::HasLocalOverride as u8) != 0,
115         )?;
116         Ok(())
117     }
118 }
119 
120 impl FlagInfoNode {
121     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>122     pub fn into_bytes(&self) -> Vec<u8> {
123         let mut result = Vec::new();
124         result.extend_from_slice(&self.attributes.to_le_bytes());
125         result
126     }
127 
128     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>129     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
130         let mut head = 0;
131         let node = Self { attributes: read_u8_from_bytes(bytes, &mut head)? };
132         Ok(node)
133     }
134 
135     /// Create flag info node
create(is_flag_rw: bool) -> Self136     pub fn create(is_flag_rw: bool) -> Self {
137         Self { attributes: if is_flag_rw { FlagInfoBit::IsReadWrite as u8 } else { 0u8 } }
138     }
139 }
140 
141 /// Flag info list struct
142 #[derive(PartialEq, Serialize, Deserialize)]
143 pub struct FlagInfoList {
144     pub header: FlagInfoHeader,
145     pub nodes: Vec<FlagInfoNode>,
146 }
147 
148 /// Implement debug print trait for flag info list
149 impl fmt::Debug for FlagInfoList {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result150     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151         writeln!(f, "Header:")?;
152         write!(f, "{:?}", self.header)?;
153         writeln!(f, "Nodes:")?;
154         for node in self.nodes.iter() {
155             write!(f, "{:?}", node)?;
156         }
157         Ok(())
158     }
159 }
160 
161 impl FlagInfoList {
162     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>163     pub fn into_bytes(&self) -> Vec<u8> {
164         [
165             self.header.into_bytes(),
166             self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
167         ]
168         .concat()
169     }
170 
171     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>172     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
173         let header = FlagInfoHeader::from_bytes(bytes)?;
174         let num_flags = header.num_flags;
175         let mut head = header.into_bytes().len();
176         let nodes = (0..num_flags)
177             .map(|_| {
178                 let node = FlagInfoNode::from_bytes(&bytes[head..])?;
179                 head += node.into_bytes().len();
180                 Ok(node)
181             })
182             .collect::<Result<Vec<_>, AconfigStorageError>>()
183             .map_err(|errmsg| {
184                 AconfigStorageError::BytesParseFail(anyhow!(
185                     "fail to parse flag info list: {}",
186                     errmsg
187                 ))
188             })?;
189         let list = Self { header, nodes };
190         Ok(list)
191     }
192 }
193 
194 #[cfg(test)]
195 mod tests {
196     use super::*;
197     use crate::{
198         test_utils::create_test_flag_info_list, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION,
199     };
200 
201     // this test point locks down the value list serialization
202     // TODO: b/376108268 - Use parameterized tests.
203     #[test]
test_serialization_default()204     fn test_serialization_default() {
205         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
206 
207         let header: &FlagInfoHeader = &flag_info_list.header;
208         let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
209         assert!(reinterpreted_header.is_ok());
210         assert_eq!(header, &reinterpreted_header.unwrap());
211 
212         let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
213         for node in nodes.iter() {
214             let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
215             assert_eq!(node, &reinterpreted_node);
216         }
217 
218         let flag_info_bytes = flag_info_list.into_bytes();
219         let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
220         assert!(reinterpreted_info_list.is_ok());
221         assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
222         assert_eq!(flag_info_bytes.len() as u32, header.file_size);
223     }
224 
225     #[test]
test_serialization_max()226     fn test_serialization_max() {
227         let flag_info_list = create_test_flag_info_list(MAX_SUPPORTED_FILE_VERSION);
228 
229         let header: &FlagInfoHeader = &flag_info_list.header;
230         let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
231         assert!(reinterpreted_header.is_ok());
232         assert_eq!(header, &reinterpreted_header.unwrap());
233 
234         let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
235         for node in nodes.iter() {
236             let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
237             assert_eq!(node, &reinterpreted_node);
238         }
239 
240         let flag_info_bytes = flag_info_list.into_bytes();
241         let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
242         assert!(reinterpreted_info_list.is_ok());
243         assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
244         assert_eq!(flag_info_bytes.len() as u32, header.file_size);
245     }
246 
247     // this test point locks down that version number should be at the top of serialized
248     // bytes
249     #[test]
test_version_number()250     fn test_version_number() {
251         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
252         let bytes = &flag_info_list.into_bytes();
253         let mut head = 0;
254         let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap();
255         assert_eq!(version_from_file, DEFAULT_FILE_VERSION);
256     }
257 
258     // this test point locks down file type check
259     #[test]
test_file_type_check()260     fn test_file_type_check() {
261         let mut flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
262         flag_info_list.header.file_type = 123u8;
263         let error = FlagInfoList::from_bytes(&flag_info_list.into_bytes()).unwrap_err();
264         assert_eq!(
265             format!("{:?}", error),
266             format!("BytesParseFail(binary file is not a flag info file)")
267         );
268     }
269 }
270