Merge "aconfig: add a new aconfig storage file flag listing api" into main

This commit is contained in:
Dennis Shen
2024-04-30 23:06:18 +00:00
committed by Gerrit Code Review
19 changed files with 562 additions and 75 deletions

View File

@@ -97,5 +97,9 @@
}
],
"postsubmit": [
{
// aconfig_storage file cpp integration tests
"name": "aconfig_storage_file.test.cpp"
}
]
}

View File

@@ -12,6 +12,7 @@ rust_defaults {
"libtempfile",
"libprotobuf",
"libclap",
"libcxx",
"libaconfig_storage_protos",
],
}
@@ -77,3 +78,62 @@ cc_library {
product_available: true,
double_loadable: true,
}
// cxx source codegen from rust api
genrule {
name: "libcxx_aconfig_storage_file_bridge_code",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) > $(out)",
srcs: ["src/lib.rs"],
out: ["aconfig_storage/lib.rs.cc"],
}
// cxx header codegen from rust api
genrule {
name: "libcxx_aconfig_storage_file_bridge_header",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) --header > $(out)",
srcs: ["src/lib.rs"],
out: ["aconfig_storage/lib.rs.h"],
}
// a static cc lib based on generated code
rust_ffi_static {
name: "libaconfig_storage_file_cxx_bridge",
crate_name: "aconfig_storage_file_cxx_bridge",
host_supported: true,
vendor_available: true,
product_available: true,
srcs: ["src/lib.rs"],
defaults: ["aconfig_storage_file.defaults"],
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
],
min_sdk_version: "29",
}
// storage file parse api cc interface
cc_library {
name: "libaconfig_storage_file_cc",
srcs: ["aconfig_storage_file.cpp"],
generated_headers: [
"cxx-bridge-header",
"libcxx_aconfig_storage_file_bridge_header",
],
generated_sources: ["libcxx_aconfig_storage_file_bridge_code"],
whole_static_libs: ["libaconfig_storage_file_cxx_bridge"],
export_include_dirs: ["include"],
host_supported: true,
vendor_available: true,
product_available: true,
shared_libs: [
"libbase",
],
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
],
min_sdk_version: "29",
double_loadable: true,
}

View File

@@ -13,6 +13,7 @@ protobuf = "3.2.0"
tempfile = "3.9.0"
thiserror = "1.0.56"
clap = { version = "4.1.8", features = ["derive"] }
cxx = "1.0"
[[bin]]
name = "aconfig-storage"

View File

@@ -0,0 +1,38 @@
#include "rust/cxx.h"
#include "aconfig_storage/lib.rs.h"
#include "aconfig_storage/aconfig_storage_file.hpp"
using namespace android::base;
namespace aconfig_storage {
Result<std::vector<FlagValueAndInfoSummary>> list_flags_with_info(
const std::string& package_map,
const std::string& flag_map,
const std::string& flag_val,
const std::string& flag_info) {
auto flag_list_cxx = list_flags_with_info_cxx(rust::Str(package_map.c_str()),
rust::Str(flag_map.c_str()),
rust::Str(flag_val.c_str()),
rust::Str(flag_info.c_str()));
if (flag_list_cxx.query_success) {
auto flag_list = std::vector<FlagValueAndInfoSummary>();
for (const auto& flag_cxx : flag_list_cxx.flags) {
auto flag = FlagValueAndInfoSummary();
flag.package_name = std::string(flag_cxx.package_name);
flag.flag_name = std::string(flag_cxx.flag_name);
flag.flag_value = std::string(flag_cxx.flag_value);
flag.value_type = std::string(flag_cxx.value_type);
flag.is_readwrite = flag_cxx.is_readwrite;
flag.has_server_override = flag_cxx.has_server_override;
flag.has_local_override = flag_cxx.has_local_override;
flag_list.push_back(flag);
}
return flag_list;
} else {
return Error() << flag_list_cxx.error_message;
}
}
} // namespace aconfig_storage

View File

