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