• 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 use crate::commands::assign_flag_ids;
18 use crate::storage::FlagPackage;
19 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState};
20 use aconfig_storage_file::{FlagInfoHeader, FlagInfoList, FlagInfoNode, StorageFileType};
21 use anyhow::{anyhow, Result};
22 
new_header(container: &str, num_flags: u32, version: u32) -> FlagInfoHeader23 fn new_header(container: &str, num_flags: u32, version: u32) -> FlagInfoHeader {
24     FlagInfoHeader {
25         version,
26         container: String::from(container),
27         file_type: StorageFileType::FlagInfo as u8,
28         file_size: 0,
29         num_flags,
30         boolean_flag_offset: 0,
31     }
32 }
33 
create_flag_info( container: &str, packages: &[FlagPackage], version: u32, ) -> Result<FlagInfoList>34 pub fn create_flag_info(
35     container: &str,
36     packages: &[FlagPackage],
37     version: u32,
38 ) -> Result<FlagInfoList> {
39     // Exclude system/vendor/product flags that are RO+disabled.
40     let mut filtered_packages = packages.to_vec();
41     if container == "system" || container == "vendor" || container == "product" {
42         for package in filtered_packages.iter_mut() {
43             package.boolean_flags.retain(|b| {
44                 !(b.state == Some(ProtoFlagState::DISABLED.into())
45                     && b.permission == Some(ProtoFlagPermission::READ_ONLY.into()))
46             });
47         }
48     }
49 
50     let num_flags = filtered_packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
51 
52     let mut is_flag_rw = vec![false; num_flags as usize];
53     for pkg in filtered_packages {
54         let start_index = pkg.boolean_start_index as usize;
55         let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
56         for pf in pkg.boolean_flags {
57             let fid = flag_ids
58                 .get(pf.name())
59                 .ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
60             is_flag_rw[start_index + (*fid as usize)] =
61                 pf.permission() == ProtoFlagPermission::READ_WRITE;
62         }
63     }
64 
65     let mut list = FlagInfoList {
66         header: new_header(container, num_flags, version),
67         nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
68     };
69 
70     // initialize all header fields
71     list.header.boolean_flag_offset = list.header.into_bytes().len() as u32;
72     let bytes_per_node = FlagInfoNode::create(false).into_bytes().len() as u32;
73     list.header.file_size = list.header.boolean_flag_offset + num_flags * bytes_per_node;
74 
75     Ok(list)
76 }
77 
78 #[cfg(test)]
79 mod tests {
80     use super::*;
81     use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
82     use aconfig_storage_file::DEFAULT_FILE_VERSION;
83 
create_test_flag_info_list_from_source() -> Result<FlagInfoList>84     pub fn create_test_flag_info_list_from_source() -> Result<FlagInfoList> {
85         let caches = parse_all_test_flags();
86         let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
87         create_flag_info("mockup", &packages, DEFAULT_FILE_VERSION)
88     }
89 
90     #[test]
91     // this test point locks down the flag info creation and each field
test_list_contents()92     fn test_list_contents() {
93         let flag_info_list = create_test_flag_info_list_from_source();
94         assert!(flag_info_list.is_ok());
95         let expected_flag_info_list =
96             aconfig_storage_file::test_utils::create_test_flag_info_list(DEFAULT_FILE_VERSION);
97         assert_eq!(flag_info_list.unwrap(), expected_flag_info_list);
98     }
99 }
100