@@ -14,4 +14,6 @@ fn main() {
.inputs(proto_files)
.cargo_out_dir("aconfig_storage_protos")
.run_from_script();
let _ = cxx_build::bridge("src/lib.rs");
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <string>
#include <android-base/result.h>
namespace aconfig_storage {
/// Flag value and info summary for a flag
struct FlagValueAndInfoSummary {
std::string package_name;
std::string flag_name;
std::string flag_value;
std::string value_type;
bool is_readwrite;
bool has_server_override;
bool has_local_override;
};
/// List all flag values with their flag info
/// \input package_map: package map file
/// \input flag_map: flag map file
/// \input flag_val: flag value file
/// \input flag_info: flag info file
android::base::Result<std::vector<FlagValueAndInfoSummary>> list_flags_with_info(
const std::string& package_map,
const std::string& flag_map,
const std::string& flag_val,
const std::string& flag_info);
}// namespace aconfig_storage

View File

@@ -278,12 +278,21 @@ pub fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, AconfigStorageErro
Ok(buffer)
}
/// Flag value summary
#[derive(Debug, PartialEq)]
pub struct FlagValueSummary {
pub package_name: String,
pub flag_name: String,
pub flag_value: String,
pub value_type: StoredFlagType,
}
/// List flag values from storage files
pub fn list_flags(
package_map: &str,
flag_map: &str,
flag_val: &str,
) -> Result<Vec<(String, String, StoredFlagType, bool)>, AconfigStorageError> {
) -> Result<Vec<FlagValueSummary>, AconfigStorageError> {
let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?;
@@ -295,30 +304,155 @@ pub fn list_flags(
let mut flags = Vec::new();
for node in flag_table.nodes.iter() {
let (package_name, package_offset) = package_info[node.package_id as usize];
let flag_offset = package_offset + node.flag_index as u32;
let flag_value = flag_value_list.booleans[flag_offset as usize];
flags.push((
String::from(package_name),
node.flag_name.clone(),
node.flag_type,
flag_value,
));
let (package_name, boolean_start_index) = package_info[node.package_id as usize];
let flag_index = boolean_start_index + node.flag_index as u32;
let flag_value = flag_value_list.booleans[flag_index as usize];
flags.push(FlagValueSummary {
package_name: String::from(package_name),
flag_name: node.flag_name.clone(),
flag_value: flag_value.to_string(),
value_type: node.flag_type,
});
}
flags.sort_by(|v1, v2| match v1.0.cmp(&v2.0) {
Ordering::Equal => v1.1.cmp(&v2.1),
flags.sort_by(|v1, v2| match v1.package_name.cmp(&v2.package_name) {
Ordering::Equal => v1.flag_name.cmp(&v2.flag_name),
other => other,
});
Ok(flags)
}
/// Flag value and info summary
#[derive(Debug, PartialEq)]
pub struct FlagValueAndInfoSummary {
pub package_name: String,
pub flag_name: String,
pub flag_value: String,
pub value_type: StoredFlagType,
pub is_readwrite: bool,
pub has_server_override: bool,
pub has_local_override: bool,
}
/// List flag values and info from storage files
pub fn list_flags_with_info(
package_map: &str,
flag_map: &str,
flag_val: &str,
flag_info: &str,
) -> Result<Vec<FlagValueAndInfoSummary>, AconfigStorageError> {
let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?;
let flag_info = FlagInfoList::from_bytes(&read_file_to_bytes(flag_info)?)?;
let mut package_info = vec![("", 0); package_table.header.num_packages as usize];
for node in package_table.nodes.iter() {
package_info[node.package_id as usize] = (&node.package_name, node.boolean_start_index);
}
let mut flags = Vec::new();
for node in flag_table.nodes.iter() {
let (package_name, boolean_start_index) = package_info[node.package_id as usize];
let flag_index = boolean_start_index + node.flag_index as u32;
let flag_value = flag_value_list.booleans[flag_index as usize];
let flag_attribute = flag_info.nodes[flag_index as usize].attributes;
flags.push(FlagValueAndInfoSummary {
package_name: String::from(package_name),
flag_name: node.flag_name.clone(),
flag_value: flag_value.to_string(),
value_type: node.flag_type,
is_readwrite: flag_attribute & (FlagInfoBit::IsReadWrite as u8) != 0,
has_server_override: flag_attribute & (FlagInfoBit::HasServerOverride as u8) != 0,
has_local_override: flag_attribute & (FlagInfoBit::HasLocalOverride as u8) != 0,
});
}
flags.sort_by(|v1, v2| match v1.package_name.cmp(&v2.package_name) {
Ordering::Equal => v1.flag_name.cmp(&v2.flag_name),
other => other,
});
Ok(flags)
}
// *************************************** //
// CC INTERLOP
// *************************************** //
// Exported rust data structure and methods, c++ code will be generated
#[cxx::bridge]
mod ffi {
/// flag value and info summary cxx return
pub struct FlagValueAndInfoSummaryCXX {
pub package_name: String,
pub flag_name: String,
pub flag_value: String,
pub value_type: String,
pub is_readwrite: bool,
pub has_server_override: bool,
pub has_local_override: bool,
}
/// list flag result cxx return
pub struct ListFlagValueAndInfoResultCXX {
pub query_success: bool,
pub error_message: String,
pub flags: Vec<FlagValueAndInfoSummaryCXX>,
}
// Rust export to c++
extern "Rust" {
pub fn list_flags_with_info_cxx(
package_map: &str,
flag_map: &str,
flag_val: &str,
flag_info: &str,
) -> ListFlagValueAndInfoResultCXX;
}
}
/// implement flag value and info summary cxx return type
impl ffi::FlagValueAndInfoSummaryCXX {
pub(crate) fn new(summary: FlagValueAndInfoSummary) -> Self {
Self {
package_name: summary.package_name,
flag_name: summary.flag_name,
flag_value: summary.flag_value,
value_type: format!("{:?}", summary.value_type),
is_readwrite: summary.is_readwrite,
has_server_override: summary.has_server_override,
has_local_override: summary.has_local_override,
}
}
}
/// implement list flag with info cxx interlop
pub fn list_flags_with_info_cxx(
package_map: &str,
flag_map: &str,
flag_val: &str,
flag_info: &str,
) -> ffi::ListFlagValueAndInfoResultCXX {
match list_flags_with_info(package_map, flag_map, flag_val, flag_info) {
Ok(summary) => ffi::ListFlagValueAndInfoResultCXX {
query_success: true,
error_message: String::new(),
flags: summary.into_iter().map(ffi::FlagValueAndInfoSummaryCXX::new).collect(),
},
Err(errmsg) => ffi::ListFlagValueAndInfoResultCXX {
query_success: false,
error_message: format!("{:?}", errmsg),
flags: Vec::new(),
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{
create_test_flag_table, create_test_flag_value_list, create_test_package_table,
write_bytes_to_temp_file,
create_test_flag_info_list, create_test_flag_table, create_test_flag_value_list,
create_test_package_table, write_bytes_to_temp_file,
};
#[test]
@@ -337,54 +471,154 @@ mod tests {
let flags =
list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap();
let expected = [
(
String::from("com.android.aconfig.storage.test_1"),
String::from("disabled_rw"),
StoredFlagType::ReadWriteBoolean,
false,
),
(
String::from("com.android.aconfig.storage.test_1"),
String::from("enabled_ro"),
StoredFlagType::ReadOnlyBoolean,
true,
),
(
String::from("com.android.aconfig.storage.test_1"),
String::from("enabled_rw"),
StoredFlagType::ReadWriteBoolean,
true,
),
(
String::from("com.android.aconfig.storage.test_2"),
String::from("disabled_rw"),
StoredFlagType::ReadWriteBoolean,
false,
),
(
String::from("com.android.aconfig.storage.test_2"),
String::from("enabled_fixed_ro"),
StoredFlagType::FixedReadOnlyBoolean,
true,
),
(
String::from("com.android.aconfig.storage.test_2"),
String::from("enabled_ro"),
StoredFlagType::ReadOnlyBoolean,
true,
),
(
String::from("com.android.aconfig.storage.test_4"),
String::from("enabled_fixed_ro"),
StoredFlagType::FixedReadOnlyBoolean,
true,
),
(
String::from("com.android.aconfig.storage.test_4"),
String::from("enabled_rw"),
StoredFlagType::ReadWriteBoolean,
true,
),
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("disabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("false"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("enabled_ro"),
value_type: StoredFlagType::ReadOnlyBoolean,
flag_value: String::from("true"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("enabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("true"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("disabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("false"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("enabled_fixed_ro"),
value_type: StoredFlagType::FixedReadOnlyBoolean,
flag_value: String::from("true"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("enabled_ro"),
value_type: StoredFlagType::ReadOnlyBoolean,
flag_value: String::from("true"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_4"),
flag_name: String::from("enabled_fixed_ro"),
value_type: StoredFlagType::FixedReadOnlyBoolean,
flag_value: String::from("true"),
},
FlagValueSummary {
package_name: String::from("com.android.aconfig.storage.test_4"),
flag_name: String::from("enabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("true"),
},
];
assert_eq!(flags, expected);
}
#[test]
// this test point locks down the flag list with info api
fn test_list_flag_with_info() {
let package_table =
write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
let flag_value_list =
write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap();
let flag_info_list =
write_bytes_to_temp_file(&create_test_flag_info_list().into_bytes()).unwrap();
let package_table_path = package_table.path().display().to_string();
let flag_table_path = flag_table.path().display().to_string();
let flag_value_list_path = flag_value_list.path().display().to_string();
let flag_info_list_path = flag_info_list.path().display().to_string();
let flags = list_flags_with_info(
&package_table_path,
&flag_table_path,
&flag_value_list_path,
&flag_info_list_path,
)
.unwrap();
let expected = [
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("disabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("false"),
is_readwrite: true,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("enabled_ro"),
value_type: StoredFlagType::ReadOnlyBoolean,
flag_value: String::from("true"),
is_readwrite: false,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_1"),
flag_name: String::from("enabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("true"),
is_readwrite: true,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("disabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("false"),
is_readwrite: true,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("enabled_fixed_ro"),
value_type: StoredFlagType::FixedReadOnlyBoolean,
flag_value: String::from("true"),
is_readwrite: false,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_2"),
flag_name: String::from("enabled_ro"),
value_type: StoredFlagType::ReadOnlyBoolean,
flag_value: String::from("true"),
is_readwrite: false,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_4"),
flag_name: String::from("enabled_fixed_ro"),
value_type: StoredFlagType::FixedReadOnlyBoolean,
flag_value: String::from("true"),
is_readwrite: false,
has_server_override: false,
has_local_override: false,
},
FlagValueAndInfoSummary {
package_name: String::from("com.android.aconfig.storage.test_4"),
flag_name: String::from("enabled_rw"),
value_type: StoredFlagType::ReadWriteBoolean,
flag_value: String::from("true"),
is_readwrite: true,
has_server_override: false,
has_local_override: false,
},
];
assert_eq!(flags, expected);
}

View File

@@ -17,8 +17,8 @@
//! `aconfig-storage` is a debugging tool to parse storage files
use aconfig_storage_file::{
list_flags, read_file_to_bytes, AconfigStorageError, FlagInfoList, FlagTable, FlagValueList,
PackageTable, StorageFileType,
list_flags, list_flags_with_info, read_file_to_bytes, AconfigStorageError, FlagInfoList,
FlagTable, FlagValueList, PackageTable, StorageFileType,
};
use clap::{builder::ArgAction, Arg, Command};
@@ -45,7 +45,10 @@ fn cli() -> Command {
.action(ArgAction::Set),
)
.arg(Arg::new("flag-map").long("flag-map").required(true).action(ArgAction::Set))
.arg(Arg::new("flag-val").long("flag-val").required(true).action(ArgAction::Set)),
.arg(Arg::new("flag-val").long("flag-val").required(true).action(ArgAction::Set))
.arg(
Arg::new("flag-info").long("flag-info").required(false).action(ArgAction::Set),
),
)
}
@@ -87,9 +90,27 @@ fn main() -> Result<(), AconfigStorageError> {
let package_map = sub_matches.get_one::<String>("package-map").unwrap();
let flag_map = sub_matches.get_one::<String>("flag-map").unwrap();
let flag_val = sub_matches.get_one::<String>("flag-val").unwrap();
let flags = list_flags(package_map, flag_map, flag_val)?;
for (package_name, flag_name, flag_type, flag_value) in flags.iter() {
println!("{} {} {:?} {}", package_name, flag_name, flag_type, flag_value);
let flag_info = sub_matches.get_one::<String>("flag-info");
match flag_info {
Some(info_file) => {
let flags = list_flags_with_info(package_map, flag_map, flag_val, info_file)?;
for flag in flags.iter() {
println!(
"{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}",
flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
flag.is_readwrite, flag.has_server_override, flag.has_local_override,
);
}
}
None => {
let flags = list_flags(package_map, flag_map, flag_val)?;
for flag in flags.iter() {
println!(
"{} {} {} {:?}",
flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
);
}
}
}
}
_ => unreachable!(),

View File

@@ -0,0 +1,23 @@
cc_test {
name: "aconfig_storage_file.test.cpp",
team: "trendy_team_android_core_experiments",
srcs: [
"storage_file_test.cpp",
],
static_libs: [
"libgmock",
"libaconfig_storage_file_cc",
"libbase",
],
data: [
"package.map",
"flag.map",
"flag.val",
"flag.info",
],
test_suites: [
"device-tests",
"general-tests",
],
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/result.h>
#include <gtest/gtest.h>
#include "aconfig_storage/aconfig_storage_file.hpp"
using namespace android::base;
using namespace aconfig_storage;
void verify_flag(const FlagValueAndInfoSummary& flag,
const std::string& package_name,
const std::string& flag_name,
const std::string& flag_val,
const std::string& value_type,
bool is_readwrite,
bool has_server_override,
bool has_local_override) {
ASSERT_EQ(flag.package_name, package_name);
ASSERT_EQ(flag.flag_name, flag_name);
ASSERT_EQ(flag.flag_value, flag_val);
ASSERT_EQ(flag.value_type, value_type);
ASSERT_EQ(flag.is_readwrite, is_readwrite);
ASSERT_EQ(flag.has_server_override, has_server_override);
ASSERT_EQ(flag.has_local_override, has_local_override);
}
TEST(AconfigStorageFileTest, test_list_flag_with_info) {
auto const test_dir = GetExecutableDirectory();
auto const package_map = test_dir + "/package.map";
auto const flag_map = test_dir + "/flag.map";
auto const flag_val = test_dir + "/flag.val";
auto const flag_info = test_dir + "/flag.info";
auto flag_list_result = aconfig_storage::list_flags_with_info(
package_map, flag_map, flag_val, flag_info);
ASSERT_TRUE(flag_list_result.ok());
auto const& flag_list = *flag_list_result;
ASSERT_EQ(flag_list.size(), 8);
verify_flag(flag_list[0], "com.android.aconfig.storage.test_1", "disabled_rw",
"false", "ReadWriteBoolean", true, false, false);
verify_flag(flag_list[1], "com.android.aconfig.storage.test_1", "enabled_ro",
"true", "ReadOnlyBoolean", false, false, false);
verify_flag(flag_list[2], "com.android.aconfig.storage.test_1", "enabled_rw",
"true", "ReadWriteBoolean", true, false, false);
verify_flag(flag_list[3], "com.android.aconfig.storage.test_2", "disabled_rw",
"false", "ReadWriteBoolean", true, false, false);
verify_flag(flag_list[4], "com.android.aconfig.storage.test_2", "enabled_fixed_ro",
"true", "FixedReadOnlyBoolean", false, false, false);
verify_flag(flag_list[5], "com.android.aconfig.storage.test_2", "enabled_ro",
"true", "ReadOnlyBoolean", false, false, false);
verify_flag(flag_list[6], "com.android.aconfig.storage.test_4", "enabled_fixed_ro",
"true", "FixedReadOnlyBoolean", false, false, false);
verify_flag(flag_list[7], "com.android.aconfig.storage.test_4", "enabled_rw",
"true", "ReadWriteBoolean", true, false, false);
}

View File

@@ -504,7 +504,7 @@ files {{
let pb_file_path = pb_file.path().display().to_string();
let flag_info_file =
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() };
let is_rw: Vec<bool> = vec![true, false, true, false, false, false, false, false];
let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true];
for (offset, expected_value) in is_rw.into_iter().enumerate() {
let attribute =
get_flag_attribute(&flag_info_file, FlagValueType::Boolean, offset as u32).unwrap();

View File

@@ -232,7 +232,7 @@ TEST_F(AconfigStorageTest, test_boolean_flag_info_query) {
ASSERT_TRUE(mapped_file.ok());
auto expected_value = std::vector<bool>{
true, false, true, false, false, false, false, false};
true, false, true, true, false, false, false, true};
for (int index = 0; index < 8; ++index) {
auto attribute = api::get_flag_attribute(*mapped_file, api::FlagValueType::Boolean, index);
ASSERT_TRUE(attribute.ok());

View File

@@ -188,7 +188,7 @@ files {{
// The safety here is ensured as the test process will not write to temp storage file
let flag_info_file =
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() };
let is_rw: Vec<bool> = vec![true, false, true, false, false, false, false, false];
let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true];
for (offset, expected_value) in is_rw.into_iter().enumerate() {
let attribute =
get_flag_attribute(&flag_info_file, FlagValueType::Boolean, offset as u32).unwrap();

View File

@@ -27,13 +27,13 @@ impl FlagSource for AconfigStorageSource {
let container =
file_info.container.ok_or(anyhow!("storage file is missing container"))?;
for (package, name, _flag_type, val) in
for listed_flag in
aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)?
{
result.push(Flag {
name: name.to_string(),
package: package.to_string(),
value: FlagValue::try_from(val.to_string().as_str())?,
name: listed_flag.flag_name,
package: listed_flag.package_name,
value: FlagValue::try_from(listed_flag.flag_value.as_str())?,
container: container.to_string(),
// TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.