xref: /aosp_15_r20/build/make/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.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 value query module defines the flag value file read from mapped bytes
18 
19 use crate::AconfigStorageError;
20 use aconfig_storage_file::{
21     flag_info::FlagInfoHeader, read_u8_from_bytes, FlagValueType, MAX_SUPPORTED_FILE_VERSION,
22 };
23 use anyhow::anyhow;
24 
25 /// Get flag attribute bitfield
find_flag_attribute( buf: &[u8], flag_type: FlagValueType, flag_index: u32, ) -> Result<u8, AconfigStorageError>26 pub fn find_flag_attribute(
27     buf: &[u8],
28     flag_type: FlagValueType,
29     flag_index: u32,
30 ) -> Result<u8, AconfigStorageError> {
31     let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
32     if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
33         return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
34             "Cannot read storage file with a higher version of {} with lib version {}",
35             interpreted_header.version,
36             MAX_SUPPORTED_FILE_VERSION
37         )));
38     }
39 
40     // get byte offset to the flag info
41     let mut head = match flag_type {
42         FlagValueType::Boolean => (interpreted_header.boolean_flag_offset + flag_index) as usize,
43     };
44 
45     if head >= interpreted_header.file_size as usize {
46         return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
47             "Flag info offset goes beyond the end of the file."
48         )));
49     }
50 
51     let val = read_u8_from_bytes(buf, &mut head)?;
52     Ok(val)
53 }
54 
55 #[cfg(test)]
56 mod tests {
57     use super::*;
58     use aconfig_storage_file::{
59         test_utils::create_test_flag_info_list, FlagInfoBit, DEFAULT_FILE_VERSION,
60     };
61 
62     #[test]
63     // this test point locks down query if flag has server override
test_is_flag_sticky()64     fn test_is_flag_sticky() {
65         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
66         for offset in 0..8 {
67             let attribute =
68                 find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
69             assert_eq!((attribute & FlagInfoBit::HasServerOverride as u8) != 0u8, false);
70         }
71     }
72 
73     #[test]
74     // this test point locks down query if flag is readwrite
test_is_flag_readwrite()75     fn test_is_flag_readwrite() {
76         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
77         let baseline: Vec<bool> = vec![true, false, true, true, false, false, false, true];
78         for offset in 0..8 {
79             let attribute =
80                 find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
81             assert_eq!(
82                 (attribute & FlagInfoBit::IsReadWrite as u8) != 0u8,
83                 baseline[offset as usize]
84             );
85         }
86     }
87 
88     #[test]
89     // this test point locks down query if flag has local override
test_flag_has_override()90     fn test_flag_has_override() {
91         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
92         for offset in 0..8 {
93             let attribute =
94                 find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
95             assert_eq!((attribute & FlagInfoBit::HasLocalOverride as u8) != 0u8, false);
96         }
97     }
98 
99     #[test]
100     // this test point locks down query beyond the end of boolean section
test_boolean_out_of_range()101     fn test_boolean_out_of_range() {
102         let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
103         let error =
104             find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, 8).unwrap_err();
105         assert_eq!(
106             format!("{:?}", error),
107             "InvalidStorageFileOffset(Flag info offset goes beyond the end of the file.)"
108         );
109     }
110 
111     #[test]
112     // this test point locks down query error when file has a higher version
test_higher_version_storage_file()113     fn test_higher_version_storage_file() {
114         let mut info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
115         info_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
116         let flag_info = info_list.into_bytes();
117         let error = find_flag_attribute(&flag_info[..], FlagValueType::Boolean, 4).unwrap_err();
118         assert_eq!(
119             format!("{:?}", error),
120             format!(
121                 "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
122                 MAX_SUPPORTED_FILE_VERSION + 1,
123                 MAX_SUPPORTED_FILE_VERSION
124             )
125         );
126     }
127 }
128