xref: /aosp_15_r20/build/make/tools/aconfig/aconfig_storage_write_api/src/lib.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 //! `aconfig_storage_write_api` is a crate that defines write apis to update flag value
18 //! in storage file. It provides one api to interface with storage files.
19 
20 pub mod flag_info_update;
21 pub mod flag_value_update;
22 pub mod mapped_file;
23 
24 #[cfg(test)]
25 mod test_utils;
26 
27 use aconfig_storage_file::{AconfigStorageError, FlagValueType};
28 
29 use anyhow::anyhow;
30 use memmap2::MmapMut;
31 
32 /// Get read write mapped storage files.
33 ///
34 /// \input file_path: path to the storage file
35 ///
36 /// # Safety
37 ///
38 /// The memory mapped file may have undefined behavior if there are writes to this
39 /// file not thru this memory mapped file or there are concurrent writes to this
40 /// memory mapped file. Ensure all writes to the underlying file are thru this memory
41 /// mapped file and there are no concurrent writes.
map_mutable_storage_file(file_path: &str) -> Result<MmapMut, AconfigStorageError>42 pub unsafe fn map_mutable_storage_file(file_path: &str) -> Result<MmapMut, AconfigStorageError> {
43     crate::mapped_file::map_file(file_path)
44 }
45 
46 /// Set boolean flag value thru mapped file and flush the change to file
47 ///
48 /// \input mapped_file: the mapped flag value file
49 /// \input index: flag index
50 /// \input value: updated flag value
51 /// \return a result of ()
52 ///
set_boolean_flag_value( file: &mut MmapMut, index: u32, value: bool, ) -> Result<(), AconfigStorageError>53 pub fn set_boolean_flag_value(
54     file: &mut MmapMut,
55     index: u32,
56     value: bool,
57 ) -> Result<(), AconfigStorageError> {
58     crate::flag_value_update::update_boolean_flag_value(file, index, value)?;
59     file.flush().map_err(|errmsg| {
60         AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
61     })
62 }
63 
64 /// Set if flag is has server override thru mapped file and flush the change to file
65 ///
66 /// \input mapped_file: the mapped flag info file
67 /// \input index: flag index
68 /// \input value: updated flag has server override value
69 /// \return a result of ()
70 ///
set_flag_has_server_override( file: &mut MmapMut, flag_type: FlagValueType, index: u32, value: bool, ) -> Result<(), AconfigStorageError>71 pub fn set_flag_has_server_override(
72     file: &mut MmapMut,
73     flag_type: FlagValueType,
74     index: u32,
75     value: bool,
76 ) -> Result<(), AconfigStorageError> {
77     crate::flag_info_update::update_flag_has_server_override(file, flag_type, index, value)?;
78     file.flush().map_err(|errmsg| {
79         AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
80     })
81 }
82 
83 /// Set if flag has local override thru mapped file and flush the change to file
84 ///
85 /// \input mapped_file: the mapped flag info file
86 /// \input index: flag index
87 /// \input value: updated flag has local override value
88 /// \return a result of ()
89 ///
set_flag_has_local_override( file: &mut MmapMut, flag_type: FlagValueType, index: u32, value: bool, ) -> Result<(), AconfigStorageError>90 pub fn set_flag_has_local_override(
91     file: &mut MmapMut,
92     flag_type: FlagValueType,
93     index: u32,
94     value: bool,
95 ) -> Result<(), AconfigStorageError> {
96     crate::flag_info_update::update_flag_has_local_override(file, flag_type, index, value)?;
97     file.flush().map_err(|errmsg| {
98         AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
99     })
100 }
101 
102 // *************************************** //
103 // CC INTERLOP
104 // *************************************** //
105 
106 // Exported rust data structure and methods, c++ code will be generated
107 #[cxx::bridge]
108 mod ffi {
109     // Flag value update return for cc interlop
110     pub struct BooleanFlagValueUpdateCXX {
111         pub update_success: bool,
112         pub offset: usize,
113         pub error_message: String,
114     }
115 
116     // Flag has server override update return for cc interlop
117     pub struct FlagHasServerOverrideUpdateCXX {
118         pub update_success: bool,
119         pub offset: usize,
120         pub error_message: String,
121     }
122 
123     // Flag has local override update return for cc interlop
124     pub struct FlagHasLocalOverrideUpdateCXX {
125         pub update_success: bool,
126         pub offset: usize,
127         pub error_message: String,
128     }
129 
130     // Rust export to c++
131     extern "Rust" {
update_boolean_flag_value_cxx( file: &mut [u8], offset: u32, value: bool, ) -> BooleanFlagValueUpdateCXX132         pub fn update_boolean_flag_value_cxx(
133             file: &mut [u8],
134             offset: u32,
135             value: bool,
136         ) -> BooleanFlagValueUpdateCXX;
137 
update_flag_has_server_override_cxx( file: &mut [u8], flag_type: u16, offset: u32, value: bool, ) -> FlagHasServerOverrideUpdateCXX138         pub fn update_flag_has_server_override_cxx(
139             file: &mut [u8],
140             flag_type: u16,
141             offset: u32,
142             value: bool,
143         ) -> FlagHasServerOverrideUpdateCXX;
144 
update_flag_has_local_override_cxx( file: &mut [u8], flag_type: u16, offset: u32, value: bool, ) -> FlagHasLocalOverrideUpdateCXX145         pub fn update_flag_has_local_override_cxx(
146             file: &mut [u8],
147             flag_type: u16,
148             offset: u32,
149             value: bool,
150         ) -> FlagHasLocalOverrideUpdateCXX;
151     }
152 }
153 
update_boolean_flag_value_cxx( file: &mut [u8], offset: u32, value: bool, ) -> ffi::BooleanFlagValueUpdateCXX154 pub(crate) fn update_boolean_flag_value_cxx(
155     file: &mut [u8],
156     offset: u32,
157     value: bool,
158 ) -> ffi::BooleanFlagValueUpdateCXX {
159     match crate::flag_value_update::update_boolean_flag_value(file, offset, value) {
160         Ok(head) => ffi::BooleanFlagValueUpdateCXX {
161             update_success: true,
162             offset: head,
163             error_message: String::from(""),
164         },
165         Err(errmsg) => ffi::BooleanFlagValueUpdateCXX {
166             update_success: false,
167             offset: usize::MAX,
168             error_message: format!("{:?}", errmsg),
169         },
170     }
171 }
172 
update_flag_has_server_override_cxx( file: &mut [u8], flag_type: u16, offset: u32, value: bool, ) -> ffi::FlagHasServerOverrideUpdateCXX173 pub(crate) fn update_flag_has_server_override_cxx(
174     file: &mut [u8],
175     flag_type: u16,
176     offset: u32,
177     value: bool,
178 ) -> ffi::FlagHasServerOverrideUpdateCXX {
179     match FlagValueType::try_from(flag_type) {
180         Ok(value_type) => {
181             match crate::flag_info_update::update_flag_has_server_override(
182                 file, value_type, offset, value,
183             ) {
184                 Ok(head) => ffi::FlagHasServerOverrideUpdateCXX {
185                     update_success: true,
186                     offset: head,
187                     error_message: String::from(""),
188                 },
189                 Err(errmsg) => ffi::FlagHasServerOverrideUpdateCXX {
190                     update_success: false,
191                     offset: usize::MAX,
192                     error_message: format!("{:?}", errmsg),
193                 },
194             }
195         }
196         Err(errmsg) => ffi::FlagHasServerOverrideUpdateCXX {
197             update_success: false,
198             offset: usize::MAX,
199             error_message: format!("{:?}", errmsg),
200         },
201     }
202 }
203 
update_flag_has_local_override_cxx( file: &mut [u8], flag_type: u16, offset: u32, value: bool, ) -> ffi::FlagHasLocalOverrideUpdateCXX204 pub(crate) fn update_flag_has_local_override_cxx(
205     file: &mut [u8],
206     flag_type: u16,
207     offset: u32,
208     value: bool,
209 ) -> ffi::FlagHasLocalOverrideUpdateCXX {
210     match FlagValueType::try_from(flag_type) {
211         Ok(value_type) => {
212             match crate::flag_info_update::update_flag_has_local_override(
213                 file, value_type, offset, value,
214             ) {
215                 Ok(head) => ffi::FlagHasLocalOverrideUpdateCXX {
216                     update_success: true,
217                     offset: head,
218                     error_message: String::from(""),
219                 },
220                 Err(errmsg) => ffi::FlagHasLocalOverrideUpdateCXX {
221                     update_success: false,
222                     offset: usize::MAX,
223                     error_message: format!("{:?}", errmsg),
224                 },
225             }
226         }
227         Err(errmsg) => ffi::FlagHasLocalOverrideUpdateCXX {
228             update_success: false,
229             offset: usize::MAX,
230             error_message: format!("{:?}", errmsg),
231         },
232     }
233 }
234 
235 #[cfg(test)]
236 mod tests {
237     use super::*;
238     use crate::test_utils::copy_to_temp_file;
239     use aconfig_storage_file::FlagInfoBit;
240     use aconfig_storage_read_api::flag_info_query::find_flag_attribute;
241     use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
242     use std::fs::File;
243     use std::io::Read;
244 
get_boolean_flag_value_at_offset(file: &str, offset: u32) -> bool245     fn get_boolean_flag_value_at_offset(file: &str, offset: u32) -> bool {
246         let mut f = File::open(&file).unwrap();
247         let mut bytes = Vec::new();
248         f.read_to_end(&mut bytes).unwrap();
249         find_boolean_flag_value(&bytes, offset).unwrap()
250     }
251 
252     #[test]
test_set_boolean_flag_value()253     fn test_set_boolean_flag_value() {
254         let flag_value_file = copy_to_temp_file("./tests/flag.val", false).unwrap();
255         let flag_value_path = flag_value_file.path().display().to_string();
256 
257         // SAFETY:
258         // The safety here is guaranteed as only this single threaded test process will
259         // write to this file
260         unsafe {
261             let mut file = map_mutable_storage_file(&flag_value_path).unwrap();
262             for i in 0..8 {
263                 set_boolean_flag_value(&mut file, i, true).unwrap();
264                 let value = get_boolean_flag_value_at_offset(&flag_value_path, i);
265                 assert_eq!(value, true);
266 
267                 set_boolean_flag_value(&mut file, i, false).unwrap();
268                 let value = get_boolean_flag_value_at_offset(&flag_value_path, i);
269                 assert_eq!(value, false);
270             }
271         }
272     }
273 
get_flag_attribute_at_offset(file: &str, value_type: FlagValueType, offset: u32) -> u8274     fn get_flag_attribute_at_offset(file: &str, value_type: FlagValueType, offset: u32) -> u8 {
275         let mut f = File::open(&file).unwrap();
276         let mut bytes = Vec::new();
277         f.read_to_end(&mut bytes).unwrap();
278         find_flag_attribute(&bytes, value_type, offset).unwrap()
279     }
280 
281     #[test]
test_set_flag_has_server_override()282     fn test_set_flag_has_server_override() {
283         let flag_info_file = copy_to_temp_file("./tests/flag.info", false).unwrap();
284         let flag_info_path = flag_info_file.path().display().to_string();
285 
286         // SAFETY:
287         // The safety here is guaranteed as only this single threaded test process will
288         // write to this file
289         unsafe {
290             let mut file = map_mutable_storage_file(&flag_info_path).unwrap();
291             for i in 0..8 {
292                 set_flag_has_server_override(&mut file, FlagValueType::Boolean, i, true).unwrap();
293                 let attribute =
294                     get_flag_attribute_at_offset(&flag_info_path, FlagValueType::Boolean, i);
295                 assert!((attribute & (FlagInfoBit::HasServerOverride as u8)) != 0);
296                 set_flag_has_server_override(&mut file, FlagValueType::Boolean, i, false).unwrap();
297                 let attribute =
298                     get_flag_attribute_at_offset(&flag_info_path, FlagValueType::Boolean, i);
299                 assert!((attribute & (FlagInfoBit::HasServerOverride as u8)) == 0);
300             }
301         }
302     }
303 
304     #[test]
test_set_flag_has_local_override()305     fn test_set_flag_has_local_override() {
306         let flag_info_file = copy_to_temp_file("./tests/flag.info", false).unwrap();
307         let flag_info_path = flag_info_file.path().display().to_string();
308 
309         // SAFETY:
310         // The safety here is guaranteed as only this single threaded test process will
311         // write to this file
312         unsafe {
313             let mut file = map_mutable_storage_file(&flag_info_path).unwrap();
314             for i in 0..8 {
315                 set_flag_has_local_override(&mut file, FlagValueType::Boolean, i, true).unwrap();
316                 let attribute =
317                     get_flag_attribute_at_offset(&flag_info_path, FlagValueType::Boolean, i);
318                 assert!((attribute & (FlagInfoBit::HasLocalOverride as u8)) != 0);
319                 set_flag_has_local_override(&mut file, FlagValueType::Boolean, i, false).unwrap();
320                 let attribute =
321                     get_flag_attribute_at_offset(&flag_info_path, FlagValueType::Boolean, i);
322                 assert!((attribute & (FlagInfoBit::HasLocalOverride as u8)) == 0);
323             }
324         }
325     }
326 }
327