Merge changes from topic "index_instead_of_offset" into main
* changes: aconfig: update storage write api aconfig: update storage read api aconfig: update storage file creation to allow storage files to store flag index instead of byte offset aconfig: update storage file to store flag index instead of file byte offset
This commit is contained in:
@@ -48,7 +48,7 @@ impl FlagTableNodeWrapper {
|
|||||||
package_id: u32,
|
package_id: u32,
|
||||||
flag_name: &str,
|
flag_name: &str,
|
||||||
flag_type: StoredFlagType,
|
flag_type: StoredFlagType,
|
||||||
flag_id: u16,
|
flag_index: u16,
|
||||||
num_buckets: u32,
|
num_buckets: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let bucket_index = FlagTableNode::find_bucket_index(package_id, flag_name, num_buckets);
|
let bucket_index = FlagTableNode::find_bucket_index(package_id, flag_name, num_buckets);
|
||||||
@@ -56,7 +56,7 @@ impl FlagTableNodeWrapper {
|
|||||||
package_id,
|
package_id,
|
||||||
flag_name: flag_name.to_string(),
|
flag_name: flag_name.to_string(),
|
||||||
flag_type,
|
flag_type,
|
||||||
flag_id,
|
flag_index,
|
||||||
next_offset: None,
|
next_offset: None,
|
||||||
};
|
};
|
||||||
Self { node, bucket_index }
|
Self { node, bucket_index }
|
||||||
|
@@ -41,14 +41,14 @@ pub fn create_flag_value(container: &str, packages: &[FlagPackage]) -> Result<Fl
|
|||||||
};
|
};
|
||||||
|
|
||||||
for pkg in packages.iter() {
|
for pkg in packages.iter() {
|
||||||
let start_offset = pkg.boolean_offset as usize;
|
let start_index = pkg.boolean_start_index as usize;
|
||||||
let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
|
let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
|
||||||
for pf in pkg.boolean_flags.iter() {
|
for pf in pkg.boolean_flags.iter() {
|
||||||
let fid = flag_ids
|
let fid = flag_ids
|
||||||
.get(pf.name())
|
.get(pf.name())
|
||||||
.ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
|
.ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
|
||||||
|
|
||||||
list.booleans[start_offset + (*fid as usize)] = pf.state() == ProtoFlagState::ENABLED;
|
list.booleans[start_index + (*fid as usize)] = pf.state() == ProtoFlagState::ENABLED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,9 +33,9 @@ pub struct FlagPackage<'a> {
|
|||||||
pub package_id: u32,
|
pub package_id: u32,
|
||||||
pub flag_names: HashSet<&'a str>,
|
pub flag_names: HashSet<&'a str>,
|
||||||
pub boolean_flags: Vec<&'a ProtoParsedFlag>,
|
pub boolean_flags: Vec<&'a ProtoParsedFlag>,
|
||||||
// offset of the first boolean flag in this flag package with respect to the start of
|
// The index of the first boolean flag in this aconfig package among all boolean
|
||||||
// boolean flag value array in the flag value file
|
// flags in this container.
|
||||||
pub boolean_offset: u32,
|
pub boolean_start_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FlagPackage<'a> {
|
impl<'a> FlagPackage<'a> {
|
||||||
@@ -45,7 +45,7 @@ impl<'a> FlagPackage<'a> {
|
|||||||
package_id,
|
package_id,
|
||||||
flag_names: HashSet::new(),
|
flag_names: HashSet::new(),
|
||||||
boolean_flags: vec![],
|
boolean_flags: vec![],
|
||||||
boolean_offset: 0,
|
boolean_start_index: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,12 +73,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate package flag value start offset, in flag value file, each boolean
|
// cacluate boolean flag start index for each package
|
||||||
// is stored as a single byte
|
let mut boolean_start_index = 0;
|
||||||
let mut boolean_offset = 0;
|
|
||||||
for p in packages.iter_mut() {
|
for p in packages.iter_mut() {
|
||||||
p.boolean_offset = boolean_offset;
|
p.boolean_start_index = boolean_start_index;
|
||||||
boolean_offset += p.boolean_flags.len() as u32;
|
boolean_start_index += p.boolean_flags.len() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
packages
|
packages
|
||||||
@@ -184,7 +183,7 @@ mod tests {
|
|||||||
assert!(packages[0].flag_names.contains("enabled_rw"));
|
assert!(packages[0].flag_names.contains("enabled_rw"));
|
||||||
assert!(packages[0].flag_names.contains("disabled_rw"));
|
assert!(packages[0].flag_names.contains("disabled_rw"));
|
||||||
assert!(packages[0].flag_names.contains("enabled_ro"));
|
assert!(packages[0].flag_names.contains("enabled_ro"));
|
||||||
assert_eq!(packages[0].boolean_offset, 0);
|
assert_eq!(packages[0].boolean_start_index, 0);
|
||||||
|
|
||||||
assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
|
assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
|
||||||
assert_eq!(packages[1].package_id, 1);
|
assert_eq!(packages[1].package_id, 1);
|
||||||
@@ -192,13 +191,13 @@ mod tests {
|
|||||||
assert!(packages[1].flag_names.contains("enabled_ro"));
|
assert!(packages[1].flag_names.contains("enabled_ro"));
|
||||||
assert!(packages[1].flag_names.contains("disabled_ro"));
|
assert!(packages[1].flag_names.contains("disabled_ro"));
|
||||||
assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
|
assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
|
||||||
assert_eq!(packages[1].boolean_offset, 3);
|
assert_eq!(packages[1].boolean_start_index, 3);
|
||||||
|
|
||||||
assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
|
assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
|
||||||
assert_eq!(packages[2].package_id, 2);
|
assert_eq!(packages[2].package_id, 2);
|
||||||
assert_eq!(packages[2].flag_names.len(), 2);
|
assert_eq!(packages[2].flag_names.len(), 2);
|
||||||
assert!(packages[2].flag_names.contains("enabled_ro"));
|
assert!(packages[2].flag_names.contains("enabled_ro"));
|
||||||
assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
|
assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
|
||||||
assert_eq!(packages[2].boolean_offset, 6);
|
assert_eq!(packages[2].boolean_start_index, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,7 @@ impl PackageTableNodeWrapper {
|
|||||||
let node = PackageTableNode {
|
let node = PackageTableNode {
|
||||||
package_name: String::from(package.package_name),
|
package_name: String::from(package.package_name),
|
||||||
package_id: package.package_id,
|
package_id: package.package_id,
|
||||||
boolean_offset: package.boolean_offset,
|
boolean_start_index: package.boolean_start_index,
|
||||||
next_offset: None,
|
next_offset: None,
|
||||||
};
|
};
|
||||||
let bucket_index = PackageTableNode::find_bucket_index(package.package_name, num_buckets);
|
let bucket_index = PackageTableNode::find_bucket_index(package.package_name, num_buckets);
|
||||||
|
@@ -100,7 +100,8 @@ pub struct FlagTableNode {
|
|||||||
pub package_id: u32,
|
pub package_id: u32,
|
||||||
pub flag_name: String,
|
pub flag_name: String,
|
||||||
pub flag_type: StoredFlagType,
|
pub flag_type: StoredFlagType,
|
||||||
pub flag_id: u16,
|
// within package flag index of this flag type
|
||||||
|
pub flag_index: u16,
|
||||||
pub next_offset: Option<u32>,
|
pub next_offset: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,8 +110,8 @@ impl fmt::Debug for FlagTableNode {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"Package Id: {}, Flag: {}, Type: {:?}, Offset: {}, Next: {:?}",
|
"Package Id: {}, Flag: {}, Type: {:?}, Index: {}, Next: {:?}",
|
||||||
self.package_id, self.flag_name, self.flag_type, self.flag_id, self.next_offset
|
self.package_id, self.flag_name, self.flag_type, self.flag_index, self.next_offset
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -125,7 +126,7 @@ impl FlagTableNode {
|
|||||||
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
|
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
|
||||||
result.extend_from_slice(name_bytes);
|
result.extend_from_slice(name_bytes);
|
||||||
result.extend_from_slice(&(self.flag_type as u16).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.flag_index.to_le_bytes());
|
||||||
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
|
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@@ -137,7 +138,7 @@ impl FlagTableNode {
|
|||||||
package_id: read_u32_from_bytes(bytes, &mut head)?,
|
package_id: read_u32_from_bytes(bytes, &mut head)?,
|
||||||
flag_name: read_str_from_bytes(bytes, &mut head)?,
|
flag_name: read_str_from_bytes(bytes, &mut head)?,
|
||||||
flag_type: StoredFlagType::try_from(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)?,
|
flag_index: read_u16_from_bytes(bytes, &mut head)?,
|
||||||
next_offset: match read_u32_from_bytes(bytes, &mut head)? {
|
next_offset: match read_u32_from_bytes(bytes, &mut head)? {
|
||||||
0 => None,
|
0 => None,
|
||||||
val => Some(val),
|
val => Some(val),
|
||||||
|
@@ -46,7 +46,7 @@ use std::fs::File;
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode, FlagInfoBit};
|
pub use crate::flag_info::{FlagInfoBit, FlagInfoHeader, FlagInfoList, FlagInfoNode};
|
||||||
pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
|
pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
|
||||||
pub use crate::flag_value::{FlagValueHeader, FlagValueList};
|
pub use crate::flag_value::{FlagValueHeader, FlagValueList};
|
||||||
pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
|
pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
|
||||||
@@ -255,13 +255,13 @@ pub fn list_flags(
|
|||||||
|
|
||||||
let mut package_info = vec![("", 0); package_table.header.num_packages as usize];
|
let mut package_info = vec![("", 0); package_table.header.num_packages as usize];
|
||||||
for node in package_table.nodes.iter() {
|
for node in package_table.nodes.iter() {
|
||||||
package_info[node.package_id as usize] = (&node.package_name, node.boolean_offset);
|
package_info[node.package_id as usize] = (&node.package_name, node.boolean_start_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut flags = Vec::new();
|
let mut flags = Vec::new();
|
||||||
for node in flag_table.nodes.iter() {
|
for node in flag_table.nodes.iter() {
|
||||||
let (package_name, package_offset) = package_info[node.package_id as usize];
|
let (package_name, package_offset) = package_info[node.package_id as usize];
|
||||||
let flag_offset = package_offset + node.flag_id as u32;
|
let flag_offset = package_offset + node.flag_index as u32;
|
||||||
let flag_value = flag_value_list.booleans[flag_offset as usize];
|
let flag_value = flag_value_list.booleans[flag_offset as usize];
|
||||||
flags.push((
|
flags.push((
|
||||||
String::from(package_name),
|
String::from(package_name),
|
||||||
|
@@ -96,9 +96,9 @@ impl PackageTableHeader {
|
|||||||
pub struct PackageTableNode {
|
pub struct PackageTableNode {
|
||||||
pub package_name: String,
|
pub package_name: String,
|
||||||
pub package_id: u32,
|
pub package_id: u32,
|
||||||
// offset of the first boolean flag in this flag package with respect to the start of
|
// The index of the first boolean flag in this aconfig package among all boolean
|
||||||
// boolean flag value array in the flag value file
|
// flags in this container.
|
||||||
pub boolean_offset: u32,
|
pub boolean_start_index: u32,
|
||||||
pub next_offset: Option<u32>,
|
pub next_offset: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,8 +107,8 @@ impl fmt::Debug for PackageTableNode {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"Package: {}, Id: {}, Offset: {}, Next: {:?}",
|
"Package: {}, Id: {}, Boolean flag start index: {}, Next: {:?}",
|
||||||
self.package_name, self.package_id, self.boolean_offset, self.next_offset
|
self.package_name, self.package_id, self.boolean_start_index, self.next_offset
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ impl PackageTableNode {
|
|||||||
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
|
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
|
||||||
result.extend_from_slice(name_bytes);
|
result.extend_from_slice(name_bytes);
|
||||||
result.extend_from_slice(&self.package_id.to_le_bytes());
|
result.extend_from_slice(&self.package_id.to_le_bytes());
|
||||||
result.extend_from_slice(&self.boolean_offset.to_le_bytes());
|
result.extend_from_slice(&self.boolean_start_index.to_le_bytes());
|
||||||
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
|
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ impl PackageTableNode {
|
|||||||
let node = Self {
|
let node = Self {
|
||||||
package_name: read_str_from_bytes(bytes, &mut head)?,
|
package_name: read_str_from_bytes(bytes, &mut head)?,
|
||||||
package_id: read_u32_from_bytes(bytes, &mut head)?,
|
package_id: read_u32_from_bytes(bytes, &mut head)?,
|
||||||
boolean_offset: read_u32_from_bytes(bytes, &mut head)?,
|
boolean_start_index: read_u32_from_bytes(bytes, &mut head)?,
|
||||||
next_offset: match read_u32_from_bytes(bytes, &mut head)? {
|
next_offset: match read_u32_from_bytes(bytes, &mut head)? {
|
||||||
0 => None,
|
0 => None,
|
||||||
val => Some(val),
|
val => Some(val),
|
||||||
|
@@ -38,19 +38,19 @@ pub fn create_test_package_table() -> PackageTable {
|
|||||||
let first_node = PackageTableNode {
|
let first_node = PackageTableNode {
|
||||||
package_name: String::from("com.android.aconfig.storage.test_2"),
|
package_name: String::from("com.android.aconfig.storage.test_2"),
|
||||||
package_id: 1,
|
package_id: 1,
|
||||||
boolean_offset: 3,
|
boolean_start_index: 3,
|
||||||
next_offset: None,
|
next_offset: None,
|
||||||
};
|
};
|
||||||
let second_node = PackageTableNode {
|
let second_node = PackageTableNode {
|
||||||
package_name: String::from("com.android.aconfig.storage.test_1"),
|
package_name: String::from("com.android.aconfig.storage.test_1"),
|
||||||
package_id: 0,
|
package_id: 0,
|
||||||
boolean_offset: 0,
|
boolean_start_index: 0,
|
||||||
next_offset: Some(159),
|
next_offset: Some(159),
|
||||||
};
|
};
|
||||||
let third_node = PackageTableNode {
|
let third_node = PackageTableNode {
|
||||||
package_name: String::from("com.android.aconfig.storage.test_4"),
|
package_name: String::from("com.android.aconfig.storage.test_4"),
|
||||||
package_id: 2,
|
package_id: 2,
|
||||||
boolean_offset: 6,
|
boolean_start_index: 6,
|
||||||
next_offset: None,
|
next_offset: None,
|
||||||
};
|
};
|
||||||
let nodes = vec![first_node, second_node, third_node];
|
let nodes = vec![first_node, second_node, third_node];
|
||||||
@@ -63,14 +63,14 @@ impl FlagTableNode {
|
|||||||
package_id: u32,
|
package_id: u32,
|
||||||
flag_name: &str,
|
flag_name: &str,
|
||||||
flag_type: u16,
|
flag_type: u16,
|
||||||
flag_id: u16,
|
flag_index: u16,
|
||||||
next_offset: Option<u32>,
|
next_offset: Option<u32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
package_id,
|
package_id,
|
||||||
flag_name: flag_name.to_string(),
|
flag_name: flag_name.to_string(),
|
||||||
flag_type: StoredFlagType::try_from(flag_type).unwrap(),
|
flag_type: StoredFlagType::try_from(flag_type).unwrap(),
|
||||||
flag_id,
|
flag_index,
|
||||||
next_offset,
|
next_offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -126,50 +126,50 @@ Result<uint32_t> get_storage_file_version(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get package offset
|
/// Get package context
|
||||||
Result<PackageOffset> get_package_offset(
|
Result<PackageReadContext> get_package_read_context(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
std::string const& package) {
|
std::string const& package) {
|
||||||
auto content = rust::Slice<const uint8_t>(
|
auto content = rust::Slice<const uint8_t>(
|
||||||
static_cast<uint8_t*>(file.file_ptr), file.file_size);
|
static_cast<uint8_t*>(file.file_ptr), file.file_size);
|
||||||
auto offset_cxx = get_package_offset_cxx(content, rust::Str(package.c_str()));
|
auto context_cxx = get_package_read_context_cxx(content, rust::Str(package.c_str()));
|
||||||
if (offset_cxx.query_success) {
|
if (context_cxx.query_success) {
|
||||||
auto offset = PackageOffset();
|
auto context = PackageReadContext();
|
||||||
offset.package_exists = offset_cxx.package_exists;
|
context.package_exists = context_cxx.package_exists;
|
||||||
offset.package_id = offset_cxx.package_id;
|
context.package_id = context_cxx.package_id;
|
||||||
offset.boolean_offset = offset_cxx.boolean_offset;
|
context.boolean_start_index = context_cxx.boolean_start_index;
|
||||||
return offset;
|
return context;
|
||||||
} else {
|
} else {
|
||||||
return Error() << offset_cxx.error_message;
|
return Error() << context_cxx.error_message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get flag offset
|
/// Get flag read context
|
||||||
Result<FlagOffset> get_flag_offset(
|
Result<FlagReadContext> get_flag_read_context(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
uint32_t package_id,
|
uint32_t package_id,
|
||||||
std::string const& flag_name){
|
std::string const& flag_name){
|
||||||
auto content = rust::Slice<const uint8_t>(
|
auto content = rust::Slice<const uint8_t>(
|
||||||
static_cast<uint8_t*>(file.file_ptr), file.file_size);
|
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()));
|
auto context_cxx = get_flag_read_context_cxx(content, package_id, rust::Str(flag_name.c_str()));
|
||||||
if (offset_cxx.query_success) {
|
if (context_cxx.query_success) {
|
||||||
auto offset = FlagOffset();
|
auto context = FlagReadContext();
|
||||||
offset.flag_exists = offset_cxx.flag_exists;
|
context.flag_exists = context_cxx.flag_exists;
|
||||||
offset.flag_type = static_cast<StoredFlagType>(offset_cxx.flag_type);
|
context.flag_type = static_cast<StoredFlagType>(context_cxx.flag_type);
|
||||||
offset.flag_id = offset_cxx.flag_id;
|
context.flag_index = context_cxx.flag_index;
|
||||||
return offset;
|
return context;
|
||||||
} else {
|
} else {
|
||||||
return Error() << offset_cxx.error_message;
|
return Error() << context_cxx.error_message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get boolean flag value
|
/// Get boolean flag value
|
||||||
Result<bool> get_boolean_flag_value(
|
Result<bool> get_boolean_flag_value(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
uint32_t offset) {
|
uint32_t index) {
|
||||||
auto content = rust::Slice<const uint8_t>(
|
auto content = rust::Slice<const uint8_t>(
|
||||||
static_cast<uint8_t*>(file.file_ptr), file.file_size);
|
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) {
|
if (value_cxx.query_success) {
|
||||||
return value_cxx.flag_value;
|
return value_cxx.flag_value;
|
||||||
} else {
|
} else {
|
||||||
@@ -180,10 +180,10 @@ Result<bool> get_boolean_flag_value(
|
|||||||
/// Get boolean flag attribute
|
/// Get boolean flag attribute
|
||||||
Result<uint8_t> get_boolean_flag_attribute(
|
Result<uint8_t> get_boolean_flag_attribute(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
uint32_t offset) {
|
uint32_t index) {
|
||||||
auto content = rust::Slice<const uint8_t>(
|
auto content = rust::Slice<const uint8_t>(
|
||||||
static_cast<uint8_t*>(file.file_ptr), file.file_size);
|
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) {
|
if (info_cxx.query_success) {
|
||||||
return info_cxx.flag_attribute;
|
return info_cxx.flag_attribute;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -20,11 +20,11 @@ struct MappedStorageFile {
|
|||||||
size_t file_size;
|
size_t file_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Package offset query result
|
/// Package read context query result
|
||||||
struct PackageOffset {
|
struct PackageReadContext {
|
||||||
bool package_exists;
|
bool package_exists;
|
||||||
uint32_t package_id;
|
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
|
/// 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,
|
FixedReadOnlyBoolean = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Flag offset query result
|
/// Flag read context query result
|
||||||
struct FlagOffset {
|
struct FlagReadContext {
|
||||||
bool flag_exists;
|
bool flag_exists;
|
||||||
StoredFlagType flag_type;
|
StoredFlagType flag_type;
|
||||||
uint16_t flag_id;
|
uint16_t flag_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// DO NOT USE APIS IN THE FOLLOWING NAMESPACE DIRECTLY
|
/// 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(
|
android::base::Result<uint32_t> get_storage_file_version(
|
||||||
std::string const& file_path);
|
std::string const& file_path);
|
||||||
|
|
||||||
/// Get package offset
|
/// Get package read context
|
||||||
/// \input file: mapped storage file
|
/// \input file: mapped storage file
|
||||||
/// \input package: the flag package name
|
/// \input package: the flag package name
|
||||||
/// \returns a package offset
|
/// \returns a package read context
|
||||||
android::base::Result<PackageOffset> get_package_offset(
|
android::base::Result<PackageReadContext> get_package_read_context(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
std::string const& package);
|
std::string const& package);
|
||||||
|
|
||||||
/// Get flag offset
|
/// Get flag read context
|
||||||
/// \input file: mapped storage file
|
/// \input file: mapped storage file
|
||||||
/// \input package_id: the flag package id obtained from package offset query
|
/// \input package_id: the flag package id obtained from package offset query
|
||||||
/// \input flag_name: flag name
|
/// \input flag_name: flag name
|
||||||
/// \returns the flag offset
|
/// \returns the flag read context
|
||||||
android::base::Result<FlagOffset> get_flag_offset(
|
android::base::Result<FlagReadContext> get_flag_read_context(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
uint32_t package_id,
|
uint32_t package_id,
|
||||||
std::string const& flag_name);
|
std::string const& flag_name);
|
||||||
|
|
||||||
/// Get boolean flag value
|
/// Get boolean flag value
|
||||||
/// \input file: mapped storage file
|
/// \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
|
/// \returns the boolean flag value
|
||||||
android::base::Result<bool> get_boolean_flag_value(
|
android::base::Result<bool> get_boolean_flag_value(
|
||||||
MappedStorageFile const& file,
|
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
|
/// Flag info enum, to be consistent with the one defined in aconfig_storage_file/src/lib.rs
|
||||||
enum FlagInfoBit {
|
enum FlagInfoBit {
|
||||||
@@ -100,9 +100,9 @@ enum FlagInfoBit {
|
|||||||
|
|
||||||
/// Get boolean flag attribute
|
/// Get boolean flag attribute
|
||||||
/// \input file: mapped storage file
|
/// \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
|
/// \returns the boolean flag attribute
|
||||||
android::base::Result<uint8_t> get_boolean_flag_attribute(
|
android::base::Result<uint8_t> get_boolean_flag_attribute(
|
||||||
MappedStorageFile const& file,
|
MappedStorageFile const& file,
|
||||||
uint32_t offset);
|
uint32_t index);
|
||||||
} // namespace aconfig_storage
|
} // namespace aconfig_storage
|
||||||
|
@@ -21,10 +21,7 @@ use aconfig_storage_file::{flag_info::FlagInfoHeader, read_u8_from_bytes};
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
/// Get flag attribute bitfield
|
/// Get flag attribute bitfield
|
||||||
pub fn find_boolean_flag_attribute(
|
pub fn find_boolean_flag_attribute(buf: &[u8], flag_index: u32) -> Result<u8, AconfigStorageError> {
|
||||||
buf: &[u8],
|
|
||||||
flag_offset: u32,
|
|
||||||
) -> Result<u8, AconfigStorageError> {
|
|
||||||
let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
|
let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
|
||||||
if interpreted_header.version > crate::FILE_VERSION {
|
if interpreted_header.version > crate::FILE_VERSION {
|
||||||
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
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 {
|
if head >= interpreted_header.file_size as usize {
|
||||||
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
||||||
"Flag info offset goes beyond the end of the file."
|
"Flag info offset goes beyond the end of the file."
|
||||||
|
@@ -24,17 +24,17 @@ use anyhow::anyhow;
|
|||||||
|
|
||||||
/// Flag table query return
|
/// Flag table query return
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct FlagOffset {
|
pub struct FlagReadContext {
|
||||||
pub flag_type: StoredFlagType,
|
pub flag_type: StoredFlagType,
|
||||||
pub flag_id: u16,
|
pub flag_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query flag within package offset
|
/// Query flag read context: flag type and within package flag index
|
||||||
pub fn find_flag_offset(
|
pub fn find_flag_read_context(
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
package_id: u32,
|
package_id: u32,
|
||||||
flag: &str,
|
flag: &str,
|
||||||
) -> Result<Option<FlagOffset>, AconfigStorageError> {
|
) -> Result<Option<FlagReadContext>, AconfigStorageError> {
|
||||||
let interpreted_header = FlagTableHeader::from_bytes(buf)?;
|
let interpreted_header = FlagTableHeader::from_bytes(buf)?;
|
||||||
if interpreted_header.version > crate::FILE_VERSION {
|
if interpreted_header.version > crate::FILE_VERSION {
|
||||||
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
||||||
@@ -58,9 +58,9 @@ pub fn find_flag_offset(
|
|||||||
loop {
|
loop {
|
||||||
let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
|
let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
|
||||||
if interpreted_node.package_id == package_id && interpreted_node.flag_name == flag {
|
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_type: interpreted_node.flag_type,
|
||||||
flag_id: interpreted_node.flag_id,
|
flag_index: interpreted_node.flag_index,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
match interpreted_node.next_offset {
|
match interpreted_node.next_offset {
|
||||||
@@ -89,11 +89,11 @@ mod tests {
|
|||||||
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
||||||
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
||||||
];
|
];
|
||||||
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
|
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
|
||||||
let flag_offset =
|
let flag_context =
|
||||||
find_flag_offset(&flag_table[..], package_id, flag_name).unwrap().unwrap();
|
find_flag_read_context(&flag_table[..], package_id, flag_name).unwrap().unwrap();
|
||||||
assert_eq!(flag_offset.flag_type, flag_type);
|
assert_eq!(flag_context.flag_type, flag_type);
|
||||||
assert_eq!(flag_offset.flag_id, flag_id);
|
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
|
// this test point locks down table query of a non exist flag
|
||||||
fn test_not_existed_flag_query() {
|
fn test_not_existed_flag_query() {
|
||||||
let flag_table = create_test_flag_table().into_bytes();
|
let flag_table = create_test_flag_table().into_bytes();
|
||||||
let flag_offset = find_flag_offset(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
|
let flag_context = find_flag_read_context(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
|
||||||
assert_eq!(flag_offset, None);
|
assert_eq!(flag_context, None);
|
||||||
let flag_offset = find_flag_offset(&flag_table[..], 2, "disabled_rw").unwrap();
|
let flag_context = find_flag_read_context(&flag_table[..], 2, "disabled_rw").unwrap();
|
||||||
assert_eq!(flag_offset, None);
|
assert_eq!(flag_context, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -113,7 +113,7 @@ mod tests {
|
|||||||
let mut table = create_test_flag_table();
|
let mut table = create_test_flag_table();
|
||||||
table.header.version = crate::FILE_VERSION + 1;
|
table.header.version = crate::FILE_VERSION + 1;
|
||||||
let flag_table = table.into_bytes();
|
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!(
|
assert_eq!(
|
||||||
format!("{:?}", error),
|
format!("{:?}", error),
|
||||||
format!(
|
format!(
|
||||||
|
@@ -21,7 +21,7 @@ use aconfig_storage_file::{flag_value::FlagValueHeader, read_u8_from_bytes};
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
/// Query flag value
|
/// 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)?;
|
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
|
||||||
if interpreted_header.version > crate::FILE_VERSION {
|
if interpreted_header.version > crate::FILE_VERSION {
|
||||||
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
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;
|
// 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;
|
||||||
// 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).
|
|
||||||
if head >= interpreted_header.file_size as usize {
|
if head >= interpreted_header.file_size as usize {
|
||||||
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
||||||
"Flag value offset goes beyond the end of the file."
|
"Flag value offset goes beyond the end of the file."
|
||||||
|
@@ -17,14 +17,16 @@
|
|||||||
//! `aconfig_storage_read_api` is a crate that defines read apis to read flags from storage
|
//! `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:
|
//! files. It provides four apis to interface with storage files:
|
||||||
//!
|
//!
|
||||||
//! 1, function to get package flag value start offset
|
//! 1, function to get package read context
|
||||||
//! pub fn get_package_offset(container: &str, package: &str) -> `Result<Option<PackageOffset>>>`
|
//! pub fn get_packager_read_context(container: &str, package: &str)
|
||||||
|
//! -> `Result<Option<PackageReadContext>>>`
|
||||||
//!
|
//!
|
||||||
//! 2, function to get flag offset within a specific package
|
//! 2, function to get flag read context
|
||||||
//! pub fn get_flag_offset(container: &str, package_id: u32, flag: &str) -> `Result<Option<u16>>>`
|
//! 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
|
//! 3, function to get the actual flag value given the global index (combined package and
|
||||||
//! flag offset).
|
//! flag index).
|
||||||
//! pub fn get_boolean_flag_value(container: &str, offset: u32) -> `Result<bool>`
|
//! pub fn get_boolean_flag_value(container: &str, offset: u32) -> `Result<bool>`
|
||||||
//!
|
//!
|
||||||
//! 4, function to get storage file version without mmapping the file.
|
//! 4, function to get storage file version without mmapping the file.
|
||||||
@@ -44,14 +46,14 @@ pub mod package_table_query;
|
|||||||
mod test_utils;
|
mod test_utils;
|
||||||
|
|
||||||
pub use aconfig_storage_file::{AconfigStorageError, StorageFileType};
|
pub use aconfig_storage_file::{AconfigStorageError, StorageFileType};
|
||||||
pub use flag_table_query::FlagOffset;
|
pub use flag_table_query::FlagReadContext;
|
||||||
pub use package_table_query::PackageOffset;
|
pub use package_table_query::PackageReadContext;
|
||||||
|
|
||||||
use aconfig_storage_file::{read_u32_from_bytes, FILE_VERSION};
|
use aconfig_storage_file::{read_u32_from_bytes, FILE_VERSION};
|
||||||
use flag_info_query::find_boolean_flag_attribute;
|
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 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 anyhow::anyhow;
|
||||||
use memmap2::Mmap;
|
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) }
|
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 file: mapped package file
|
||||||
/// \input package: package name
|
/// \input package: package name
|
||||||
///
|
///
|
||||||
/// \return
|
/// \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 a package is not found, it returns Ok(None)
|
||||||
/// If errors out, it returns an Err(errmsg)
|
/// If errors out, it returns an Err(errmsg)
|
||||||
pub fn get_package_offset(
|
pub fn get_package_read_context(
|
||||||
file: &Mmap,
|
file: &Mmap,
|
||||||
package: &str,
|
package: &str,
|
||||||
) -> Result<Option<PackageOffset>, AconfigStorageError> {
|
) -> Result<Option<PackageReadContext>, AconfigStorageError> {
|
||||||
find_package_offset(file, package)
|
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 file: mapped flag file
|
||||||
/// \input package_id: package id obtained from package mapping file
|
/// \input package_id: package id obtained from package mapping file
|
||||||
/// \input flag: flag name
|
/// \input flag: flag name
|
||||||
///
|
///
|
||||||
/// \return
|
/// \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 a flag is not found, it returns Ok(None)
|
||||||
/// If errors out, it returns an Err(errmsg)
|
/// If errors out, it returns an Err(errmsg)
|
||||||
pub fn get_flag_offset(
|
pub fn get_flag_read_context(
|
||||||
file: &Mmap,
|
file: &Mmap,
|
||||||
package_id: u32,
|
package_id: u32,
|
||||||
flag: &str,
|
flag: &str,
|
||||||
) -> Result<Option<FlagOffset>, AconfigStorageError> {
|
) -> Result<Option<FlagReadContext>, AconfigStorageError> {
|
||||||
find_flag_offset(file, package_id, flag)
|
find_flag_read_context(file, package_id, flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the boolean flag value.
|
/// Get the boolean flag value.
|
||||||
///
|
///
|
||||||
/// \input file: mapped flag file
|
/// \input file: mapped flag file
|
||||||
/// \input offset: flag value offset
|
/// \input index: boolean flag offset
|
||||||
///
|
///
|
||||||
/// \return
|
/// \return
|
||||||
/// If the provide offset is valid, it returns the boolean flag value, otherwise it
|
/// If the provide offset is valid, it returns the boolean flag value, otherwise it
|
||||||
/// returns the error message.
|
/// returns the error message.
|
||||||
pub fn get_boolean_flag_value(file: &Mmap, offset: u32) -> Result<bool, AconfigStorageError> {
|
pub fn get_boolean_flag_value(file: &Mmap, index: u32) -> Result<bool, AconfigStorageError> {
|
||||||
find_boolean_flag_value(file, offset)
|
find_boolean_flag_value(file, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get storage file version number
|
/// 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.
|
/// Get the boolean flag attribute.
|
||||||
///
|
///
|
||||||
/// \input file: mapped flag info file
|
/// \input file: mapped flag info file
|
||||||
/// \input offset: boolean flag offset
|
/// \input index: boolean flag index
|
||||||
///
|
///
|
||||||
/// \return
|
/// \return
|
||||||
/// If the provide offset is valid, it returns the boolean flag attribute bitfiled, otherwise it
|
/// If the provide offset is valid, it returns the boolean flag attribute bitfiled, otherwise it
|
||||||
/// returns the error message.
|
/// returns the error message.
|
||||||
pub fn get_boolean_flag_attribute(file: &Mmap, offset: u32) -> Result<u8, AconfigStorageError> {
|
pub fn get_boolean_flag_attribute(file: &Mmap, index: u32) -> Result<u8, AconfigStorageError> {
|
||||||
find_boolean_flag_attribute(file, offset)
|
find_boolean_flag_attribute(file, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// *************************************** //
|
// *************************************** //
|
||||||
@@ -174,21 +176,21 @@ mod ffi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Package table query return for cc interlop
|
// Package table query return for cc interlop
|
||||||
pub struct PackageOffsetQueryCXX {
|
pub struct PackageReadContextQueryCXX {
|
||||||
pub query_success: bool,
|
pub query_success: bool,
|
||||||
pub error_message: String,
|
pub error_message: String,
|
||||||
pub package_exists: bool,
|
pub package_exists: bool,
|
||||||
pub package_id: u32,
|
pub package_id: u32,
|
||||||
pub boolean_offset: u32,
|
pub boolean_start_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag table query return for cc interlop
|
// Flag table query return for cc interlop
|
||||||
pub struct FlagOffsetQueryCXX {
|
pub struct FlagReadContextQueryCXX {
|
||||||
pub query_success: bool,
|
pub query_success: bool,
|
||||||
pub error_message: String,
|
pub error_message: String,
|
||||||
pub flag_exists: bool,
|
pub flag_exists: bool,
|
||||||
pub flag_type: u16,
|
pub flag_type: u16,
|
||||||
pub flag_id: u16,
|
pub flag_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag value query return for cc interlop
|
// Flag value query return for cc interlop
|
||||||
@@ -209,9 +211,16 @@ mod ffi {
|
|||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
pub fn get_storage_file_version_cxx(file_path: &str) -> VersionNumberQueryCXX;
|
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;
|
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
|
/// Implement the package offset interlop return type, create from actual package offset api return type
|
||||||
impl ffi::PackageOffsetQueryCXX {
|
impl ffi::PackageReadContextQueryCXX {
|
||||||
pub(crate) fn new(offset_result: Result<Option<PackageOffset>, AconfigStorageError>) -> Self {
|
pub(crate) fn new(
|
||||||
|
offset_result: Result<Option<PackageReadContext>, AconfigStorageError>,
|
||||||
|
) -> Self {
|
||||||
match offset_result {
|
match offset_result {
|
||||||
Ok(offset_opt) => match offset_opt {
|
Ok(offset_opt) => match offset_opt {
|
||||||
Some(offset) => Self {
|
Some(offset) => Self {
|
||||||
@@ -232,14 +243,14 @@ impl ffi::PackageOffsetQueryCXX {
|
|||||||
error_message: String::from(""),
|
error_message: String::from(""),
|
||||||
package_exists: true,
|
package_exists: true,
|
||||||
package_id: offset.package_id,
|
package_id: offset.package_id,
|
||||||
boolean_offset: offset.boolean_offset,
|
boolean_start_index: offset.boolean_start_index,
|
||||||
},
|
},
|
||||||
None => Self {
|
None => Self {
|
||||||
query_success: true,
|
query_success: true,
|
||||||
error_message: String::from(""),
|
error_message: String::from(""),
|
||||||
package_exists: false,
|
package_exists: false,
|
||||||
package_id: 0,
|
package_id: 0,
|
||||||
boolean_offset: 0,
|
boolean_start_index: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Err(errmsg) => Self {
|
Err(errmsg) => Self {
|
||||||
@@ -247,15 +258,15 @@ impl ffi::PackageOffsetQueryCXX {
|
|||||||
error_message: format!("{:?}", errmsg),
|
error_message: format!("{:?}", errmsg),
|
||||||
package_exists: false,
|
package_exists: false,
|
||||||
package_id: 0,
|
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
|
/// Implement the flag offset interlop return type, create from actual flag offset api return type
|
||||||
impl ffi::FlagOffsetQueryCXX {
|
impl ffi::FlagReadContextQueryCXX {
|
||||||
pub(crate) fn new(offset_result: Result<Option<FlagOffset>, AconfigStorageError>) -> Self {
|
pub(crate) fn new(offset_result: Result<Option<FlagReadContext>, AconfigStorageError>) -> Self {
|
||||||
match offset_result {
|
match offset_result {
|
||||||
Ok(offset_opt) => match offset_opt {
|
Ok(offset_opt) => match offset_opt {
|
||||||
Some(offset) => Self {
|
Some(offset) => Self {
|
||||||
@@ -263,14 +274,14 @@ impl ffi::FlagOffsetQueryCXX {
|
|||||||
error_message: String::from(""),
|
error_message: String::from(""),
|
||||||
flag_exists: true,
|
flag_exists: true,
|
||||||
flag_type: offset.flag_type as u16,
|
flag_type: offset.flag_type as u16,
|
||||||
flag_id: offset.flag_id,
|
flag_index: offset.flag_index,
|
||||||
},
|
},
|
||||||
None => Self {
|
None => Self {
|
||||||
query_success: true,
|
query_success: true,
|
||||||
error_message: String::from(""),
|
error_message: String::from(""),
|
||||||
flag_exists: false,
|
flag_exists: false,
|
||||||
flag_type: 0u16,
|
flag_type: 0u16,
|
||||||
flag_id: 0u16,
|
flag_index: 0u16,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Err(errmsg) => Self {
|
Err(errmsg) => Self {
|
||||||
@@ -278,7 +289,7 @@ impl ffi::FlagOffsetQueryCXX {
|
|||||||
error_message: format!("{:?}", errmsg),
|
error_message: format!("{:?}", errmsg),
|
||||||
flag_exists: false,
|
flag_exists: false,
|
||||||
flag_type: 0u16,
|
flag_type: 0u16,
|
||||||
flag_id: 0u16,
|
flag_index: 0u16,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,14 +346,18 @@ impl ffi::VersionNumberQueryCXX {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get package start offset cc interlop
|
/// Get package read context cc interlop
|
||||||
pub fn get_package_offset_cxx(file: &[u8], package: &str) -> ffi::PackageOffsetQueryCXX {
|
pub fn get_package_read_context_cxx(file: &[u8], package: &str) -> ffi::PackageReadContextQueryCXX {
|
||||||
ffi::PackageOffsetQueryCXX::new(find_package_offset(file, package))
|
ffi::PackageReadContextQueryCXX::new(find_package_read_context(file, package))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get flag start offset cc interlop
|
/// Get flag read context cc interlop
|
||||||
pub fn get_flag_offset_cxx(file: &[u8], package_id: u32, flag: &str) -> ffi::FlagOffsetQueryCXX {
|
pub fn get_flag_read_context_cxx(
|
||||||
ffi::FlagOffsetQueryCXX::new(find_flag_offset(file, package_id, flag))
|
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
|
/// Get boolean flag value cc interlop
|
||||||
@@ -400,39 +415,39 @@ files {{
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// this test point locks down flag package offset query
|
// this test point locks down flag package read context query
|
||||||
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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
let package_mapped_file = unsafe {
|
let package_mapped_file = unsafe {
|
||||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_1")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
|
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_2")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
|
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_4")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
|
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// this test point locks down flag offset query
|
// this test point locks down flag read context query
|
||||||
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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
let flag_mapped_file =
|
let flag_mapped_file =
|
||||||
@@ -448,11 +463,11 @@ files {{
|
|||||||
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
||||||
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
||||||
];
|
];
|
||||||
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
|
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
|
||||||
let flag_offset =
|
let flag_context =
|
||||||
get_flag_offset(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
|
get_flag_read_context(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
|
||||||
assert_eq!(flag_offset.flag_type, flag_type);
|
assert_eq!(flag_context.flag_type, flag_type);
|
||||||
assert_eq!(flag_offset.flag_id, flag_id);
|
assert_eq!(flag_context.flag_index, flag_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,16 +24,16 @@ use anyhow::anyhow;
|
|||||||
|
|
||||||
/// Package table query return
|
/// Package table query return
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct PackageOffset {
|
pub struct PackageReadContext {
|
||||||
pub package_id: u32,
|
pub package_id: u32,
|
||||||
pub boolean_offset: u32,
|
pub boolean_start_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query package id and start offset
|
/// Query package read context: package id and start index
|
||||||
pub fn find_package_offset(
|
pub fn find_package_read_context(
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
package: &str,
|
package: &str,
|
||||||
) -> Result<Option<PackageOffset>, AconfigStorageError> {
|
) -> Result<Option<PackageReadContext>, AconfigStorageError> {
|
||||||
let interpreted_header = PackageTableHeader::from_bytes(buf)?;
|
let interpreted_header = PackageTableHeader::from_bytes(buf)?;
|
||||||
if interpreted_header.version > FILE_VERSION {
|
if interpreted_header.version > FILE_VERSION {
|
||||||
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
|
||||||
@@ -57,9 +57,9 @@ pub fn find_package_offset(
|
|||||||
loop {
|
loop {
|
||||||
let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
|
let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
|
||||||
if interpreted_node.package_name == package {
|
if interpreted_node.package_name == package {
|
||||||
return Ok(Some(PackageOffset {
|
return Ok(Some(PackageReadContext {
|
||||||
package_id: interpreted_node.package_id,
|
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 {
|
match interpreted_node.next_offset {
|
||||||
@@ -78,24 +78,24 @@ mod tests {
|
|||||||
// this test point locks down table query
|
// this test point locks down table query
|
||||||
fn test_package_query() {
|
fn test_package_query() {
|
||||||
let package_table = create_test_package_table().into_bytes();
|
let package_table = create_test_package_table().into_bytes();
|
||||||
let package_offset =
|
let package_context =
|
||||||
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
|
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
let package_offset =
|
let package_context =
|
||||||
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_2")
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
|
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
let package_offset =
|
let package_context =
|
||||||
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_4")
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
|
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -103,13 +103,15 @@ mod tests {
|
|||||||
fn test_not_existed_package_query() {
|
fn test_not_existed_package_query() {
|
||||||
// this will land at an empty bucket
|
// this will land at an empty bucket
|
||||||
let package_table = create_test_package_table().into_bytes();
|
let package_table = create_test_package_table().into_bytes();
|
||||||
let package_offset =
|
let package_context =
|
||||||
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_3").unwrap();
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_3")
|
||||||
assert_eq!(package_offset, None);
|
.unwrap();
|
||||||
|
assert_eq!(package_context, None);
|
||||||
// this will land at the end of a linked list
|
// this will land at the end of a linked list
|
||||||
let package_offset =
|
let package_context =
|
||||||
find_package_offset(&package_table[..], "com.android.aconfig.storage.test_5").unwrap();
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_5")
|
||||||
assert_eq!(package_offset, None);
|
.unwrap();
|
||||||
|
assert_eq!(package_context, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -118,8 +120,9 @@ mod tests {
|
|||||||
let mut table = create_test_package_table();
|
let mut table = create_test_package_table();
|
||||||
table.header.version = crate::FILE_VERSION + 1;
|
table.header.version = crate::FILE_VERSION + 1;
|
||||||
let package_table = table.into_bytes();
|
let package_table = table.into_bytes();
|
||||||
let error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
|
let error =
|
||||||
.unwrap_err();
|
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
|
||||||
|
.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", error),
|
format!("{:?}", error),
|
||||||
format!(
|
format!(
|
||||||
|
@@ -104,6 +104,9 @@ TEST_F(AconfigStorageTest, test_storage_version_query) {
|
|||||||
version = api::get_storage_file_version(flag_val);
|
version = api::get_storage_file_version(flag_val);
|
||||||
ASSERT_TRUE(version.ok());
|
ASSERT_TRUE(version.ok());
|
||||||
ASSERT_EQ(*version, 1);
|
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
|
/// 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");
|
"Unable to find storage files for container vendor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test to lock down storage package offset query api
|
/// Test to lock down storage package context query api
|
||||||
TEST_F(AconfigStorageTest, test_package_offset_query) {
|
TEST_F(AconfigStorageTest, test_package_context_query) {
|
||||||
auto mapped_file = private_api::get_mapped_file_impl(
|
auto mapped_file = private_api::get_mapped_file_impl(
|
||||||
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
||||||
ASSERT_TRUE(mapped_file.ok());
|
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");
|
*mapped_file, "com.android.aconfig.storage.test_1");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_TRUE(offset->package_exists);
|
ASSERT_TRUE(context->package_exists);
|
||||||
ASSERT_EQ(offset->package_id, 0);
|
ASSERT_EQ(context->package_id, 0);
|
||||||
ASSERT_EQ(offset->boolean_offset, 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");
|
*mapped_file, "com.android.aconfig.storage.test_2");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_TRUE(offset->package_exists);
|
ASSERT_TRUE(context->package_exists);
|
||||||
ASSERT_EQ(offset->package_id, 1);
|
ASSERT_EQ(context->package_id, 1);
|
||||||
ASSERT_EQ(offset->boolean_offset, 3);
|
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");
|
*mapped_file, "com.android.aconfig.storage.test_4");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_TRUE(offset->package_exists);
|
ASSERT_TRUE(context->package_exists);
|
||||||
ASSERT_EQ(offset->package_id, 2);
|
ASSERT_EQ(context->package_id, 2);
|
||||||
ASSERT_EQ(offset->boolean_offset, 6);
|
ASSERT_EQ(context->boolean_start_index, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test to lock down when querying none exist package
|
/// 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(
|
auto mapped_file = private_api::get_mapped_file_impl(
|
||||||
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
||||||
ASSERT_TRUE(mapped_file.ok());
|
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");
|
*mapped_file, "com.android.aconfig.storage.test_3");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_FALSE(offset->package_exists);
|
ASSERT_FALSE(context->package_exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test to lock down storage flag offset query api
|
/// Test to lock down storage flag context query api
|
||||||
TEST_F(AconfigStorageTest, test_flag_offset_query) {
|
TEST_F(AconfigStorageTest, test_flag_context_query) {
|
||||||
auto mapped_file = private_api::get_mapped_file_impl(
|
auto mapped_file = private_api::get_mapped_file_impl(
|
||||||
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
||||||
ASSERT_TRUE(mapped_file.ok());
|
ASSERT_TRUE(mapped_file.ok());
|
||||||
@@ -171,28 +174,28 @@ TEST_F(AconfigStorageTest, test_flag_offset_query) {
|
|||||||
{2, "enabled_fixed_ro", api::StoredFlagType::FixedReadOnlyBoolean, 0},
|
{2, "enabled_fixed_ro", api::StoredFlagType::FixedReadOnlyBoolean, 0},
|
||||||
{0, "disabled_rw", api::StoredFlagType::ReadWriteBoolean, 0},
|
{0, "disabled_rw", api::StoredFlagType::ReadWriteBoolean, 0},
|
||||||
};
|
};
|
||||||
for (auto const&[package_id, flag_name, flag_type, flag_id] : baseline) {
|
for (auto const&[package_id, flag_name, flag_type, flag_index] : baseline) {
|
||||||
auto offset = api::get_flag_offset(*mapped_file, package_id, flag_name);
|
auto context = api::get_flag_read_context(*mapped_file, package_id, flag_name);
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_TRUE(offset->flag_exists);
|
ASSERT_TRUE(context->flag_exists);
|
||||||
ASSERT_EQ(offset->flag_type, flag_type);
|
ASSERT_EQ(context->flag_type, flag_type);
|
||||||
ASSERT_EQ(offset->flag_id, flag_id);
|
ASSERT_EQ(context->flag_index, flag_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test to lock down when querying none exist flag
|
/// 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(
|
auto mapped_file = private_api::get_mapped_file_impl(
|
||||||
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
||||||
ASSERT_TRUE(mapped_file.ok());
|
ASSERT_TRUE(mapped_file.ok());
|
||||||
|
|
||||||
auto offset = api::get_flag_offset(*mapped_file, 0, "none_exist");
|
auto context = api::get_flag_read_context(*mapped_file, 0, "none_exist");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_FALSE(offset->flag_exists);
|
ASSERT_FALSE(context->flag_exists);
|
||||||
|
|
||||||
offset = api::get_flag_offset(*mapped_file, 3, "enabled_ro");
|
context = api::get_flag_read_context(*mapped_file, 3, "enabled_ro");
|
||||||
ASSERT_TRUE(offset.ok());
|
ASSERT_TRUE(context.ok());
|
||||||
ASSERT_FALSE(offset->flag_exists);
|
ASSERT_FALSE(context->flag_exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test to lock down storage flag value query api
|
/// 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>{
|
auto expected_value = std::vector<bool>{
|
||||||
false, true, true, false, true, true, true, true};
|
false, true, true, false, true, true, true, true};
|
||||||
for (int offset = 0; offset < 8; ++offset) {
|
for (int index = 0; index < 8; ++index) {
|
||||||
auto value = api::get_boolean_flag_value(*mapped_file, offset);
|
auto value = api::get_boolean_flag_value(*mapped_file, index);
|
||||||
ASSERT_TRUE(value.ok());
|
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>{
|
auto expected_value = std::vector<bool>{
|
||||||
true, false, true, false, false, false, false, false};
|
true, false, true, false, false, false, false, false};
|
||||||
for (int offset = 0; offset < 8; ++offset) {
|
for (int index = 0; index < 8; ++index) {
|
||||||
auto attribute = api::get_boolean_flag_attribute(*mapped_file, offset);
|
auto attribute = api::get_boolean_flag_attribute(*mapped_file, index);
|
||||||
ASSERT_TRUE(attribute.ok());
|
ASSERT_TRUE(attribute.ok());
|
||||||
ASSERT_EQ(*attribute & static_cast<uint8_t>(api::FlagInfoBit::IsSticky), 0);
|
ASSERT_EQ(*attribute & static_cast<uint8_t>(api::FlagInfoBit::IsSticky), 0);
|
||||||
ASSERT_EQ((*attribute & static_cast<uint8_t>(api::FlagInfoBit::IsReadWrite)) != 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);
|
ASSERT_EQ(*attribute & static_cast<uint8_t>(api::FlagInfoBit::HasOverride), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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::protos::storage_record_pb::write_proto_to_temp_file;
|
||||||
use aconfig_storage_file::{FlagInfoBit, StorageFileType, StoredFlagType};
|
use aconfig_storage_file::{FlagInfoBit, StorageFileType, StoredFlagType};
|
||||||
use aconfig_storage_read_api::{
|
use aconfig_storage_read_api::{
|
||||||
get_boolean_flag_attribute, get_boolean_flag_value, get_flag_offset, get_package_offset,
|
get_boolean_flag_attribute, get_boolean_flag_value, get_flag_read_context,
|
||||||
get_storage_file_version, mapped_file::get_mapped_file, PackageOffset,
|
get_package_read_context, get_storage_file_version, mapped_file::get_mapped_file,
|
||||||
|
PackageReadContext,
|
||||||
};
|
};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
@@ -58,7 +59,7 @@ files {{
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@@ -67,30 +68,30 @@ files {{
|
|||||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_1")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
|
let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_2")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
|
let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
|
|
||||||
let package_offset =
|
let package_context =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_4")
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
|
let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
|
||||||
assert_eq!(package_offset, expected_package_offset);
|
assert_eq!(package_context, expected_package_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@@ -99,13 +100,14 @@ files {{
|
|||||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let package_offset_option =
|
let package_context_option =
|
||||||
get_package_offset(&package_mapped_file, "com.android.aconfig.storage.test_3").unwrap();
|
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_3")
|
||||||
assert_eq!(package_offset_option, None);
|
.unwrap();
|
||||||
|
assert_eq!(package_context_option, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@@ -123,27 +125,29 @@ files {{
|
|||||||
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
(2, "enabled_fixed_ro", StoredFlagType::FixedReadOnlyBoolean, 0u16),
|
||||||
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
(0, "disabled_rw", StoredFlagType::ReadWriteBoolean, 0u16),
|
||||||
];
|
];
|
||||||
for (package_id, flag_name, flag_type, flag_id) in baseline.into_iter() {
|
for (package_id, flag_name, flag_type, flag_index) in baseline.into_iter() {
|
||||||
let flag_offset =
|
let flag_context =
|
||||||
get_flag_offset(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
|
get_flag_read_context(&flag_mapped_file, package_id, flag_name).unwrap().unwrap();
|
||||||
assert_eq!(flag_offset.flag_type, flag_type);
|
assert_eq!(flag_context.flag_type, flag_type);
|
||||||
assert_eq!(flag_offset.flag_id, flag_id);
|
assert_eq!(flag_context.flag_index, flag_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 [_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 pb_file_path = pb_file.path().display().to_string();
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// The safety here is ensured as the test process will not write to temp storage file
|
// The safety here is ensured as the test process will not write to temp storage file
|
||||||
let flag_mapped_file =
|
let flag_mapped_file =
|
||||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() };
|
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();
|
let flag_context_option =
|
||||||
assert_eq!(flag_offset_option, None);
|
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();
|
let flag_context_option =
|
||||||
assert_eq!(flag_offset_option, None);
|
get_flag_read_context(&flag_mapped_file, 3, "enabled_ro").unwrap();
|
||||||
|
assert_eq!(flag_context_option, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -22,7 +22,7 @@ use anyhow::anyhow;
|
|||||||
/// Set flag value
|
/// Set flag value
|
||||||
pub fn update_boolean_flag_value(
|
pub fn update_boolean_flag_value(
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
flag_offset: u32,
|
flag_index: u32,
|
||||||
flag_value: bool,
|
flag_value: bool,
|
||||||
) -> Result<(), AconfigStorageError> {
|
) -> Result<(), AconfigStorageError> {
|
||||||
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
|
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
|
||||||
@@ -34,10 +34,8 @@ pub fn update_boolean_flag_value(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = (interpreted_header.boolean_value_offset + flag_offset) as usize;
|
// get byte offset to the flag
|
||||||
|
let head = (interpreted_header.boolean_value_offset + flag_index) 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).
|
|
||||||
if head >= interpreted_header.file_size as usize {
|
if head >= interpreted_header.file_size as usize {
|
||||||
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
|
||||||
"Flag value offset goes beyond the end of the file."
|
"Flag value offset goes beyond the end of the file."
|
||||||
|
@@ -55,16 +55,16 @@ pub unsafe fn get_mapped_flag_value_file(container: &str) -> Result<MmapMut, Aco
|
|||||||
/// Set boolean flag value thru mapped file and flush the change to file
|
/// Set boolean flag value thru mapped file and flush the change to file
|
||||||
///
|
///
|
||||||
/// \input mapped_file: the mapped flag value file
|
/// \input mapped_file: the mapped flag value file
|
||||||
/// \input offset: flag value offset
|
/// \input index: flag index
|
||||||
/// \input value: updated flag value
|
/// \input value: updated flag value
|
||||||
/// \return a result of ()
|
/// \return a result of ()
|
||||||
///
|
///
|
||||||
pub fn set_boolean_flag_value(
|
pub fn set_boolean_flag_value(
|
||||||
file: &mut MmapMut,
|
file: &mut MmapMut,
|
||||||
offset: u32,
|
index: u32,
|
||||||
value: bool,
|
value: bool,
|
||||||
) -> Result<(), AconfigStorageError> {
|
) -> Result<(), AconfigStorageError> {
|
||||||
crate::flag_value_update::update_boolean_flag_value(file, offset, value)?;
|
crate::flag_value_update::update_boolean_flag_value(file, index, value)?;
|
||||||
file.flush().map_err(|errmsg| {
|
file.flush().map_err(|errmsg| {
|
||||||
AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
|
AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
|
||||||
})
|
})
|
||||||
@@ -106,15 +106,15 @@ pub fn create_flag_info(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut package_offsets = vec![0; package_table.header.num_packages as usize];
|
let mut package_start_index = vec![0; package_table.header.num_packages as usize];
|
||||||
for node in package_table.nodes.iter() {
|
for node in package_table.nodes.iter() {
|
||||||
package_offsets[node.package_id as usize] = node.boolean_offset;
|
package_start_index[node.package_id as usize] = node.boolean_start_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
|
let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
|
||||||
for node in flag_table.nodes.iter() {
|
for node in flag_table.nodes.iter() {
|
||||||
let flag_offset = package_offsets[node.package_id as usize] + node.flag_id as u32;
|
let flag_index = package_start_index[node.package_id as usize] + node.flag_index as u32;
|
||||||
is_flag_rw[flag_offset as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
|
is_flag_rw[flag_index as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut list = FlagInfoList {
|
let mut list = FlagInfoList {
|
||||||
|
Reference in New Issue
Block a user