Merge "Convert device/sample/Android.mk to Android.bp" into main
diff --git a/core/board_config.mk b/core/board_config.mk
index 4424517..633303f 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -992,7 +992,7 @@
# BOARD_API_LEVEL for vendor API surface
ifdef RELEASE_BOARD_API_LEVEL
ifdef BOARD_API_LEVEL
- $(error BOARD_API_LEVEL must not set manully. The build system automatically sets this value.)
+ $(error BOARD_API_LEVEL must not be set manually. The build system automatically sets this value.)
endif
BOARD_API_LEVEL := $(RELEASE_BOARD_API_LEVEL)
.KATI_READONLY := BOARD_API_LEVEL
diff --git a/core/config.mk b/core/config.mk
index e37f010..daefa70 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -420,12 +420,9 @@
.KATI_READONLY := TARGET_MAX_PAGE_SIZE_SUPPORTED
# Boolean variable determining if AOSP relies on bionic's PAGE_SIZE macro.
+TARGET_NO_BIONIC_PAGE_SIZE_MACRO := false
ifdef PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO
TARGET_NO_BIONIC_PAGE_SIZE_MACRO := $(PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO)
-else ifeq ($(call math_lt,$(VSR_VENDOR_API_LEVEL),34),true)
- TARGET_NO_BIONIC_PAGE_SIZE_MACRO := false
-else
- TARGET_NO_BIONIC_PAGE_SIZE_MACRO := true
endif
.KATI_READONLY := TARGET_NO_BIONIC_PAGE_SIZE_MACRO
diff --git a/core/release_config.mk b/core/release_config.mk
index a7b5b3f..3e51af5 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -41,8 +41,7 @@
# which has OWNERS control. If it isn't let others define their own.
# TODO: Remove wildcard for build/release one when all branch manifests
# have updated.
-config_map_files := $(wildcard build/trunk_release/release_config_map.mk) \
- $(wildcard build/release/release_config_map.mk) \
+config_map_files := $(wildcard build/release/release_config_map.mk) \
$(wildcard vendor/google_shared/build/release/release_config_map.mk) \
$(if $(wildcard vendor/google/release/release_config_map.mk), \
vendor/google/release/release_config_map.mk, \
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 0ea8fea..7651dba 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -20,7 +20,7 @@
// aconfig C++ integration tests (test mode auto-generated code)
"name": "aconfig.test.cpp.test_mode"
},
- // TODO(327420679): Enable export mode for native flag library
+ // TODO(b/327420679): Enable export mode for native flag library
// {
// // aconfig C++ integration tests (exported mode auto-generated code)
// "name": "aconfig.test.cpp.exported_mode"
@@ -33,7 +33,7 @@
// aconfig Rust integration tests (test mode auto-generated code)
"name": "aconfig.test_mode.test.rust"
},
- // TODO(327420679): Enable export mode for native flag library
+ // TODO(b/327420679): Enable export mode for native flag library
// {
// // aconfig Rust integration tests (exported mode auto-generated code)
// "name": "aconfig.exported_mode.test.rust"
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index b861c1f..a07f179 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -16,8 +16,10 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
+use aconfig_protos::ProtoFlagPermission;
use aconfig_storage_file::{
- get_table_size, FlagTable, FlagTableHeader, FlagTableNode, FILE_VERSION, StorageFileType
+ get_table_size, FlagTable, FlagTableHeader, FlagTableNode, StorageFileType, StoredFlagType,
+ FILE_VERSION,
};
use anyhow::{anyhow, Result};
@@ -45,7 +47,7 @@
fn new(
package_id: u32,
flag_name: &str,
- flag_type: u16,
+ flag_type: StoredFlagType,
flag_id: u16,
num_buckets: u32,
) -> Self {
@@ -70,11 +72,14 @@
let fid = flag_ids
.get(pf.name())
.ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
- // all flags are boolean value at the moment, thus using the last bit.
- // When more flag value types are supported, flag value type information
- // should come from the parsed flag, and we will set the flag_type bit
- // mask properly.
- let flag_type = 1;
+ let flag_type = if pf.is_fixed_read_only() {
+ StoredFlagType::FixedReadOnlyBoolean
+ } else {
+ match pf.permission() {
+ ProtoFlagPermission::READ_WRITE => StoredFlagType::ReadWriteBoolean,
+ ProtoFlagPermission::READ_ONLY => StoredFlagType::ReadOnlyBoolean,
+ }
+ };
Ok(Self::new(package.package_id, pf.name(), flag_type, *fid, num_buckets))
})
.collect::<Result<Vec<_>>>()
@@ -95,10 +100,10 @@
.concat();
// initialize all header fields
- header.bucket_offset = header.as_bytes().len() as u32;
+ header.bucket_offset = header.into_bytes().len() as u32;
header.node_offset = header.bucket_offset + num_buckets * 4;
header.file_size = header.node_offset
- + node_wrappers.iter().map(|x| x.node.as_bytes().len()).sum::<usize>() as u32;
+ + node_wrappers.iter().map(|x| x.node.into_bytes().len()).sum::<usize>() as u32;
// sort nodes by bucket index for efficiency
node_wrappers.sort_by(|a, b| a.bucket_index.cmp(&b.bucket_index));
@@ -116,7 +121,7 @@
if buckets[node_bucket_idx as usize].is_none() {
buckets[node_bucket_idx as usize] = Some(offset);
}
- offset += node_wrappers[i].node.as_bytes().len() as u32;
+ offset += node_wrappers[i].node.into_bytes().len() as u32;
if let Some(index) = next_node_bucket_idx {
if index == node_bucket_idx {
@@ -147,7 +152,7 @@
FlagTableNode {
package_id,
flag_name: flag_name.to_string(),
- flag_type,
+ flag_type: StoredFlagType::try_from(flag_type).unwrap(),
flag_id,
next_offset,
}
@@ -203,12 +208,12 @@
assert_eq!(nodes.len(), 8);
assert_eq!(nodes[0], new_expected_node(0, "enabled_ro", 1, 1, None));
- assert_eq!(nodes[1], new_expected_node(0, "enabled_rw", 1, 2, Some(151)));
+ assert_eq!(nodes[1], new_expected_node(0, "enabled_rw", 0, 2, Some(151)));
assert_eq!(nodes[2], new_expected_node(1, "disabled_ro", 1, 0, None));
assert_eq!(nodes[3], new_expected_node(2, "enabled_ro", 1, 1, None));
- assert_eq!(nodes[4], new_expected_node(1, "enabled_fixed_ro", 1, 1, Some(236)));
+ assert_eq!(nodes[4], new_expected_node(1, "enabled_fixed_ro", 2, 1, Some(236)));
assert_eq!(nodes[5], new_expected_node(1, "enabled_ro", 1, 2, None));
- assert_eq!(nodes[6], new_expected_node(2, "enabled_fixed_ro", 1, 0, None));
- assert_eq!(nodes[7], new_expected_node(0, "disabled_rw", 1, 0, None));
+ assert_eq!(nodes[6], new_expected_node(2, "enabled_fixed_ro", 2, 0, None));
+ assert_eq!(nodes[7], new_expected_node(0, "disabled_rw", 0, 0, None));
}
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index e40bbc1..4dcf751 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -17,7 +17,7 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
use aconfig_protos::ProtoFlagState;
-use aconfig_storage_file::{FlagValueHeader, FlagValueList, FILE_VERSION, StorageFileType};
+use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType, FILE_VERSION};
use anyhow::{anyhow, Result};
fn new_header(container: &str, num_flags: u32) -> FlagValueHeader {
@@ -53,7 +53,7 @@
}
// initialize all header fields
- list.header.boolean_value_offset = list.header.as_bytes().len() as u32;
+ list.header.boolean_value_offset = list.header.into_bytes().len() as u32;
list.header.file_size = list.header.boolean_value_offset + num_flags;
Ok(list)
@@ -88,7 +88,7 @@
assert_eq!(header, &expected_header);
let booleans: &Vec<bool> = &flag_value_list.as_ref().unwrap().booleans;
- let expected_booleans: Vec<bool> = vec![false; header.num_flags as usize];
+ let expected_booleans: Vec<bool> = vec![false, true, true, false, true, true, true, true];
assert_eq!(booleans, &expected_booleans);
}
}
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index c818d79..30517de 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -18,7 +18,7 @@
pub mod flag_value;
pub mod package_table;
-use anyhow::Result;
+use anyhow::{anyhow, Result};
use std::collections::{HashMap, HashSet};
use crate::storage::{
@@ -97,16 +97,17 @@
match file {
StorageFileType::PackageMap => {
let package_table = create_package_table(container, &packages)?;
- Ok(package_table.as_bytes())
+ Ok(package_table.into_bytes())
}
StorageFileType::FlagMap => {
let flag_table = create_flag_table(container, &packages)?;
- Ok(flag_table.as_bytes())
+ Ok(flag_table.into_bytes())
}
StorageFileType::FlagVal => {
let flag_value = create_flag_value(container, &packages)?;
- Ok(flag_value.as_bytes())
+ Ok(flag_value.into_bytes())
}
+ _ => Err(anyhow!("aconfig does not support the creation of this storage file type")),
}
}
@@ -121,30 +122,38 @@
"com.android.aconfig.storage.test_1",
"storage_test_1.aconfig",
include_bytes!("../../tests/storage_test_1.aconfig").as_slice(),
+ "storage_test_1.value",
+ include_bytes!("../../tests/storage_test_1.values").as_slice(),
),
(
"com.android.aconfig.storage.test_2",
"storage_test_2.aconfig",
include_bytes!("../../tests/storage_test_2.aconfig").as_slice(),
+ "storage_test_2.value",
+ include_bytes!("../../tests/storage_test_2.values").as_slice(),
),
(
"com.android.aconfig.storage.test_4",
"storage_test_4.aconfig",
include_bytes!("../../tests/storage_test_4.aconfig").as_slice(),
+ "storage_test_4.value",
+ include_bytes!("../../tests/storage_test_4.values").as_slice(),
),
];
-
aconfig_files
.into_iter()
- .map(|(pkg, file, content)| {
+ .map(|(pkg, aconfig_file, aconfig_content, value_file, value_content)| {
let bytes = crate::commands::parse_flags(
pkg,
Some("system"),
vec![Input {
- source: format!("tests/{}", file).to_string(),
- reader: Box::new(content),
+ source: format!("tests/{}", aconfig_file).to_string(),
+ reader: Box::new(aconfig_content),
}],
- vec![],
+ vec![Input {
+ source: format!("tests/{}", value_file).to_string(),
+ reader: Box::new(value_content),
+ }],
crate::commands::DEFAULT_FLAG_PERMISSION,
)
.unwrap();
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index bc2da4d..4e3d987 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -17,7 +17,8 @@
use anyhow::Result;
use aconfig_storage_file::{
- get_table_size, PackageTable, PackageTableHeader, PackageTableNode, FILE_VERSION, StorageFileType
+ get_table_size, PackageTable, PackageTableHeader, PackageTableNode, StorageFileType,
+ FILE_VERSION,
};
use crate::storage::FlagPackage;
@@ -65,10 +66,10 @@
packages.iter().map(|pkg| PackageTableNodeWrapper::new(pkg, num_buckets)).collect();
// initialize all header fields
- header.bucket_offset = header.as_bytes().len() as u32;
+ header.bucket_offset = header.into_bytes().len() as u32;
header.node_offset = header.bucket_offset + num_buckets * 4;
header.file_size = header.node_offset
- + node_wrappers.iter().map(|x| x.node.as_bytes().len()).sum::<usize>() as u32;
+ + node_wrappers.iter().map(|x| x.node.into_bytes().len()).sum::<usize>() as u32;
// sort node_wrappers by bucket index for efficiency
node_wrappers.sort_by(|a, b| a.bucket_index.cmp(&b.bucket_index));
@@ -86,7 +87,7 @@
if buckets[node_bucket_idx as usize].is_none() {
buckets[node_bucket_idx as usize] = Some(offset);
}
- offset += node_wrappers[i].node.as_bytes().len() as u32;
+ offset += node_wrappers[i].node.into_bytes().len() as u32;
if let Some(index) = next_node_bucket_idx {
if index == node_bucket_idx {
diff --git a/tools/aconfig/aconfig/tests/storage_test_1.values b/tools/aconfig/aconfig/tests/storage_test_1.values
new file mode 100644
index 0000000..35548ae
--- /dev/null
+++ b/tools/aconfig/aconfig/tests/storage_test_1.values
@@ -0,0 +1,18 @@
+flag_value {
+ package: "com.android.aconfig.storage.test_1"
+ name: "enabled_rw"
+ state: ENABLED
+ permission: READ_WRITE
+}
+flag_value {
+ package: "com.android.aconfig.storage.test_1"
+ name: "disabled_rw"
+ state: DISABLED
+ permission: READ_WRITE
+}
+flag_value {
+ package: "com.android.aconfig.storage.test_1"
+ name: "enabled_ro"
+ state: ENABLED
+ permission: READ_ONLY
+}
diff --git a/tools/aconfig/aconfig/tests/storage_test_2.values b/tools/aconfig/aconfig/tests/storage_test_2.values
new file mode 100644
index 0000000..a7bb0b1
--- /dev/null
+++ b/tools/aconfig/aconfig/tests/storage_test_2.values
@@ -0,0 +1,18 @@
+flag_value {
+ package: "com.android.aconfig.storage.test_2"
+ name: "enabled_ro"
+ state: ENABLED
+ permission: READ_ONLY
+}
+flag_value {
+ package: "com.android.aconfig.storage.test_2"
+ name: "disabled_ro"
+ state: DISABLED
+ permission: READ_ONLY
+}
+flag_value {
+ package: "com.android.aconfig.storage.test_2"
+ name: "enabled_fixed_ro"
+ state: ENABLED
+ permission: READ_ONLY
+}
diff --git a/tools/aconfig/aconfig/tests/storage_test_4.values b/tools/aconfig/aconfig/tests/storage_test_4.values
new file mode 100644
index 0000000..fa21317
--- /dev/null
+++ b/tools/aconfig/aconfig/tests/storage_test_4.values
@@ -0,0 +1,12 @@
+flag_value {
+ package: "com.android.aconfig.storage.test_4"
+ name: "enabled_ro"
+ state: ENABLED
+ permission: READ_ONLY
+}
+flag_value {
+ package: "com.android.aconfig.storage.test_4"
+ name: "enabled_fixed_ro"
+ state: ENABLED
+ permission: READ_ONLY
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_info.rs b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
new file mode 100644
index 0000000..c67e70e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! flag info module defines the flag info file format and methods for serialization
+//! and deserialization
+
+use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
+use crate::{AconfigStorageError, StorageFileType};
+use anyhow::anyhow;
+use std::fmt;
+
+/// Flag info header struct
+#[derive(PartialEq)]
+pub struct FlagInfoHeader {
+ pub version: u32,
+ pub container: String,
+ pub file_type: u8,
+ pub file_size: u32,
+ pub num_flags: u32,
+ pub boolean_flag_offset: u32,
+}
+
+/// Implement debug print trait for header
+impl fmt::Debug for FlagInfoHeader {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ writeln!(
+ f,
+ "Version: {}, Container: {}, File Type: {:?}, File Size: {}",
+ self.version,
+ self.container,
+ StorageFileType::try_from(self.file_type),
+ self.file_size
+ )?;
+ writeln!(
+ f,
+ "Num of Flags: {}, Boolean Flag Offset:{}",
+ self.num_flags, self.boolean_flag_offset
+ )?;
+ Ok(())
+ }
+}
+
+impl FlagInfoHeader {
+ /// Serialize to bytes
+ pub fn into_bytes(&self) -> Vec<u8> {
+ let mut result = Vec::new();
+ result.extend_from_slice(&self.version.to_le_bytes());
+ let container_bytes = self.container.as_bytes();
+ result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes());
+ result.extend_from_slice(container_bytes);
+ result.extend_from_slice(&self.file_type.to_le_bytes());
+ result.extend_from_slice(&self.file_size.to_le_bytes());
+ result.extend_from_slice(&self.num_flags.to_le_bytes());
+ result.extend_from_slice(&self.boolean_flag_offset.to_le_bytes());
+ result
+ }
+
+ /// Deserialize from bytes
+ pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+ let mut head = 0;
+ let list = Self {
+ version: read_u32_from_bytes(bytes, &mut head)?,
+ container: read_str_from_bytes(bytes, &mut head)?,
+ file_type: read_u8_from_bytes(bytes, &mut head)?,
+ file_size: read_u32_from_bytes(bytes, &mut head)?,
+ num_flags: read_u32_from_bytes(bytes, &mut head)?,
+ boolean_flag_offset: read_u32_from_bytes(bytes, &mut head)?,
+ };
+ if list.file_type != StorageFileType::FlagInfo as u8 {
+ return Err(AconfigStorageError::BytesParseFail(anyhow!(
+ "binary file is not a flag info file"
+ )));
+ }
+ Ok(list)
+ }
+}
+
+/// bit field for flag info
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FlagInfoBit {
+ IsSticky = 0,
+ IsReadWrite = 1,
+ HasOverride = 2,
+}
+
+/// Flag info node struct
+#[derive(PartialEq, Clone)]
+pub struct FlagInfoNode {
+ pub attributes: u8,
+}
+
+/// Implement debug print trait for node
+impl fmt::Debug for FlagInfoNode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ writeln!(
+ f,
+ "sticky: {}, readwrite: {}, override: {}",
+ self.attributes & (FlagInfoBit::IsSticky as u8),
+ self.attributes & (FlagInfoBit::IsReadWrite as u8),
+ self.attributes & (FlagInfoBit::HasOverride as u8),
+ )?;
+ Ok(())
+ }
+}
+
+impl FlagInfoNode {
+ /// Serialize to bytes
+ pub fn into_bytes(&self) -> Vec<u8> {
+ let mut result = Vec::new();
+ result.extend_from_slice(&self.attributes.to_le_bytes());
+ result
+ }
+
+ /// Deserialize from bytes
+ pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+ let mut head = 0;
+ let node = Self { attributes: read_u8_from_bytes(bytes, &mut head)? };
+ Ok(node)
+ }
+}
+
+/// Flag info list struct
+#[derive(PartialEq)]
+pub struct FlagInfoList {
+ pub header: FlagInfoHeader,
+ pub nodes: Vec<FlagInfoNode>,
+}
+
+/// Implement debug print trait for flag info list
+impl fmt::Debug for FlagInfoList {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ writeln!(f, "Header:")?;
+ write!(f, "{:?}", self.header)?;
+ writeln!(f, "Nodes:")?;
+ for node in self.nodes.iter() {
+ write!(f, "{:?}", node)?;
+ }
+ Ok(())
+ }
+}
+
+impl FlagInfoList {
+ /// Serialize to bytes
+ pub fn into_bytes(&self) -> Vec<u8> {
+ [
+ self.header.into_bytes(),
+ self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
+ ]
+ .concat()
+ }
+
+ /// Deserialize from bytes
+ pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+ let header = FlagInfoHeader::from_bytes(bytes)?;
+ let num_flags = header.num_flags;
+ let mut head = header.into_bytes().len();
+ let nodes = (0..num_flags)
+ .map(|_| {
+ let node = FlagInfoNode::from_bytes(&bytes[head..])?;
+ head += node.into_bytes().len();
+ Ok(node)
+ })
+ .collect::<Result<Vec<_>, AconfigStorageError>>()
+ .map_err(|errmsg| {
+ AconfigStorageError::BytesParseFail(anyhow!(
+ "fail to parse flag info list: {}",
+ errmsg
+ ))
+ })?;
+ let list = Self { header, nodes };
+ Ok(list)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::test_utils::create_test_flag_info_list;
+
+ #[test]
+ // this test point locks down the value list serialization
+ fn test_serialization() {
+ let flag_info_list = create_test_flag_info_list();
+
+ let header: &FlagInfoHeader = &flag_info_list.header;
+ let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
+ assert!(reinterpreted_header.is_ok());
+ assert_eq!(header, &reinterpreted_header.unwrap());
+
+ let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
+ for node in nodes.iter() {
+ let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
+ assert_eq!(node, &reinterpreted_node);
+ }
+
+ let flag_info_bytes = flag_info_list.into_bytes();
+ let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
+ assert!(reinterpreted_info_list.is_ok());
+ assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
+ assert_eq!(flag_info_bytes.len() as u32, header.file_size);
+ }
+
+ #[test]
+ // this test point locks down that version number should be at the top of serialized
+ // bytes
+ fn test_version_number() {
+ let flag_info_list = create_test_flag_info_list();
+ let bytes = &flag_info_list.into_bytes();
+ let mut head = 0;
+ let version = read_u32_from_bytes(bytes, &mut head).unwrap();
+ assert_eq!(version, 1234)
+ }
+
+ #[test]
+ // this test point locks down file type check
+ fn test_file_type_check() {
+ let mut flag_info_list = create_test_flag_info_list();
+ flag_info_list.header.file_type = 123u8;
+ let error = FlagInfoList::from_bytes(&flag_info_list.into_bytes()).unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ format!("BytesParseFail(binary file is not a flag info file)")
+ );
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index f9b3158..98a1321 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -21,7 +21,7 @@
get_bucket_index, read_str_from_bytes, read_u16_from_bytes, read_u32_from_bytes,
read_u8_from_bytes,
};
-use crate::{AconfigStorageError, StorageFileType};
+use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
use anyhow::anyhow;
use std::fmt;
@@ -59,7 +59,7 @@
impl FlagTableHeader {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
result.extend_from_slice(&self.version.to_le_bytes());
let container_bytes = self.container.as_bytes();
@@ -99,7 +99,7 @@
pub struct FlagTableNode {
pub package_id: u32,
pub flag_name: String,
- pub flag_type: u16,
+ pub flag_type: StoredFlagType,
pub flag_id: u16,
pub next_offset: Option<u32>,
}
@@ -109,7 +109,7 @@
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
- "Package Id: {}, Flag: {}, Type: {}, Offset: {}, Next: {:?}",
+ "Package Id: {}, Flag: {}, Type: {:?}, Offset: {}, Next: {:?}",
self.package_id, self.flag_name, self.flag_type, self.flag_id, self.next_offset
)?;
Ok(())
@@ -118,13 +118,13 @@
impl FlagTableNode {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
result.extend_from_slice(&self.package_id.to_le_bytes());
let name_bytes = self.flag_name.as_bytes();
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
result.extend_from_slice(name_bytes);
- result.extend_from_slice(&self.flag_type.to_le_bytes());
+ result.extend_from_slice(&(self.flag_type as u16).to_le_bytes());
result.extend_from_slice(&self.flag_id.to_le_bytes());
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
result
@@ -136,7 +136,7 @@
let node = Self {
package_id: read_u32_from_bytes(bytes, &mut head)?,
flag_name: read_str_from_bytes(bytes, &mut head)?,
- flag_type: read_u16_from_bytes(bytes, &mut head)?,
+ flag_type: StoredFlagType::try_from(read_u16_from_bytes(bytes, &mut head)?)?,
flag_id: read_u16_from_bytes(bytes, &mut head)?,
next_offset: match read_u32_from_bytes(bytes, &mut head)? {
0 => None,
@@ -178,11 +178,11 @@
/// Flag table struct
impl FlagTable {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
[
- self.header.as_bytes(),
+ self.header.into_bytes(),
self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
- self.nodes.iter().map(|v| v.as_bytes()).collect::<Vec<_>>().concat(),
+ self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
]
.concat()
}
@@ -192,7 +192,7 @@
let header = FlagTableHeader::from_bytes(bytes)?;
let num_flags = header.num_flags;
let num_buckets = crate::get_table_size(num_flags)?;
- let mut head = header.as_bytes().len();
+ let mut head = header.into_bytes().len();
let buckets = (0..num_buckets)
.map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() {
0 => None,
@@ -202,7 +202,7 @@
let nodes = (0..num_flags)
.map(|_| {
let node = FlagTableNode::from_bytes(&bytes[head..])?;
- head += node.as_bytes().len();
+ head += node.into_bytes().len();
Ok(node)
})
.collect::<Result<Vec<_>, AconfigStorageError>>()
@@ -226,17 +226,17 @@
let flag_table = create_test_flag_table();
let header: &FlagTableHeader = &flag_table.header;
- let reinterpreted_header = FlagTableHeader::from_bytes(&header.as_bytes());
+ let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes());
assert!(reinterpreted_header.is_ok());
assert_eq!(header, &reinterpreted_header.unwrap());
let nodes: &Vec<FlagTableNode> = &flag_table.nodes;
for node in nodes.iter() {
- let reinterpreted_node = FlagTableNode::from_bytes(&node.as_bytes()).unwrap();
+ let reinterpreted_node = FlagTableNode::from_bytes(&node.into_bytes()).unwrap();
assert_eq!(node, &reinterpreted_node);
}
- let flag_table_bytes = flag_table.as_bytes();
+ let flag_table_bytes = flag_table.into_bytes();
let reinterpreted_table = FlagTable::from_bytes(&flag_table_bytes);
assert!(reinterpreted_table.is_ok());
assert_eq!(&flag_table, &reinterpreted_table.unwrap());
@@ -248,7 +248,7 @@
// bytes
fn test_version_number() {
let flag_table = create_test_flag_table();
- let bytes = &flag_table.as_bytes();
+ let bytes = &flag_table.into_bytes();
let mut head = 0;
let version = read_u32_from_bytes(bytes, &mut head).unwrap();
assert_eq!(version, 1234)
@@ -259,7 +259,7 @@
fn test_file_type_check() {
let mut flag_table = create_test_flag_table();
flag_table.header.file_type = 123u8;
- let error = FlagTable::from_bytes(&flag_table.as_bytes()).unwrap_err();
+ let error = FlagTable::from_bytes(&flag_table.into_bytes()).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!("BytesParseFail(binary file is not a flag map)")
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index c9d09a1..40ccb34 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -55,7 +55,7 @@
impl FlagValueHeader {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
result.extend_from_slice(&self.version.to_le_bytes());
let container_bytes = self.container.as_bytes();
@@ -108,9 +108,9 @@
impl FlagValueList {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
[
- self.header.as_bytes(),
+ self.header.into_bytes(),
self.booleans.iter().map(|&v| u8::from(v).to_le_bytes()).collect::<Vec<_>>().concat(),
]
.concat()
@@ -120,7 +120,7 @@
pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
let header = FlagValueHeader::from_bytes(bytes)?;
let num_flags = header.num_flags;
- let mut head = header.as_bytes().len();
+ let mut head = header.into_bytes().len();
let booleans =
(0..num_flags).map(|_| read_u8_from_bytes(bytes, &mut head).unwrap() == 1).collect();
let list = Self { header, booleans };
@@ -139,11 +139,11 @@
let flag_value_list = create_test_flag_value_list();
let header: &FlagValueHeader = &flag_value_list.header;
- let reinterpreted_header = FlagValueHeader::from_bytes(&header.as_bytes());
+ let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
assert!(reinterpreted_header.is_ok());
assert_eq!(header, &reinterpreted_header.unwrap());
- let flag_value_bytes = flag_value_list.as_bytes();
+ let flag_value_bytes = flag_value_list.into_bytes();
let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes);
assert!(reinterpreted_value_list.is_ok());
assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
@@ -155,7 +155,7 @@
// bytes
fn test_version_number() {
let flag_value_list = create_test_flag_value_list();
- let bytes = &flag_value_list.as_bytes();
+ let bytes = &flag_value_list.into_bytes();
let mut head = 0;
let version = read_u32_from_bytes(bytes, &mut head).unwrap();
assert_eq!(version, 1234)
@@ -166,7 +166,7 @@
fn test_file_type_check() {
let mut flag_value_list = create_test_flag_value_list();
flag_value_list.header.file_type = 123u8;
- let error = FlagValueList::from_bytes(&flag_value_list.as_bytes()).unwrap_err();
+ let error = FlagValueList::from_bytes(&flag_value_list.into_bytes()).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!("BytesParseFail(binary file is not a flag value file)")
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 24b16a1..a47926f 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -32,6 +32,7 @@
//! apis. DO NOT DIRECTLY USE THESE APIS IN YOUR SOURCE CODE. For auto generated flag apis
//! please refer to the g3doc go/android-flags
+pub mod flag_info;
pub mod flag_table;
pub mod flag_value;
pub mod package_table;
@@ -46,11 +47,12 @@
use std::hash::{Hash, Hasher};
use std::io::Read;
+pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
pub use crate::flag_value::{FlagValueHeader, FlagValueList};
pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
-use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit};
+use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit, InvalidStoredFlagType};
/// Storage file version
pub const FILE_VERSION: u32 = 1;
@@ -68,6 +70,7 @@
PackageMap = 0,
FlagMap = 1,
FlagVal = 2,
+ FlagInfo = 3,
}
impl TryFrom<&str> for StorageFileType {
@@ -78,8 +81,9 @@
"package_map" => Ok(Self::PackageMap),
"flag_map" => Ok(Self::FlagMap),
"flag_val" => Ok(Self::FlagVal),
+ "flag_info" => Ok(Self::FlagInfo),
_ => Err(anyhow!(
- "Invalid storage file type, valid types are package_map|flag_map|flag_val"
+ "Invalid storage file type, valid types are package_map|flag_map|flag_val|flag_info"
)),
}
}
@@ -93,11 +97,33 @@
x if x == Self::PackageMap as u8 => Ok(Self::PackageMap),
x if x == Self::FlagMap as u8 => Ok(Self::FlagMap),
x if x == Self::FlagVal as u8 => Ok(Self::FlagVal),
+ x if x == Self::FlagInfo as u8 => Ok(Self::FlagInfo),
_ => Err(anyhow!("Invalid storage file type")),
}
}
}
+/// Flag type enum as stored by storage file
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum StoredFlagType {
+ ReadWriteBoolean = 0,
+ ReadOnlyBoolean = 1,
+ FixedReadOnlyBoolean = 2,
+}
+
+impl TryFrom<u16> for StoredFlagType {
+ type Error = AconfigStorageError;
+
+ fn try_from(value: u16) -> Result<Self, Self::Error> {
+ match value {
+ x if x == Self::ReadWriteBoolean as u16 => Ok(Self::ReadWriteBoolean),
+ x if x == Self::ReadOnlyBoolean as u16 => Ok(Self::ReadOnlyBoolean),
+ x if x == Self::FixedReadOnlyBoolean as u16 => Ok(Self::FixedReadOnlyBoolean),
+ _ => Err(InvalidStoredFlagType(anyhow!("Invalid stored flag type"))),
+ }
+ }
+}
+
/// Get the right hash table size given number of entries in the table. Use a
/// load factor of 0.5 for performance.
pub fn get_table_size(entries: u32) -> Result<u32, AconfigStorageError> {
@@ -196,6 +222,9 @@
#[error("failed to create file")]
FileCreationFail(#[source] anyhow::Error),
+
+ #[error("invalid stored flag type")]
+ InvalidStoredFlagType(#[source] anyhow::Error),
}
/// Read in storage file as bytes
@@ -219,7 +248,7 @@
package_map: &str,
flag_map: &str,
flag_val: &str,
-) -> Result<Vec<(String, bool)>, AconfigStorageError> {
+) -> Result<Vec<(String, String, bool)>, AconfigStorageError> {
let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?;
@@ -232,10 +261,9 @@
let mut flags = Vec::new();
for node in flag_table.nodes.iter() {
let (package_name, package_offset) = package_info[node.package_id as usize];
- let full_flag_name = String::from(package_name) + "/" + &node.flag_name;
let flag_offset = package_offset + node.flag_id as u32;
let flag_value = flag_value_list.booleans[flag_offset as usize];
- flags.push((full_flag_name, flag_value));
+ flags.push((String::from(package_name), node.flag_name.clone(), flag_value));
}
flags.sort_by(|v1, v2| v1.0.cmp(&v2.0));
@@ -254,10 +282,10 @@
// this test point locks down the flag list api
fn test_list_flag() {
let package_table =
- write_bytes_to_temp_file(&create_test_package_table().as_bytes()).unwrap();
- let flag_table = write_bytes_to_temp_file(&create_test_flag_table().as_bytes()).unwrap();
+ write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
+ let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
let flag_value_list =
- write_bytes_to_temp_file(&create_test_flag_value_list().as_bytes()).unwrap();
+ write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap();
let package_table_path = package_table.path().display().to_string();
let flag_table_path = flag_table.path().display().to_string();
@@ -266,14 +294,30 @@
let flags =
list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap();
let expected = [
- (String::from("com.android.aconfig.storage.test_1/disabled_rw"), false),
- (String::from("com.android.aconfig.storage.test_1/enabled_ro"), true),
- (String::from("com.android.aconfig.storage.test_1/enabled_rw"), false),
- (String::from("com.android.aconfig.storage.test_2/disabled_ro"), false),
- (String::from("com.android.aconfig.storage.test_2/enabled_fixed_ro"), true),
- (String::from("com.android.aconfig.storage.test_2/enabled_ro"), true),
- (String::from("com.android.aconfig.storage.test_4/enabled_fixed_ro"), false),
- (String::from("com.android.aconfig.storage.test_4/enabled_ro"), true),
+ (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_ro"), true),
+ (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_rw"), false),
+ (
+ String::from("com.android.aconfig.storage.test_1"),
+ String::from("disabled_rw"),
+ false,
+ ),
+ (
+ String::from("com.android.aconfig.storage.test_2"),
+ String::from("disabled_ro"),
+ false,
+ ),
+ (
+ String::from("com.android.aconfig.storage.test_2"),
+ String::from("enabled_fixed_ro"),
+ true,
+ ),
+ (String::from("com.android.aconfig.storage.test_2"), String::from("enabled_ro"), true),
+ (String::from("com.android.aconfig.storage.test_4"), String::from("enabled_ro"), true),
+ (
+ String::from("com.android.aconfig.storage.test_4"),
+ String::from("enabled_fixed_ro"),
+ false,
+ ),
];
assert_eq!(flags, expected);
}
diff --git a/tools/aconfig/aconfig_storage_file/src/main.rs b/tools/aconfig/aconfig_storage_file/src/main.rs
index 293d018..12e0024 100644
--- a/tools/aconfig/aconfig_storage_file/src/main.rs
+++ b/tools/aconfig/aconfig_storage_file/src/main.rs
@@ -17,8 +17,8 @@
//! `aconfig-storage` is a debugging tool to parse storage files
use aconfig_storage_file::{
- list_flags, read_file_to_bytes, AconfigStorageError, FlagTable, FlagValueList, PackageTable,
- StorageFileType,
+ list_flags, read_file_to_bytes, AconfigStorageError, FlagInfoList, FlagTable, FlagValueList,
+ PackageTable, StorageFileType,
};
use clap::{builder::ArgAction, Arg, Command};
@@ -67,6 +67,10 @@
let flag_value = FlagValueList::from_bytes(&bytes)?;
println!("{:?}", flag_value);
}
+ StorageFileType::FlagInfo => {
+ let flag_info = FlagInfoList::from_bytes(&bytes)?;
+ println!("{:?}", flag_info);
+ }
}
Ok(())
}
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index 7cb60eb..e377115 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -56,7 +56,7 @@
impl PackageTableHeader {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
result.extend_from_slice(&self.version.to_le_bytes());
let container_bytes = self.container.as_bytes();
@@ -116,7 +116,7 @@
impl PackageTableNode {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
let mut result = Vec::new();
let name_bytes = self.package_name.as_bytes();
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
@@ -175,11 +175,11 @@
impl PackageTable {
/// Serialize to bytes
- pub fn as_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self) -> Vec<u8> {
[
- self.header.as_bytes(),
+ self.header.into_bytes(),
self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
- self.nodes.iter().map(|v| v.as_bytes()).collect::<Vec<_>>().concat(),
+ self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
]
.concat()
}
@@ -189,7 +189,7 @@
let header = PackageTableHeader::from_bytes(bytes)?;
let num_packages = header.num_packages;
let num_buckets = crate::get_table_size(num_packages)?;
- let mut head = header.as_bytes().len();
+ let mut head = header.into_bytes().len();
let buckets = (0..num_buckets)
.map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() {
0 => None,
@@ -199,7 +199,7 @@
let nodes = (0..num_packages)
.map(|_| {
let node = PackageTableNode::from_bytes(&bytes[head..])?;
- head += node.as_bytes().len();
+ head += node.into_bytes().len();
Ok(node)
})
.collect::<Result<Vec<_>, AconfigStorageError>>()
@@ -225,17 +225,17 @@
fn test_serialization() {
let package_table = create_test_package_table();
let header: &PackageTableHeader = &package_table.header;
- let reinterpreted_header = PackageTableHeader::from_bytes(&header.as_bytes());
+ let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes());
assert!(reinterpreted_header.is_ok());
assert_eq!(header, &reinterpreted_header.unwrap());
let nodes: &Vec<PackageTableNode> = &package_table.nodes;
for node in nodes.iter() {
- let reinterpreted_node = PackageTableNode::from_bytes(&node.as_bytes()).unwrap();
+ let reinterpreted_node = PackageTableNode::from_bytes(&node.into_bytes()).unwrap();
assert_eq!(node, &reinterpreted_node);
}
- let package_table_bytes = package_table.as_bytes();
+ let package_table_bytes = package_table.into_bytes();
let reinterpreted_table = PackageTable::from_bytes(&package_table_bytes);
assert!(reinterpreted_table.is_ok());
assert_eq!(&package_table, &reinterpreted_table.unwrap());
@@ -247,7 +247,7 @@
// bytes
fn test_version_number() {
let package_table = create_test_package_table();
- let bytes = &package_table.as_bytes();
+ let bytes = &package_table.into_bytes();
let mut head = 0;
let version = read_u32_from_bytes(bytes, &mut head).unwrap();
assert_eq!(version, 1234)
@@ -258,7 +258,7 @@
fn test_file_type_check() {
let mut package_table = create_test_package_table();
package_table.header.file_type = 123u8;
- let error = PackageTable::from_bytes(&package_table.as_bytes()).unwrap_err();
+ let error = PackageTable::from_bytes(&package_table.into_bytes()).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!("BytesParseFail(binary file is not a package map)")
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 586bb4c..4097ba6 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
use crate::flag_value::{FlagValueHeader, FlagValueList};
use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
-use crate::{AconfigStorageError, StorageFileType};
+use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
use anyhow::anyhow;
use std::io::Write;
@@ -65,7 +66,13 @@
flag_id: u16,
next_offset: Option<u32>,
) -> Self {
- Self { package_id, flag_name: flag_name.to_string(), flag_type, flag_id, next_offset }
+ Self {
+ package_id,
+ flag_name: flag_name.to_string(),
+ flag_type: StoredFlagType::try_from(flag_type).unwrap(),
+ flag_id,
+ next_offset,
+ }
}
}
@@ -124,6 +131,19 @@
FlagValueList { header, booleans }
}
+pub(crate) fn create_test_flag_info_list() -> FlagInfoList {
+ let header = FlagInfoHeader {
+ version: 1234,
+ container: String::from("system"),
+ file_type: StorageFileType::FlagInfo as u8,
+ file_size: 35,
+ num_flags: 8,
+ boolean_flag_offset: 27,
+ };
+ let nodes: Vec<FlagInfoNode> = vec![FlagInfoNode { attributes: 0 }; 8];
+ FlagInfoList { header, nodes }
+}
+
pub(crate) fn write_bytes_to_temp_file(bytes: &[u8]) -> Result<NamedTempFile, AconfigStorageError> {
let mut file = NamedTempFile::new().map_err(|_| {
AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
diff --git a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
index ea756b3..2213831 100644
--- a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
@@ -67,18 +67,18 @@
static Result<MappedStorageFile> map_storage_file(std::string const& file) {
int fd = open(file.c_str(), O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
if (fd == -1) {
- return Error() << "failed to open " << file;
+ return ErrnoError() << "failed to open " << file;
};
struct stat fd_stat;
if (fstat(fd, &fd_stat) < 0) {
- return Error() << "fstat failed";
+ return ErrnoError() << "fstat failed";
}
size_t file_size = fd_stat.st_size;
void* const map_result = mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
if (map_result == MAP_FAILED) {
- return Error() << "mmap failed";
+ return ErrnoError() << "mmap failed";
}
auto mapped_file = MappedStorageFile();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
index 43977ee..8ce2397 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
@@ -65,7 +65,7 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::{FlagTable, StorageFileType};
+ use aconfig_storage_file::{FlagTable, StorageFileType, StoredFlagType};
// create test baseline, syntactic sugar
fn new_expected_node(
@@ -78,7 +78,7 @@
FlagTableNode {
package_id,
flag_name: flag_name.to_string(),
- flag_type,
+ flag_type: StoredFlagType::try_from(flag_type).unwrap(),
flag_id,
next_offset,
}
@@ -129,7 +129,7 @@
#[test]
// this test point locks down table query
fn test_flag_query() {
- let flag_table = create_test_flag_table().as_bytes();
+ let flag_table = create_test_flag_table().into_bytes();
let baseline = vec![
(0, "enabled_ro", 1u16),
(0, "enabled_rw", 2u16),
@@ -150,7 +150,7 @@
#[test]
// this test point locks down table query of a non exist flag
fn test_not_existed_flag_query() {
- let flag_table = create_test_flag_table().as_bytes();
+ let flag_table = create_test_flag_table().into_bytes();
let flag_offset = find_flag_offset(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
assert_eq!(flag_offset, None);
let flag_offset = find_flag_offset(&flag_table[..], 2, "disabled_rw").unwrap();
@@ -162,7 +162,7 @@
fn test_higher_version_storage_file() {
let mut table = create_test_flag_table();
table.header.version = crate::FILE_VERSION + 1;
- let flag_table = table.as_bytes();
+ let flag_table = table.into_bytes();
let error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
assert_eq!(
format!("{:?}", error),
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
index 88d2397..964cd69 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
@@ -66,7 +66,7 @@
#[test]
// this test point locks down flag value query
fn test_flag_value_query() {
- let flag_value_list = create_test_flag_value_list().as_bytes();
+ let flag_value_list = create_test_flag_value_list().into_bytes();
let baseline: Vec<bool> = vec![false, true, false, false, true, true, false, true];
for (offset, expected_value) in baseline.into_iter().enumerate() {
let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
@@ -77,7 +77,7 @@
#[test]
// this test point locks down query beyond the end of boolean section
fn test_boolean_out_of_range() {
- let flag_value_list = create_test_flag_value_list().as_bytes();
+ let flag_value_list = create_test_flag_value_list().into_bytes();
let error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
assert_eq!(
format!("{:?}", error),
@@ -90,7 +90,7 @@
fn test_higher_version_storage_file() {
let mut value_list = create_test_flag_value_list();
value_list.header.version = crate::FILE_VERSION + 1;
- let flag_value = value_list.as_bytes();
+ let flag_value = value_list.into_bytes();
let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
assert_eq!(
format!("{:?}", error),
diff --git a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
index 86c6a1b..51354db 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
@@ -91,6 +91,9 @@
StorageFileType::PackageMap => unsafe { map_file(files_location.package_map()) },
StorageFileType::FlagMap => unsafe { map_file(files_location.flag_map()) },
StorageFileType::FlagVal => unsafe { map_file(files_location.flag_val()) },
+ StorageFileType::FlagInfo => {
+ Err(MapFileFail(anyhow!("TODO: add support for flag info file")))
+ }
}
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
index 3587e10..190de99 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
@@ -110,7 +110,7 @@
#[test]
// this test point locks down table query
fn test_package_query() {
- let package_table = create_test_package_table().as_bytes();
+ let package_table = create_test_package_table().into_bytes();
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap()
@@ -135,7 +135,7 @@
// this test point locks down table query of a non exist package
fn test_not_existed_package_query() {
// this will land at an empty bucket
- let package_table = create_test_package_table().as_bytes();
+ let package_table = create_test_package_table().into_bytes();
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_3").unwrap();
assert_eq!(package_offset, None);
@@ -150,7 +150,7 @@
fn test_higher_version_storage_file() {
let mut table = create_test_package_table();
table.header.version = crate::FILE_VERSION + 1;
- let package_table = table.as_bytes();
+ let package_table = table.into_bytes();
let error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap_err();
assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
index 391b305..e863c0e 100644
--- a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
+++ b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
@@ -58,24 +58,24 @@
static Result<MappedFlagValueFile> map_storage_file(std::string const& file) {
struct stat file_stat;
if (stat(file.c_str(), &file_stat) < 0) {
- return Error() << "fstat failed";
+ return ErrnoError() << "stat failed";
}
if ((file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) {
- return Error() << "cannot map nonwriteable file";
+ return ErrnoError() << "cannot map nonwriteable file";
}
size_t file_size = file_stat.st_size;
const int fd = open(file.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
- return Error() << "failed to open " << file;
+ return ErrnoError() << "failed to open " << file;
};
void* const map_result =
mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map_result == MAP_FAILED) {
- return Error() << "mmap failed";
+ return ErrnoError() << "mmap failed";
}
auto mapped_file = MappedFlagValueFile();
@@ -95,7 +95,12 @@
if (!file_result.ok()) {
return Error() << file_result.error();
}
- return map_storage_file(*file_result);
+ auto mapped_result = map_storage_file(*file_result);
+ if (!mapped_result.ok()) {
+ return Error() << "failed to map " << *file_result << ": "
+ << mapped_result.error();
+ }
+ return *mapped_result;
}
} // namespace private internal api
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
index c2375dd..4cb7939 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
@@ -71,7 +71,7 @@
fn test_boolean_flag_value_update() {
let flag_value_list = create_test_flag_value_list();
let value_offset = flag_value_list.header.boolean_value_offset;
- let mut content = flag_value_list.as_bytes();
+ let mut content = flag_value_list.into_bytes();
let true_byte = u8::from(true).to_le_bytes()[0];
let false_byte = u8::from(false).to_le_bytes()[0];
@@ -87,7 +87,7 @@
#[test]
// this test point locks down update beyond the end of boolean section
fn test_boolean_out_of_range() {
- let mut flag_value_list = create_test_flag_value_list().as_bytes();
+ let mut flag_value_list = create_test_flag_value_list().into_bytes();
let error = update_boolean_flag_value(&mut flag_value_list[..], 8, true).unwrap_err();
assert_eq!(
format!("{:?}", error),
@@ -100,7 +100,7 @@
fn test_higher_version_storage_file() {
let mut value_list = create_test_flag_value_list();
value_list.header.version = FILE_VERSION + 1;
- let mut flag_value = value_list.as_bytes();
+ let mut flag_value = value_list.into_bytes();
let error = update_boolean_flag_value(&mut flag_value[..], 4, true).unwrap_err();
assert_eq!(
format!("{:?}", error),
diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp
index b36aa34..4920a6f 100644
--- a/tools/aconfig/aflags/Android.bp
+++ b/tools/aconfig/aflags/Android.bp
@@ -10,6 +10,8 @@
srcs: ["src/main.rs"],
rustlibs: [
"libaconfig_protos",
+ "libaconfig_storage_read_api",
+ "libaconfig_storage_file",
"libanyhow",
"libclap",
"libnix",
diff --git a/tools/aconfig/aflags/Cargo.toml b/tools/aconfig/aflags/Cargo.toml
index 6a08da6..cce7f9d 100644
--- a/tools/aconfig/aflags/Cargo.toml
+++ b/tools/aconfig/aflags/Cargo.toml
@@ -6,8 +6,10 @@
[dependencies]
anyhow = "1.0.69"
paste = "1.0.11"
-clap = { version = "4", features = ["derive"] }
protobuf = "3.2.0"
regex = "1.10.3"
aconfig_protos = { path = "../aconfig_protos" }
nix = { version = "0.28.0", features = ["user"] }
+aconfig_storage_file = { version = "0.1.0", path = "../aconfig_storage_file" }
+aconfig_storage_read_api = { version = "0.1.0", path = "../aconfig_storage_read_api" }
+clap = {version = "4.5.2" }
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
new file mode 100644
index 0000000..1d73688
--- /dev/null
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -0,0 +1,56 @@
+use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
+use anyhow::{anyhow, Result};
+
+use std::fs::File;
+use std::io::Read;
+
+pub struct AconfigStorageSource {}
+
+use aconfig_storage_file::protos::ProtoStorageFiles;
+
+static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
+
+impl FlagSource for AconfigStorageSource {
+ fn list_flags() -> Result<Vec<Flag>> {
+ let mut result = Vec::new();
+
+ let mut file = File::open(STORAGE_INFO_FILE_PATH)?;
+ let mut bytes = Vec::new();
+ file.read_to_end(&mut bytes)?;
+ let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;
+
+ for file_info in storage_file_info.files {
+ let package_map =
+ file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
+ let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
+ let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
+ let container =
+ file_info.container.ok_or(anyhow!("storage file is missing container"))?;
+
+ for (package, name, val) in
+ aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)?
+ {
+ result.push(Flag {
+ name: name.to_string(),
+ package: package.to_string(),
+ value: FlagValue::try_from(val.to_string().as_str())?,
+ container: container.to_string(),
+
+ // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
+ namespace: "-".to_string(),
+
+ // TODO(b/324436145): Populate with real values once API is available.
+ staged_value: None,
+ permission: FlagPermission::ReadOnly,
+ value_picked_from: ValuePickedFrom::Default,
+ });
+ }
+ }
+
+ Ok(result)
+ }
+
+ fn override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()> {
+ todo!()
+ }
+}
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index 808ffa0..1c453c5 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -22,6 +22,9 @@
mod device_config_source;
use device_config_source::DeviceConfigSource;
+mod aconfig_storage_source;
+use aconfig_storage_source::AconfigStorageSource;
+
#[derive(Clone, PartialEq, Debug)]
enum FlagPermission {
ReadOnly,
@@ -109,6 +112,11 @@
fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
}
+enum FlagSourceType {
+ DeviceConfig,
+ AconfigStorage,
+}
+
const ABOUT_TEXT: &str = "Tool for reading and writing flags.
Rows in the table from the `list` command follow this format:
@@ -139,7 +147,11 @@
#[derive(Parser, Debug)]
enum Command {
/// List all aconfig flags on this device.
- List,
+ List {
+ /// Read from the new flag storage.
+ #[clap(long)]
+ use_new_storage: bool,
+ },
/// Enable an aconfig flag on this device, on the next boot.
Enable {
@@ -201,8 +213,11 @@
Ok(())
}
-fn list() -> Result<String> {
- let flags = DeviceConfigSource::list_flags()?;
+fn list(source_type: FlagSourceType) -> Result<String> {
+ let flags = match source_type {
+ FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?,
+ FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?,
+ };
let padding_info = PaddingInfo {
longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
@@ -234,7 +249,8 @@
fn main() {
let cli = Cli::parse();
let output = match cli.command {
- Command::List => list().map(Some),
+ Command::List { use_new_storage: true } => list(FlagSourceType::AconfigStorage).map(Some),
+ Command::List { use_new_storage: false } => list(FlagSourceType::DeviceConfig).map(Some),
Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
};
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index c0ff5d2..67438e6 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -872,6 +872,7 @@
target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
if OPTIONS.disable_vabc and target_info.is_release_key:
raise ValueError("Disabling VABC on release-key builds is not supported.")
+
ValidateCompressionParam(target_info)
vabc_compression_param = target_info.vabc_compression_param
@@ -907,7 +908,6 @@
logger.info("Source build and target build use different compression methods {} vs {}, default to source builds parameter {}".format(
source_info.vabc_compression_param, target_info.vabc_compression_param, source_info.vabc_compression_param))
vabc_compression_param = source_info.vabc_compression_param
-
# Virtual AB Cow version 3 is introduced in Android U with improved memory
# and install time performance. All OTA's with
# both the source build and target build with VIRTUAL_AB_COW_VERSION = 3
@@ -918,6 +918,7 @@
elif source_info.vabc_cow_version != target_info.vabc_cow_version:
logger.info("Source and Target have different cow VABC_COW_VERSION specified, default to minimum version")
OPTIONS.vabc_cow_version = min(source_info.vabc_cow_version, target_info.vabc_cow_version)
+
# Virtual AB Compression was introduced in Androd S.
# Later, we backported VABC to Android R. But verity support was not
# backported, so if VABC is used and we are on Android R, disable
@@ -930,6 +931,19 @@
assert "ab_partitions" in OPTIONS.info_dict, \
"META/ab_partitions.txt is required for ab_update."
source_info = None
+ if not target_info.vabc_cow_version:
+ OPTIONS.vabc_cow_version = 2
+ elif target_info.vabc_cow_version >= "3" and target_info.vendor_api_level < 35:
+ logger.warning(
+ "This full OTA is configured to use VABC cow version"
+ " 3 which is supported since"
+ " Android API level 35, but device is "
+ "launched with {} . If this full OTA is"
+ " served to a device running old build, OTA might fail due to "
+ "unsupported vabc cow version. For safety, version 2 is used because "
+ "it's supported since day 1.".format(
+ target_info.vendor_api_level))
+ OPTIONS.vabc_cow_version = 2
if OPTIONS.vabc_compression_param is None and vabc_compression_param:
minimum_api_level_required = VABC_COMPRESSION_PARAM_SUPPORT[
vabc_compression_param]