aconfig: update storage read api

With the update to store flag index instead of flag byte offset in
storage file. We need to update flag read api accordingly.

Bug: b/321077378
Test: atest -c
Change-Id: Iccbf939fc5b7fe0ce0f2c33f7e3aa403c268120a
This commit is contained in:
Dennis Shen 2024-04-08 18:15:19 +00:00
parent a8ba164422
commit b18227e8d8
9 changed files with 256 additions and 236 deletions

View file

@ -126,50 +126,50 @@ Result<uint32_t> get_storage_file_version(
}
}
/// Get package offset
Result<PackageOffset> get_package_offset(
/// Get package context
Result<PackageReadContext> get_package_read_context(
MappedStorageFile const& file,
std::string const& package) {
auto content = rust::Slice<const uint8_t>(
static_cast<uint8_t*>(file.file_ptr), file.file_size);
auto offset_cxx = get_package_offset_cxx(content, rust::Str(package.c_str()));
if (offset_cxx.query_success) {
auto offset = PackageOffset();
offset.package_exists = offset_cxx.package_exists;
offset.package_id = offset_cxx.package_id;
offset.boolean_offset = offset_cxx.boolean_offset;
return offset;
auto context_cxx = get_package_read_context_cxx(content, rust::Str(package.c_str()));
if (context_cxx.query_success) {
auto context = PackageReadContext();
context.package_exists = context_cxx.package_exists;
context.package_id = context_cxx.package_id;
context.boolean_start_index = context_cxx.boolean_start_index;
return context;
} else {
return Error() << offset_cxx.error_message;
return Error() << context_cxx.error_message;
}
}
/// Get flag offset
Result<FlagOffset> get_flag_offset(
/// Get flag read context
Result<FlagReadContext> get_flag_read_context(
MappedStorageFile const& file,
uint32_t package_id,
std::string const& flag_name){
auto content = rust::Slice<const uint8_t>(
static_cast<uint8_t*>(file.file_ptr), file.file_size);
auto offset_cxx = get_flag_offset_cxx(content, package_id, rust::Str(flag_name.c_str()));
if (offset_cxx.query_success) {
auto offset = FlagOffset();
offset.flag_exists = offset_cxx.flag_exists;
offset.flag_type = static_cast<StoredFlagType>(offset_cxx.flag_type);
offset.flag_id = offset_cxx.flag_id;
return offset;
auto context_cxx = get_flag_read_context_cxx(content, package_id, rust::Str(flag_name.c_str()));
if (context_cxx.query_success) {
auto context = FlagReadContext();
context.flag_exists = context_cxx.flag_exists;
context.flag_type = static_cast<StoredFlagType>(context_cxx.flag_type);
context.flag_index = context_cxx.flag_index;
return context;
} else {
return Error() << offset_cxx.error_message;
return Error() << context_cxx.error_message;
}
}
/// Get boolean flag value
Result<bool> get_boolean_flag_value(
MappedStorageFile const& file,
uint32_t offset) {
uint32_t index) {
auto content = rust::Slice<const uint8_t>(
static_cast<uint8_t*>(file.file_ptr), file.file_size);
auto value_cxx = get_boolean_flag_value_cxx(content, offset);
auto value_cxx = get_boolean_flag_value_cxx(content, index);
if (value_cxx.query_success) {
return value_cxx.flag_value;
} else {
@ -180,10 +180,10 @@ Result<bool> get_boolean_flag_value(
/// Get boolean flag attribute
Result<uint8_t> get_boolean_flag_attribute(
MappedStorageFile const& file,
uint32_t offset) {
uint32_t index) {
auto content = rust::Slice<const uint8_t>(
static_cast<uint8_t*>(file.file_ptr), file.file_size);
auto info_cxx = get_boolean_flag_attribute_cxx(content, offset);
auto info_cxx = get_boolean_flag_attribute_cxx(content, index);
if (info_cxx.query_success) {
return info_cxx.flag_attribute;
} else {

View file

@ -20,11 +20,11 @@ struct MappedStorageFile {
size_t file_size;
};
/// Package offset query result
struct PackageOffset {
/// Package read context query result
struct PackageReadContext {
bool package_exists;
uint32_t package_id;
uint32_t boolean_offset;
uint32_t boolean_start_index;
};
/// Flag type enum, to be consistent with the one defined in aconfig_storage_file/src/lib.rs
@ -34,11 +34,11 @@ enum StoredFlagType {
FixedReadOnlyBoolean = 2,
};
/// Flag offset query result
struct FlagOffset {
/// Flag read context query result
struct FlagReadContext {
bool flag_exists;
StoredFlagType flag_type;
uint16_t flag_id;
uint16_t flag_index;
};
/// DO NOT USE APIS IN THE FOLLOWING NAMESPACE DIRECTLY
@ -65,31 +65,31 @@ android::base::Result<MappedStorageFile> get_mapped_file(
android::base::Result<uint32_t> get_storage_file_version(
std::string const& file_path);
/// Get package offset
/// Get package read context
/// \input file: mapped storage file
/// \input package: the flag package name
/// \returns a package offset
android::base::Result<PackageOffset> get_package_offset(
/// \returns a package read context
android::base::Result<PackageReadContext> get_package_read_context(
MappedStorageFile const& file,
std::string const& package);
/// Get flag offset
/// Get flag read context
/// \input file: mapped storage file
/// \input package_id: the flag package id obtained from package offset query
/// \input flag_name: flag name
/// \returns the flag offset
android::base::Result<FlagOffset> get_flag_offset(
/// \returns the flag read context
android::base::Result<FlagReadContext> get_flag_read_context(
MappedStorageFile const& file,
uint32_t package_id,
std::string const& flag_name);
/// Get boolean flag value
/// \input file: mapped storage file
/// \input offset: the boolean flag value offset in the file
/// \input index: the boolean flag index in the file
/// \returns the boolean flag value
android::base::Result<bool> get_boolean_flag_value(
MappedStorageFile const& file,
uint32_t offset);
uint32_t index);
/// Flag info enum, to be consistent with the one defined in aconfig_storage_file/src/lib.rs
enum FlagInfoBit {
@ -100,9 +100,9 @@ enum FlagInfoBit {
/// Get boolean flag attribute
/// \input file: mapped storage file
/// \input offset: the boolean flag info offset in the file
/// \input index: the boolean flag index in the file
/// \returns the boolean flag attribute
android::base::Result<uint8_t> get_boolean_flag_attribute(
MappedStorageFile const& file,
uint32_t offset);
uint32_t index);
} // namespace aconfig_storage

View file

@ -21,10 +21,7 @@ use aconfig_storage_file::{flag_info::FlagInfoHeader, read_u8_from_bytes};
use anyhow::anyhow;
/// Get flag attribute bitfield
pub fn find_boolean_flag_attribute(
buf: &[u8],
flag_offset: u32,
) -> Result<u8, AconfigStorageError> {
pub fn find_boolean_flag_attribute(buf: &[u8], flag_index: u32) -> Result<u8, AconfigStorageError> {
let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
if interpreted_header.version > crate::FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
@ -34,8 +31,8 @@ pub fn find_boolean_flag_attribute(
)));
}
let mut head = (interpreted_header.boolean_flag_offset + flag_offset) as usize;
// Find the byte offset to the flag info, each flag info now takes one byte
let mut head = (interpreted_header.boolean_flag_offset + flag_index) as usize;
if head >= interpreted_header.file_size as usize {
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
"Flag info offset goes beyond the end of the file."

View file

@ -24,17 +24,17 @@ use anyhow::anyhow;
/// Flag table query return
#[derive(PartialEq, Debug)]
pub struct FlagOffset {
pub struct FlagReadContext {
pub flag_type: StoredFlagType,
pub flag_id: u16,
pub flag_index: u16,
}
/// Query flag within package offset
pub fn find_flag_offset(
/// Query flag read context: flag type and within package flag index
pub fn find_flag_read_context(
buf: &[u8],
package_id: u32,
flag: &str,
) -> Result<Option<FlagOffset>, AconfigStorageError> {
) -> Result<Option<FlagReadContext>, AconfigStorageError> {
let interpreted_header = FlagTableHeader::from_bytes(buf)?;
if interpreted_header.version > crate::FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
@ -58,9 +58,9 @@ pub fn find_flag_offset(
loop {
let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
if interpreted_node.package_id == package_id && interpreted_node.flag_name == flag {
return Ok(Some(FlagOffset {
return Ok(Some(FlagReadContext {
flag_type: interpreted_node.flag_type,
flag_id: interpreted_node.flag_id,
flag_index: interpreted_node.flag_index,
}));
}
match interpreted_node.next_offset {
@ -89,11 +89,11 @@ mod tests {
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
];
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
let flag_offset =
find_flag_offset(&flag_table[..], package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_offset.flag_type, flag_type);
assert_eq!(flag_offset.flag_id, flag_id);
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
let flag_context =
find_flag_read_context(&flag_table[..], package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_context.flag_type, flag_type);
assert_eq!(flag_context.flag_index, flag_index);
}
}
@ -101,10 +101,10 @@ mod tests {
// 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().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();
assert_eq!(flag_offset, None);
let flag_context = find_flag_read_context(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
assert_eq!(flag_context, None);
let flag_context = find_flag_read_context(&flag_table[..], 2, "disabled_rw").unwrap();
assert_eq!(flag_context, None);
}
#[test]
@ -113,7 +113,7 @@ mod tests {
let mut table = create_test_flag_table();
table.header.version = crate::FILE_VERSION + 1;
let flag_table = table.into_bytes();
let error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
let error = find_flag_read_context(&flag_table[..], 0, "enabled_ro").unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(

View file

@ -21,7 +21,7 @@ use aconfig_storage_file::{flag_value::FlagValueHeader, read_u8_from_bytes};
use anyhow::anyhow;
/// Query flag value
pub fn find_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool, AconfigStorageError> {
pub fn find_boolean_flag_value(buf: &[u8], flag_index: u32) -> Result<bool, AconfigStorageError> {
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
if interpreted_header.version > crate::FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
@ -31,10 +31,8 @@ pub fn find_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool, Aco
)));
}
let mut head = (interpreted_header.boolean_value_offset + flag_offset) as usize;
// TODO: right now, there is only boolean flags, with more flag value types added
// later, the end of boolean flag value section should be updated (b/322826265).
// Find byte offset to the flag value, each boolean flag cost one byte to store
let mut head = (interpreted_header.boolean_value_offset + flag_index) as usize;
if head >= interpreted_header.file_size as usize {
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
"Flag value offset goes beyond the end of the file."

View file

@ -17,14 +17,16 @@
//! `aconfig_storage_read_api` is a crate that defines read apis to read flags from storage
//! files. It provides four apis to interface with storage files:
//!
//! 1, function to get package flag value start offset
//! pub fn get_package_offset(container: &str, package: &str) -> `Result<Option<PackageOffset>>>`
//! 1, function to get package read context
//! pub fn get_packager_read_context(container: &str, package: &str)
//! -> `Result<Option<PackageReadContext>>>`
//!
//! 2, function to get flag offset within a specific package
//! pub fn get_flag_offset(container: &str, package_id: u32, flag: &str) -> `Result<Option<u16>>>`
//! 2, function to get flag read context
//! pub fn get_flag_read_context(container: &str, package_id: u32, flag: &str)
//! -> `Result<Option<FlagReadContext>>>`
//!
//! 3, function to get the actual flag value given the global offset (combined package and
//! flag offset).
//! 3, function to get the actual flag value given the global index (combined package and
//! flag index).
//! pub fn get_boolean_flag_value(container: &str, offset: u32) -> `Result<bool>`
//!
//! 4, function to get storage file version without mmapping the file.
@ -44,14 +46,14 @@ pub mod package_table_query;
mod test_utils;
pub use aconfig_storage_file::{AconfigStorageError, StorageFileType};
pub use flag_table_query::FlagOffset;
pub use package_table_query::PackageOffset;
pub use flag_table_query::FlagReadContext;
pub use package_table_query::PackageReadContext;
use aconfig_storage_file::{read_u32_from_bytes, FILE_VERSION};
use flag_info_query::find_boolean_flag_attribute;
use flag_table_query::find_flag_offset;
use flag_table_query::find_flag_read_context;
use flag_value_query::find_boolean_flag_value;
use package_table_query::find_package_offset;
use package_table_query::find_package_read_context;
use anyhow::anyhow;
use memmap2::Mmap;
@ -79,50 +81,50 @@ pub unsafe fn get_mapped_storage_file(
unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION_FILE, container, file_type) }
}
/// Get package start offset for flags.
/// Get package read context for a specific package.
///
/// \input file: mapped package file
/// \input package: package name
///
/// \return
/// If a package is found, it returns Ok(Some(PackageOffset))
/// If a package is found, it returns Ok(Some(PackageReadContext))
/// If a package is not found, it returns Ok(None)
/// If errors out, it returns an Err(errmsg)
pub fn get_package_offset(
pub fn get_package_read_context(
file: &Mmap,
package: &str,
) -> Result<Option<PackageOffset>, AconfigStorageError> {
find_package_offset(file, package)
) -> Result<Option<PackageReadContext>, AconfigStorageError> {
find_package_read_context(file, package)
}
/// Get flag offset within a package given.
/// Get flag read context for a specific flag.
///
/// \input file: mapped flag file
/// \input package_id: package id obtained from package mapping file
/// \input flag: flag name
///
/// \return
/// If a flag is found, it returns Ok(Some(u16))
/// If a flag is found, it returns Ok(Some(FlagReadContext))
/// If a flag is not found, it returns Ok(None)
/// If errors out, it returns an Err(errmsg)
pub fn get_flag_offset(
pub fn get_flag_read_context(
file: &Mmap,
package_id: u32,
flag: &str,
) -> Result<Option<FlagOffset>, AconfigStorageError> {
find_flag_offset(file, package_id, flag)
) -> Result<Option<FlagReadContext>, AconfigStorageError> {
find_flag_read_context(file, package_id, flag)
}
/// Get the boolean flag value.
///
/// \input file: mapped flag file
/// \input offset: flag value offset
/// \input index: boolean flag offset
///
/// \return
/// If the provide offset is valid, it returns the boolean flag value, otherwise it
/// returns the error message.
pub fn get_boolean_flag_value(file: &Mmap, offset: u32) -> Result<bool, AconfigStorageError> {
find_boolean_flag_value(file, offset)
pub fn get_boolean_flag_value(file: &Mmap, index: u32) -> Result<bool, AconfigStorageError> {
find_boolean_flag_value(file, index)
}
/// Get storage file version number
@ -150,13 +152,13 @@ pub fn get_storage_file_version(file_path: &str) -> Result<u32, AconfigStorageEr
/// Get the boolean flag attribute.
///
/// \input file: mapped flag info file
/// \input offset: boolean flag offset
/// \input index: boolean flag index
///
/// \return
/// If the provide offset is valid, it returns the boolean flag attribute bitfiled, otherwise it
/// returns the error message.
pub fn get_boolean_flag_attribute(file: &Mmap, offset: u32) -> Result<u8, AconfigStorageError> {
find_boolean_flag_attribute(file, offset)
pub fn get_boolean_flag_attribute(file: &Mmap, index: u32) -> Result<u8, AconfigStorageError> {
find_boolean_flag_attribute(file, index)
}
// *************************************** //
@ -174,21 +176,21 @@ mod ffi {
}
// Package table query return for cc interlop
pub struct PackageOffsetQueryCXX {
pub struct PackageReadContextQueryCXX {
pub query_success: bool,
pub error_message: String,
pub package_exists: bool,
pub package_id: u32,
pub boolean_offset: u32,
pub boolean_start_index: u32,
}
// Flag table query return for cc interlop
pub struct FlagOffsetQueryCXX {
pub struct FlagReadContextQueryCXX {
pub query_success: bool,
pub error_message: String,
pub flag_exists: bool,
pub flag_type: u16,
pub flag_id: u16,
pub flag_index: u16,
}
// Flag value query return for cc interlop
@ -209,9 +211,16 @@ mod ffi {
extern "Rust" {
pub fn get_storage_file_version_cxx(file_path: &str) -> VersionNumberQueryCXX;
pub fn get_package_offset_cxx(file: &[u8], package: &str) -> PackageOffsetQueryCXX;
pub fn get_package_read_context_cxx(
file: &[u8],
package: &str,
) -> PackageReadContextQueryCXX;
pub fn get_flag_offset_cxx(file: &[u8], package_id: u32, flag: &str) -> FlagOffsetQueryCXX;
pub fn get_flag_read_context_cxx(
file: &[u8],
package_id: u32,
flag: &str,
) -> FlagReadContextQueryCXX;
pub fn get_boolean_flag_value_cxx(file: &[u8], offset: u32) -> BooleanFlagValueQueryCXX;
@ -223,8 +232,10 @@ mod ffi {
}
/// Implement the package offset interlop return type, create from actual package offset api return type
impl ffi::PackageOffsetQueryCXX {
pub(crate) fn new(offset_result: Result<Option<PackageOffset>, AconfigStorageError>) -> Self {
impl ffi::PackageReadContextQueryCXX {
pub(crate) fn new(
offset_result: Result<Option<PackageReadContext>, AconfigStorageError>,
) -> Self {
match offset_result {
Ok(offset_opt) => match offset_opt {
Some(offset) => Self {
@ -232,14 +243,14 @@ impl ffi::PackageOffsetQueryCXX {
error_message: String::from(""),
package_exists: true,
package_id: offset.package_id,
boolean_offset: offset.boolean_offset,
boolean_start_index: offset.boolean_start_index,
},
None => Self {
query_success: true,
error_message: String::from(""),
package_exists: false,
package_id: 0,
boolean_offset: 0,
boolean_start_index: 0,
},
},
Err(errmsg) => Self {
@ -247,15 +258,15 @@ impl ffi::PackageOffsetQueryCXX {
error_message: format!("{:?}", errmsg),
package_exists: false,
package_id: 0,
boolean_offset: 0,
boolean_start_index: 0,
},
}
}
}
/// Implement the flag offset interlop return type, create from actual flag offset api return type
impl ffi::FlagOffsetQueryCXX {
pub(crate) fn new(offset_result: Result<Option<FlagOffset>, AconfigStorageError>) -> Self {
impl ffi::FlagReadContextQueryCXX {
pub(crate) fn new(offset_result: Result<Option<FlagReadContext>, AconfigStorageError>) -> Self {
match offset_result {
Ok(offset_opt) => match offset_opt {
Some(offset) => Self {
@ -263,14 +274,14 @@ impl ffi::FlagOffsetQueryCXX {
error_message: String::from(""),
flag_exists: true,
flag_type: offset.flag_type as u16,
flag_id: offset.flag_id,
flag_index: offset.flag_index,
},
None => Self {
query_success: true,
error_message: String::from(""),
flag_exists: false,
flag_type: 0u16,
flag_id: 0u16,
flag_index: 0u16,
},
},
Err(errmsg) => Self {
@ -278,7 +289,7 @@ impl ffi::FlagOffsetQueryCXX {
error_message: format!("{:?}", errmsg),
flag_exists: false,
flag_type: 0u16,
flag_id: 0u16,
flag_index: 0u16,
},
}
}
@ -335,14 +346,18 @@ impl ffi::VersionNumberQueryCXX {
}
}
/// Get package start offset cc interlop
pub fn get_package_offset_cxx(file: &[u8], package: &str) -> ffi::PackageOffsetQueryCXX {
ffi::PackageOffsetQueryCXX::new(find_package_offset(file, package))
/// Get package read context cc interlop
pub fn get_package_read_context_cxx(file: &[u8], package: &str) -> ffi::PackageReadContextQueryCXX {
ffi::PackageReadContextQueryCXX::new(find_package_read_context(file, package))
}
/// Get flag start offset cc interlop
pub fn get_flag_offset_cxx(file: &[u8], package_id: u32, flag: &str) -> ffi::FlagOffsetQueryCXX {
ffi::FlagOffsetQueryCXX::new(find_flag_offset(file, package_id, flag))
/// Get flag read context cc interlop
pub fn get_flag_read_context_cxx(
file: &[u8],
package_id: u32,
flag: &str,
) -> ffi::FlagReadContextQueryCXX {
ffi::FlagReadContextQueryCXX::new(find_flag_read_context(file, package_id, flag))
}
/// Get boolean flag value cc interlop
@ -400,39 +415,39 @@ files {{
}
#[test]
// this test point locks down flag package offset query
fn test_package_offset_query() {
// this test point locks down flag package read context query
fn test_package_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
let package_mapped_file = unsafe {
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
};
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_1")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
assert_eq!(package_context, expected_package_context);
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_2")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
assert_eq!(package_context, expected_package_context);
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_4")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
assert_eq!(package_context, expected_package_context);
}
#[test]
// this test point locks down flag offset query
fn test_flag_offset_query() {
// this test point locks down flag read context query
fn test_flag_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
let flag_mapped_file =
@ -448,11 +463,11 @@ files {{
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
];
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
let flag_offset =
get_flag_offset(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_offset.flag_type, flag_type);
assert_eq!(flag_offset.flag_id, flag_id);
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
let flag_context =
get_flag_read_context(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_context.flag_type, flag_type);
assert_eq!(flag_context.flag_index, flag_index);
}
}

View file

@ -24,16 +24,16 @@ use anyhow::anyhow;
/// Package table query return
#[derive(PartialEq, Debug)]
pub struct PackageOffset {
pub struct PackageReadContext {
pub package_id: u32,
pub boolean_offset: u32,
pub boolean_start_index: u32,
}
/// Query package id and start offset
pub fn find_package_offset(
/// Query package read context: package id and start index
pub fn find_package_read_context(
buf: &[u8],
package: &str,
) -> Result<Option<PackageOffset>, AconfigStorageError> {
) -> Result<Option<PackageReadContext>, AconfigStorageError> {
let interpreted_header = PackageTableHeader::from_bytes(buf)?;
if interpreted_header.version > FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
@ -57,9 +57,9 @@ pub fn find_package_offset(
loop {
let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
if interpreted_node.package_name == package {
return Ok(Some(PackageOffset {
return Ok(Some(PackageReadContext {
package_id: interpreted_node.package_id,
boolean_offset: interpreted_node.boolean_offset,
boolean_start_index: interpreted_node.boolean_start_index,
}));
}
match interpreted_node.next_offset {
@ -78,24 +78,24 @@ mod tests {
// this test point locks down table query
fn test_package_query() {
let package_table = create_test_package_table().into_bytes();
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
assert_eq!(package_offset, expected_package_offset);
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_2")
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
assert_eq!(package_offset, expected_package_offset);
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_4")
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
assert_eq!(package_context, expected_package_context);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
assert_eq!(package_context, expected_package_context);
}
#[test]
@ -103,13 +103,15 @@ mod tests {
fn test_not_existed_package_query() {
// this will land at an empty bucket
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);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_3")
.unwrap();
assert_eq!(package_context, None);
// this will land at the end of a linked list
let package_offset =
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_5").unwrap();
assert_eq!(package_offset, None);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_5")
.unwrap();
assert_eq!(package_context, None);
}
#[test]
@ -118,8 +120,9 @@ mod tests {
let mut table = create_test_package_table();
table.header.version = crate::FILE_VERSION + 1;
let package_table = table.into_bytes();
let error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap_err();
let error =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(

View file

@ -104,6 +104,9 @@ TEST_F(AconfigStorageTest, test_storage_version_query) {
version = api::get_storage_file_version(flag_val);
ASSERT_TRUE(version.ok());
ASSERT_EQ(*version, 1);
version = api::get_storage_file_version(flag_info);
ASSERT_TRUE(version.ok());
ASSERT_EQ(*version, 1);
}
/// Negative test to lock down the error when mapping none exist storage files
@ -115,48 +118,48 @@ TEST_F(AconfigStorageTest, test_none_exist_storage_file_mapping) {
"Unable to find storage files for container vendor");
}
/// Test to lock down storage package offset query api
TEST_F(AconfigStorageTest, test_package_offset_query) {
/// Test to lock down storage package context query api
TEST_F(AconfigStorageTest, test_package_context_query) {
auto mapped_file = private_api::get_mapped_file_impl(
storage_record_pb, "mockup", api::StorageFileType::package_map);
ASSERT_TRUE(mapped_file.ok());
auto offset = api::get_package_offset(
auto context = api::get_package_read_context(
*mapped_file, "com.android.aconfig.storage.test_1");
ASSERT_TRUE(offset.ok());
ASSERT_TRUE(offset->package_exists);
ASSERT_EQ(offset->package_id, 0);
ASSERT_EQ(offset->boolean_offset, 0);
ASSERT_TRUE(context.ok());
ASSERT_TRUE(context->package_exists);
ASSERT_EQ(context->package_id, 0);
ASSERT_EQ(context->boolean_start_index, 0);
offset = api::get_package_offset(
context = api::get_package_read_context(
*mapped_file, "com.android.aconfig.storage.test_2");
ASSERT_TRUE(offset.ok());
ASSERT_TRUE(offset->package_exists);
ASSERT_EQ(offset->package_id, 1);
ASSERT_EQ(offset->boolean_offset, 3);
ASSERT_TRUE(context.ok());
ASSERT_TRUE(context->package_exists);
ASSERT_EQ(context->package_id, 1);
ASSERT_EQ(context->boolean_start_index, 3);
offset = api::get_package_offset(
context = api::get_package_read_context(
*mapped_file, "com.android.aconfig.storage.test_4");
ASSERT_TRUE(offset.ok());
ASSERT_TRUE(offset->package_exists);
ASSERT_EQ(offset->package_id, 2);
ASSERT_EQ(offset->boolean_offset, 6);
ASSERT_TRUE(context.ok());
ASSERT_TRUE(context->package_exists);
ASSERT_EQ(context->package_id, 2);
ASSERT_EQ(context->boolean_start_index, 6);
}
/// Test to lock down when querying none exist package
TEST_F(AconfigStorageTest, test_none_existent_package_offset_query) {
TEST_F(AconfigStorageTest, test_none_existent_package_context_query) {
auto mapped_file = private_api::get_mapped_file_impl(
storage_record_pb, "mockup", api::StorageFileType::package_map);
ASSERT_TRUE(mapped_file.ok());
auto offset = api::get_package_offset(
auto context = api::get_package_read_context(
*mapped_file, "com.android.aconfig.storage.test_3");
ASSERT_TRUE(offset.ok());
ASSERT_FALSE(offset->package_exists);
ASSERT_TRUE(context.ok());
ASSERT_FALSE(context->package_exists);
}
/// Test to lock down storage flag offset query api
TEST_F(AconfigStorageTest, test_flag_offset_query) {
/// Test to lock down storage flag context query api
TEST_F(AconfigStorageTest, test_flag_context_query) {
auto mapped_file = private_api::get_mapped_file_impl(
storage_record_pb, "mockup", api::StorageFileType::flag_map);
ASSERT_TRUE(mapped_file.ok());
@ -171,28 +174,28 @@ TEST_F(AconfigStorageTest, test_flag_offset_query) {
{2, "enabled_fixed_ro", api::StoredFlagType::FixedReadOnlyBoolean, 0},
{0, "disabled_rw", api::StoredFlagType::ReadWriteBoolean, 0},
};
for (auto const&[package_id, flag_name, flag_type, flag_id] : baseline) {
auto offset = api::get_flag_offset(*mapped_file, package_id, flag_name);
ASSERT_TRUE(offset.ok());
ASSERT_TRUE(offset->flag_exists);
ASSERT_EQ(offset->flag_type, flag_type);
ASSERT_EQ(offset->flag_id, flag_id);
for (auto const&[package_id, flag_name, flag_type, flag_index] : baseline) {
auto context = api::get_flag_read_context(*mapped_file, package_id, flag_name);
ASSERT_TRUE(context.ok());
ASSERT_TRUE(context->flag_exists);
ASSERT_EQ(context->flag_type, flag_type);
ASSERT_EQ(context->flag_index, flag_index);
}
}
/// Test to lock down when querying none exist flag
TEST_F(AconfigStorageTest, test_none_existent_flag_offset_query) {
TEST_F(AconfigStorageTest, test_none_existent_flag_context_query) {
auto mapped_file = private_api::get_mapped_file_impl(
storage_record_pb, "mockup", api::StorageFileType::flag_map);
ASSERT_TRUE(mapped_file.ok());
auto offset = api::get_flag_offset(*mapped_file, 0, "none_exist");
ASSERT_TRUE(offset.ok());
ASSERT_FALSE(offset->flag_exists);
auto context = api::get_flag_read_context(*mapped_file, 0, "none_exist");
ASSERT_TRUE(context.ok());
ASSERT_FALSE(context->flag_exists);
offset = api::get_flag_offset(*mapped_file, 3, "enabled_ro");
ASSERT_TRUE(offset.ok());
ASSERT_FALSE(offset->flag_exists);
context = api::get_flag_read_context(*mapped_file, 3, "enabled_ro");
ASSERT_TRUE(context.ok());
ASSERT_FALSE(context->flag_exists);
}
/// Test to lock down storage flag value query api
@ -203,10 +206,10 @@ TEST_F(AconfigStorageTest, test_boolean_flag_value_query) {
auto expected_value = std::vector<bool>{
false, true, true, false, true, true, true, true};
for (int offset = 0; offset < 8; ++offset) {
auto value = api::get_boolean_flag_value(*mapped_file, offset);
for (int index = 0; index < 8; ++index) {
auto value = api::get_boolean_flag_value(*mapped_file, index);
ASSERT_TRUE(value.ok());
ASSERT_EQ(*value, expected_value[offset]);
ASSERT_EQ(*value, expected_value[index]);
}
}
@ -230,12 +233,12 @@ TEST_F(AconfigStorageTest, test_boolean_flag_info_query) {
auto expected_value = std::vector<bool>{
true, false, true, false, false, false, false, false};
for (int offset = 0; offset < 8; ++offset) {
auto attribute = api::get_boolean_flag_attribute(*mapped_file, offset);
for (int index = 0; index < 8; ++index) {
auto attribute = api::get_boolean_flag_attribute(*mapped_file, index);
ASSERT_TRUE(attribute.ok());
ASSERT_EQ(*attribute & static_cast<uint8_t>(api::FlagInfoBit::IsSticky), 0);
ASSERT_EQ((*attribute & static_cast<uint8_t>(api::FlagInfoBit::IsReadWrite)) != 0,
expected_value[offset]);
expected_value[index]);
ASSERT_EQ(*attribute & static_cast<uint8_t>(api::FlagInfoBit::HasOverride), 0);
}
}

View file

@ -3,8 +3,9 @@ mod aconfig_storage_rust_test {
use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
use aconfig_storage_file::{FlagInfoBit, StorageFileType, StoredFlagType};
use aconfig_storage_read_api::{
get_boolean_flag_attribute, get_boolean_flag_value, get_flag_offset, get_package_offset,
get_storage_file_version, mapped_file::get_mapped_file, PackageOffset,
get_boolean_flag_attribute, get_boolean_flag_value, get_flag_read_context,
get_package_read_context, get_storage_file_version, mapped_file::get_mapped_file,
PackageReadContext,
};
use std::fs;
use tempfile::NamedTempFile;
@ -58,7 +59,7 @@ files {{
}
#[test]
fn test_package_offset_query() {
fn test_package_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
// SAFETY:
@ -67,30 +68,30 @@ files {{
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
};
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_1")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
assert_eq!(package_context, expected_package_context);
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_2")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
assert_eq!(package_context, expected_package_context);
let package_offset =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_4")
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
assert_eq!(package_offset, expected_package_offset);
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
assert_eq!(package_context, expected_package_context);
}
#[test]
fn test_none_exist_package_offset_query() {
fn test_none_exist_package_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
// SAFETY:
@ -99,13 +100,14 @@ files {{
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
};
let package_offset_option =
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_3").unwrap();
assert_eq!(package_offset_option, None);
let package_context_option =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_3")
.unwrap();
assert_eq!(package_context_option, None);
}
#[test]
fn test_flag_offset_query() {
fn test_flag_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
// SAFETY:
@ -123,27 +125,29 @@ files {{
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
];
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
let flag_offset =
get_flag_offset(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_offset.flag_type, flag_type);
assert_eq!(flag_offset.flag_id, flag_id);
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
let flag_context =
get_flag_read_context(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
assert_eq!(flag_context.flag_type, flag_type);
assert_eq!(flag_context.flag_index, flag_index);
}
}
#[test]
fn test_none_exist_flag_offset_query() {
fn test_none_exist_flag_context_query() {
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
let pb_file_path = pb_file.path().display().to_string();
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_mapped_file =
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() };
let flag_offset_option = get_flag_offset(&flag_mapped_file, 0, "none_exist").unwrap();
assert_eq!(flag_offset_option, None);
let flag_context_option =
get_flag_read_context(&flag_mapped_file, 0, "none_exist").unwrap();
assert_eq!(flag_context_option, None);
let flag_offset_option = get_flag_offset(&flag_mapped_file, 3, "enabled_ro").unwrap();
assert_eq!(flag_offset_option, None);
let flag_context_option =
get_flag_read_context(&flag_mapped_file, 3, "enabled_ro").unwrap();
assert_eq!(flag_context_option, None);
}
#[test]