Merge "Revert^2 "Cache Java codegen'd flags in static member variables."" into main am: ca355c09a2 am: c0e30a22e6

Original change: https://android-review.googlesource.com/c/platform/build/+/2833310

Change-Id: Ic735c83a09c5a61705fc87bb25475e4000dc329e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Ted Bauer
2023-11-16 19:47:41 +00:00
committed by Automerger Merge Worker
10 changed files with 305 additions and 90 deletions

View File

@@ -58,6 +58,7 @@ rust_defaults {
"libaconfig_protos", "libaconfig_protos",
"libanyhow", "libanyhow",
"libclap", "libclap",
"libitertools",
"libprotobuf", "libprotobuf",
"libserde", "libserde",
"libserde_json", "libserde_json",

View File

@@ -11,6 +11,7 @@ cargo = []
[dependencies] [dependencies]
anyhow = "1.0.69" anyhow = "1.0.69"
clap = { version = "4.1.8", features = ["derive"] } clap = { version = "4.1.8", features = ["derive"] }
itertools = "0.10.5"
paste = "1.0.11" paste = "1.0.11"
protobuf = "3.2.0" protobuf = "3.2.0"
serde = { version = "1.0.152", features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }

View File

@@ -32,8 +32,9 @@ where
I: Iterator<Item = &'a ProtoParsedFlag>, I: Iterator<Item = &'a ProtoParsedFlag>,
{ {
let mut readwrite_count = 0; let mut readwrite_count = 0;
let class_elements: Vec<ClassElement> = let class_elements: Vec<ClassElement> = parsed_flags_iter
parsed_flags_iter.map(|pf| create_class_element(package, pf, &mut readwrite_count)).collect(); .map(|pf| create_class_element(package, pf, &mut readwrite_count))
.collect();
let readwrite = readwrite_count > 0; let readwrite = readwrite_count > 0;
let has_fixed_read_only = class_elements.iter().any(|item| item.is_fixed_read_only); let has_fixed_read_only = class_elements.iter().any(|item| item.is_fixed_read_only);
let header = package.replace('.', "_"); let header = package.replace('.', "_");
@@ -110,7 +111,9 @@ pub struct ClassElement {
fn create_class_element(package: &str, pf: &ProtoParsedFlag, rw_count: &mut i32) -> ClassElement { fn create_class_element(package: &str, pf: &ProtoParsedFlag, rw_count: &mut i32) -> ClassElement {
ClassElement { ClassElement {
readwrite_idx: if pf.permission() == ProtoFlagPermission::READ_WRITE { readwrite_idx: if pf.permission() == ProtoFlagPermission::READ_WRITE {
let index = *rw_count; *rw_count += 1; index let index = *rw_count;
*rw_count += 1;
index
} else { } else {
-1 -1
}, },
@@ -162,6 +165,8 @@ public:
virtual bool disabled_rw() = 0; virtual bool disabled_rw() = 0;
virtual bool disabled_rw_2() = 0;
virtual bool enabled_fixed_ro() = 0; virtual bool enabled_fixed_ro() = 0;
virtual bool enabled_ro() = 0; virtual bool enabled_ro() = 0;
@@ -179,6 +184,10 @@ inline bool disabled_rw() {
return provider_->disabled_rw(); return provider_->disabled_rw();
} }
inline bool disabled_rw_2() {
return provider_->disabled_rw_2();
}
inline bool enabled_fixed_ro() { inline bool enabled_fixed_ro() {
return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO; return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
} }
@@ -200,6 +209,8 @@ bool com_android_aconfig_test_disabled_ro();
bool com_android_aconfig_test_disabled_rw(); bool com_android_aconfig_test_disabled_rw();
bool com_android_aconfig_test_disabled_rw_2();
bool com_android_aconfig_test_enabled_fixed_ro(); bool com_android_aconfig_test_enabled_fixed_ro();
bool com_android_aconfig_test_enabled_ro(); bool com_android_aconfig_test_enabled_ro();
@@ -233,6 +244,10 @@ public:
virtual void disabled_rw(bool val) = 0; virtual void disabled_rw(bool val) = 0;
virtual bool disabled_rw_2() = 0;
virtual void disabled_rw_2(bool val) = 0;
virtual bool enabled_fixed_ro() = 0; virtual bool enabled_fixed_ro() = 0;
virtual void enabled_fixed_ro(bool val) = 0; virtual void enabled_fixed_ro(bool val) = 0;
@@ -266,6 +281,14 @@ inline void disabled_rw(bool val) {
provider_->disabled_rw(val); provider_->disabled_rw(val);
} }
inline bool disabled_rw_2() {
return provider_->disabled_rw_2();
}
inline void disabled_rw_2(bool val) {
provider_->disabled_rw_2(val);
}
inline bool enabled_fixed_ro() { inline bool enabled_fixed_ro() {
return provider_->enabled_fixed_ro(); return provider_->enabled_fixed_ro();
} }
@@ -307,6 +330,10 @@ bool com_android_aconfig_test_disabled_rw();
void set_com_android_aconfig_test_disabled_rw(bool val); void set_com_android_aconfig_test_disabled_rw(bool val);
bool com_android_aconfig_test_disabled_rw_2();
void set_com_android_aconfig_test_disabled_rw_2(bool val);
bool com_android_aconfig_test_enabled_fixed_ro(); bool com_android_aconfig_test_enabled_fixed_ro();
void set_com_android_aconfig_test_enabled_fixed_ro(bool val); void set_com_android_aconfig_test_enabled_fixed_ro(bool val);
@@ -352,6 +379,16 @@ namespace com::android::aconfig::test {
return cache_[0]; return cache_[0];
} }
virtual bool disabled_rw_2() override {
if (cache_[1] == -1) {
cache_[1] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
"com.android.aconfig.test.disabled_rw_2",
"false") == "true";
}
return cache_[1];
}
virtual bool enabled_fixed_ro() override { virtual bool enabled_fixed_ro() override {
return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO; return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
} }
@@ -361,18 +398,18 @@ namespace com::android::aconfig::test {
} }
virtual bool enabled_rw() override { virtual bool enabled_rw() override {
if (cache_[1] == -1) { if (cache_[2] == -1) {
cache_[1] = server_configurable_flags::GetServerConfigurableFlag( cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.aconfig_test", "aconfig_flags.aconfig_test",
"com.android.aconfig.test.enabled_rw", "com.android.aconfig.test.enabled_rw",
"true") == "true"; "true") == "true";
} }
return cache_[1]; return cache_[2];
} }
}; };
std::vector<int8_t> cache_ = std::vector<int8_t>(2, -1); std::vector<int8_t> cache_ = std::vector<int8_t>(3, -1);
std::unique_ptr<flag_provider_interface> provider_ = std::unique_ptr<flag_provider_interface> provider_ =
std::make_unique<flag_provider>(); std::make_unique<flag_provider>();
@@ -386,6 +423,10 @@ bool com_android_aconfig_test_disabled_rw() {
return com::android::aconfig::test::disabled_rw(); return com::android::aconfig::test::disabled_rw();
} }
bool com_android_aconfig_test_disabled_rw_2() {
return com::android::aconfig::test::disabled_rw_2();
}
bool com_android_aconfig_test_enabled_fixed_ro() { bool com_android_aconfig_test_enabled_fixed_ro() {
return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO; return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
} }
@@ -446,6 +487,22 @@ namespace com::android::aconfig::test {
overrides_["disabled_rw"] = val; overrides_["disabled_rw"] = val;
} }
virtual bool disabled_rw_2() override {
auto it = overrides_.find("disabled_rw_2");
if (it != overrides_.end()) {
return it->second;
} else {
return server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
"com.android.aconfig.test.disabled_rw_2",
"false") == "true";
}
}
virtual void disabled_rw_2(bool val) override {
overrides_["disabled_rw_2"] = val;
}
virtual bool enabled_fixed_ro() override { virtual bool enabled_fixed_ro() override {
auto it = overrides_.find("enabled_fixed_ro"); auto it = overrides_.find("enabled_fixed_ro");
if (it != overrides_.end()) { if (it != overrides_.end()) {
@@ -515,6 +572,15 @@ void set_com_android_aconfig_test_disabled_rw(bool val) {
com::android::aconfig::test::disabled_rw(val); com::android::aconfig::test::disabled_rw(val);
} }
bool com_android_aconfig_test_disabled_rw_2() {
return com::android::aconfig::test::disabled_rw_2();
}
void set_com_android_aconfig_test_disabled_rw_2(bool val) {
com::android::aconfig::test::disabled_rw_2(val);
}
bool com_android_aconfig_test_enabled_fixed_ro() { bool com_android_aconfig_test_enabled_fixed_ro() {
return com::android::aconfig::test::enabled_fixed_ro(); return com::android::aconfig::test::enabled_fixed_ro();

View File

@@ -16,7 +16,7 @@
use anyhow::Result; use anyhow::Result;
use serde::Serialize; use serde::Serialize;
use std::collections::BTreeSet; use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf; use std::path::PathBuf;
use tinytemplate::TinyTemplate; use tinytemplate::TinyTemplate;
@@ -34,12 +34,14 @@ where
{ {
let flag_elements: Vec<FlagElement> = let flag_elements: Vec<FlagElement> =
parsed_flags_iter.map(|pf| create_flag_element(package, pf)).collect(); parsed_flags_iter.map(|pf| create_flag_element(package, pf)).collect();
let namespace_flags = gen_flags_by_namespace(&flag_elements);
let properties_set: BTreeSet<String> = let properties_set: BTreeSet<String> =
flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect(); flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect();
let is_read_write = flag_elements.iter().any(|elem| elem.is_read_write); let is_read_write = flag_elements.iter().any(|elem| elem.is_read_write);
let is_test_mode = codegen_mode == CodegenMode::Test; let is_test_mode = codegen_mode == CodegenMode::Test;
let context = Context { let context = Context {
flag_elements, flag_elements,
namespace_flags,
is_test_mode, is_test_mode,
is_read_write, is_read_write,
properties_set, properties_set,
@@ -72,16 +74,44 @@ where
.collect::<Result<Vec<OutputFile>>>() .collect::<Result<Vec<OutputFile>>>()
} }
fn gen_flags_by_namespace(flags: &[FlagElement]) -> Vec<NamespaceFlags> {
let mut namespace_to_flag: BTreeMap<String, Vec<FlagElement>> = BTreeMap::new();
for flag in flags {
match namespace_to_flag.get_mut(&flag.device_config_namespace) {
Some(flag_list) => flag_list.push(flag.clone()),
None => {
namespace_to_flag.insert(flag.device_config_namespace.clone(), vec![flag.clone()]);
}
}
}
namespace_to_flag
.iter()
.map(|(namespace, flags)| NamespaceFlags {
namespace: namespace.to_string(),
flags: flags.clone(),
})
.collect()
}
#[derive(Serialize)] #[derive(Serialize)]
struct Context { struct Context {
pub flag_elements: Vec<FlagElement>, pub flag_elements: Vec<FlagElement>,
pub namespace_flags: Vec<NamespaceFlags>,
pub is_test_mode: bool, pub is_test_mode: bool,
pub is_read_write: bool, pub is_read_write: bool,
pub properties_set: BTreeSet<String>, pub properties_set: BTreeSet<String>,
pub package_name: String, pub package_name: String,
} }
#[derive(Serialize)] #[derive(Serialize, Debug)]
struct NamespaceFlags {
pub namespace: String,
pub flags: Vec<FlagElement>,
}
#[derive(Serialize, Clone, Debug)]
struct FlagElement { struct FlagElement {
pub default_value: bool, pub default_value: bool,
pub device_config_namespace: String, pub device_config_namespace: String,
@@ -148,6 +178,8 @@ mod tests {
boolean disabledRo(); boolean disabledRo();
@UnsupportedAppUsage @UnsupportedAppUsage
boolean disabledRw(); boolean disabledRw();
@UnsupportedAppUsage
boolean disabledRw2();
@com.android.aconfig.annotations.AssumeTrueForR8 @com.android.aconfig.annotations.AssumeTrueForR8
@UnsupportedAppUsage @UnsupportedAppUsage
boolean enabledFixedRo(); boolean enabledFixedRo();
@@ -170,6 +202,8 @@ mod tests {
/** @hide */ /** @hide */
public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw"; public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
/** @hide */ /** @hide */
public static final String FLAG_DISABLED_RW_2 = "com.android.aconfig.test.disabled_rw_2";
/** @hide */
public static final String FLAG_ENABLED_FIXED_RO = "com.android.aconfig.test.enabled_fixed_ro"; public static final String FLAG_ENABLED_FIXED_RO = "com.android.aconfig.test.enabled_fixed_ro";
/** @hide */ /** @hide */
public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro"; public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
@@ -185,6 +219,10 @@ mod tests {
public static boolean disabledRw() { public static boolean disabledRw() {
return FEATURE_FLAGS.disabledRw(); return FEATURE_FLAGS.disabledRw();
} }
@UnsupportedAppUsage
public static boolean disabledRw2() {
return FEATURE_FLAGS.disabledRw2();
}
@com.android.aconfig.annotations.AssumeTrueForR8 @com.android.aconfig.annotations.AssumeTrueForR8
@UnsupportedAppUsage @UnsupportedAppUsage
public static boolean enabledFixedRo() { public static boolean enabledFixedRo() {
@@ -224,6 +262,11 @@ mod tests {
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRw2() {
return getValue(Flags.FLAG_DISABLED_RW_2);
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() { public boolean enabledFixedRo() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO); return getValue(Flags.FLAG_ENABLED_FIXED_RO);
} }
@@ -259,6 +302,7 @@ mod tests {
Map.ofEntries( Map.ofEntries(
Map.entry(Flags.FLAG_DISABLED_RO, false), Map.entry(Flags.FLAG_DISABLED_RO, false),
Map.entry(Flags.FLAG_DISABLED_RW, false), Map.entry(Flags.FLAG_DISABLED_RW, false),
Map.entry(Flags.FLAG_DISABLED_RW_2, false),
Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
Map.entry(Flags.FLAG_ENABLED_RO, false), Map.entry(Flags.FLAG_ENABLED_RO, false),
Map.entry(Flags.FLAG_ENABLED_RW, false) Map.entry(Flags.FLAG_ENABLED_RW, false)
@@ -289,7 +333,52 @@ mod tests {
import android.provider.DeviceConfig.Properties; import android.provider.DeviceConfig.Properties;
/** @hide */ /** @hide */
public final class FeatureFlagsImpl implements FeatureFlags { public final class FeatureFlagsImpl implements FeatureFlags {
private Properties mPropertiesAconfigTest; private static boolean aconfig_test_is_cached = false;
private static boolean other_namespace_is_cached = false;
private static boolean disabledRw = false;
private static boolean disabledRw2 = false;
private static boolean enabledRw = true;
private void load_overrides_aconfig_test() {
try {
Properties properties = DeviceConfig.getProperties("aconfig_test");
disabledRw =
properties.getBoolean("com.android.aconfig.test.disabled_rw", false);
enabledRw =
properties.getBoolean("com.android.aconfig.test.enabled_rw", true);
} catch (NullPointerException e) {
throw new RuntimeException(
"Cannot read value from namespace aconfig_test "
+ "from DeviceConfig. It could be that the code using flag "
+ "executed before SettingsProvider initialization. Please use "
+ "fixed read-only flag by adding is_fixed_read_only: true in "
+ "flag declaration.",
e
);
}
aconfig_test_is_cached = true;
}
private void load_overrides_other_namespace() {
try {
Properties properties = DeviceConfig.getProperties("other_namespace");
disabledRw2 =
properties.getBoolean("com.android.aconfig.test.disabled_rw_2", false);
} catch (NullPointerException e) {
throw new RuntimeException(
"Cannot read value from namespace other_namespace "
+ "from DeviceConfig. It could be that the code using flag "
+ "executed before SettingsProvider initialization. Please use "
+ "fixed read-only flag by adding is_fixed_read_only: true in "
+ "flag declaration.",
e
);
}
other_namespace_is_cached = true;
}
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRo() { public boolean disabledRo() {
@@ -298,18 +387,18 @@ mod tests {
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRw() { public boolean disabledRw() {
if (mPropertiesAconfigTest == null) { if (!aconfig_test_is_cached) {
mPropertiesAconfigTest = load_overrides_aconfig_test();
getProperties(
"aconfig_test",
"com.android.aconfig.test.disabled_rw"
);
} }
return mPropertiesAconfigTest return disabledRw;
.getBoolean( }
"com.android.aconfig.test.disabled_rw", @Override
false @UnsupportedAppUsage
); public boolean disabledRw2() {
if (!other_namespace_is_cached) {
load_overrides_other_namespace();
}
return disabledRw2;
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -324,36 +413,10 @@ mod tests {
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRw() { public boolean enabledRw() {
if (mPropertiesAconfigTest == null) { if (!aconfig_test_is_cached) {
mPropertiesAconfigTest = load_overrides_aconfig_test();
getProperties(
"aconfig_test",
"com.android.aconfig.test.enabled_rw"
);
} }
return mPropertiesAconfigTest return enabledRw;
.getBoolean(
"com.android.aconfig.test.enabled_rw",
true
);
}
private Properties getProperties(
String namespace,
String flagName) {
Properties properties = null;
try {
properties = DeviceConfig.getProperties(namespace);
} catch (NullPointerException e) {
throw new RuntimeException(
"Cannot read value of flag " + flagName + " from DeviceConfig. "
+ "It could be that the code using flag executed "
+ "before SettingsProvider initialization. "
+ "Please use fixed read-only flag by adding "
+ "is_fixed_read_only: true in flag declaration.",
e
);
}
return properties;
} }
} }
"#; "#;
@@ -426,6 +489,12 @@ mod tests {
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRw2() {
throw new UnsupportedOperationException(
"Method is not implemented.");
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() { public boolean enabledFixedRo() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Method is not implemented."); "Method is not implemented.");

View File

@@ -104,6 +104,12 @@ lazy_static::lazy_static! {
"com.android.aconfig.test.disabled_rw", "com.android.aconfig.test.disabled_rw",
"false") == "true"; "false") == "true";
/// flag value cache for disabled_rw_2
static ref CACHED_disabled_rw_2: bool = flags_rust::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
"com.android.aconfig.test.disabled_rw_2",
"false") == "true";
/// flag value cache for enabled_rw /// flag value cache for enabled_rw
static ref CACHED_enabled_rw: bool = flags_rust::GetServerConfigurableFlag( static ref CACHED_enabled_rw: bool = flags_rust::GetServerConfigurableFlag(
"aconfig_flags.aconfig_test", "aconfig_flags.aconfig_test",
@@ -122,6 +128,11 @@ impl FlagProvider {
*CACHED_disabled_rw *CACHED_disabled_rw
} }
/// query flag disabled_rw_2
pub fn disabled_rw_2(&self) -> bool {
*CACHED_disabled_rw_2
}
/// query flag enabled_fixed_ro /// query flag enabled_fixed_ro
pub fn enabled_fixed_ro(&self) -> bool { pub fn enabled_fixed_ro(&self) -> bool {
true true
@@ -153,6 +164,12 @@ pub fn disabled_rw() -> bool {
PROVIDER.disabled_rw() PROVIDER.disabled_rw()
} }
/// query flag disabled_rw_2
#[inline(always)]
pub fn disabled_rw_2() -> bool {
PROVIDER.disabled_rw_2()
}
/// query flag enabled_fixed_ro /// query flag enabled_fixed_ro
#[inline(always)] #[inline(always)]
pub fn enabled_fixed_ro() -> bool { pub fn enabled_fixed_ro() -> bool {
@@ -211,6 +228,21 @@ impl FlagProvider {
self.overrides.insert("disabled_rw", val); self.overrides.insert("disabled_rw", val);
} }
/// query flag disabled_rw_2
pub fn disabled_rw_2(&self) -> bool {
self.overrides.get("disabled_rw_2").copied().unwrap_or(
flags_rust::GetServerConfigurableFlag(
"aconfig_flags.other_namespace",
"com.android.aconfig.test.disabled_rw_2",
"false") == "true"
)
}
/// set flag disabled_rw_2
pub fn set_disabled_rw_2(&mut self, val: bool) {
self.overrides.insert("disabled_rw_2", val);
}
/// query flag enabled_fixed_ro /// query flag enabled_fixed_ro
pub fn enabled_fixed_ro(&self) -> bool { pub fn enabled_fixed_ro(&self) -> bool {
self.overrides.get("enabled_fixed_ro").copied().unwrap_or( self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
@@ -285,6 +317,18 @@ pub fn set_disabled_rw(val: bool) {
PROVIDER.lock().unwrap().set_disabled_rw(val); PROVIDER.lock().unwrap().set_disabled_rw(val);
} }
/// query flag disabled_rw_2
#[inline(always)]
pub fn disabled_rw_2() -> bool {
PROVIDER.lock().unwrap().disabled_rw_2()
}
/// set flag disabled_rw_2
#[inline(always)]
pub fn set_disabled_rw_2(val: bool) {
PROVIDER.lock().unwrap().set_disabled_rw_2(val);
}
/// query flag enabled_fixed_ro /// query flag enabled_fixed_ro
#[inline(always)] #[inline(always)]
pub fn enabled_fixed_ro() -> bool { pub fn enabled_fixed_ro() -> bool {

View File

@@ -334,7 +334,7 @@ mod tests {
assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state()); assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state());
assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission()); assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission());
assert_eq!(5, parsed_flags.parsed_flag.len()); assert_eq!(6, parsed_flags.parsed_flag.len());
for pf in parsed_flags.parsed_flag.iter() { for pf in parsed_flags.parsed_flag.iter() {
if pf.name() == "enabled_fixed_ro" { if pf.name() == "enabled_fixed_ro" {
continue; continue;
@@ -433,7 +433,7 @@ mod tests {
let input = parse_test_flags_as_input(); let input = parse_test_flags_as_input();
let bytes = create_device_config_defaults(input).unwrap(); let bytes = create_device_config_defaults(input).unwrap();
let text = std::str::from_utf8(&bytes).unwrap(); let text = std::str::from_utf8(&bytes).unwrap();
assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text); assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\nother_namespace:com.android.aconfig.test.disabled_rw_2=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
} }
#[test] #[test]
@@ -441,7 +441,7 @@ mod tests {
let input = parse_test_flags_as_input(); let input = parse_test_flags_as_input();
let bytes = create_device_config_sysprops(input).unwrap(); let bytes = create_device_config_sysprops(input).unwrap();
let text = std::str::from_utf8(&bytes).unwrap(); let text = std::str::from_utf8(&bytes).unwrap();
assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text); assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.disabled_rw_2=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
} }
#[test] #[test]

View File

@@ -58,6 +58,26 @@ parsed_flag {
} }
is_fixed_read_only: false is_fixed_read_only: false
} }
parsed_flag {
package: "com.android.aconfig.test"
name: "disabled_rw_2"
namespace: "other_namespace"
description: "This flag is DISABLED + READ_WRITE"
bug: "999"
state: DISABLED
permission: READ_WRITE
trace {
source: "tests/test.aconfig"
state: DISABLED
permission: READ_WRITE
}
trace {
source: "tests/first.values"
state: DISABLED
permission: READ_WRITE
}
is_fixed_read_only: false
}
parsed_flag { parsed_flag {
package: "com.android.aconfig.test" package: "com.android.aconfig.test"
name: "enabled_fixed_ro" name: "enabled_fixed_ro"

View File

@@ -8,10 +8,41 @@ import android.provider.DeviceConfig.Properties;
{{ endif }} {{ endif }}
/** @hide */ /** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{ public final class FeatureFlagsImpl implements FeatureFlags \{
{{ if is_read_write- }} {{- if is_read_write }}
{{ for properties in properties_set }} {{- for namespace_with_flags in namespace_flags }}
private Properties {properties}; private static boolean {namespace_with_flags.namespace}_is_cached = false;
{{- endfor- }}
{{ for flag in flag_elements }}
{{- if flag.is_read_write }}
private static boolean {flag.method_name} = {flag.default_value};
{{- endif- }}
{{ endfor }} {{ endfor }}
{{ for namespace_with_flags in namespace_flags }}
private void load_overrides_{namespace_with_flags.namespace}() \{
try \{
Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
{{- for flag in namespace_with_flags.flags }}
{{- if flag.is_read_write }}
{flag.method_name} =
properties.getBoolean("{flag.device_config_flag}", {flag.default_value});
{{- endif- }}
{{ endfor }}
} catch (NullPointerException e) \{
throw new RuntimeException(
"Cannot read value from namespace {namespace_with_flags.namespace} "
+ "from DeviceConfig. It could be that the code using flag "
+ "executed before SettingsProvider initialization. Please use "
+ "fixed read-only flag by adding is_fixed_read_only: true in "
+ "flag declaration.",
e
);
}
{namespace_with_flags.namespace}_is_cached = true;
}
{{ endfor- }}
{{ endif- }} {{ endif- }}
{{ for flag in flag_elements }} {{ for flag in flag_elements }}
@@ -19,45 +50,15 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean {flag.method_name}() \{ public boolean {flag.method_name}() \{
{{ -if flag.is_read_write }} {{ -if flag.is_read_write }}
if ({flag.properties} == null) \{ if (!{flag.device_config_namespace}_is_cached) \{
{flag.properties} = load_overrides_{flag.device_config_namespace}();
getProperties(
"{flag.device_config_namespace}",
"{flag.device_config_flag}"
);
} }
return {flag.properties} return {flag.method_name};
.getBoolean(
"{flag.device_config_flag}",
{flag.default_value}
);
{{ else }} {{ else }}
return {flag.default_value}; return {flag.default_value};
{{ endif- }} {{ endif- }}
} }
{{ endfor }} {{ endfor }}
{{ -if is_read_write }}
private Properties getProperties(
String namespace,
String flagName) \{
Properties properties = null;
try \{
properties = DeviceConfig.getProperties(namespace);
} catch (NullPointerException e) \{
throw new RuntimeException(
"Cannot read value of flag " + flagName + " from DeviceConfig. "
+ "It could be that the code using flag executed "
+ "before SettingsProvider initialization. "
+ "Please use fixed read-only flag by adding "
+ "is_fixed_read_only: true in flag declaration.",
e
);
}
return properties;
}
{{ endif- }}
} }
{{ else }} {{ else }}
{#- Generate only stub if in test mode #} {#- Generate only stub if in test mode #}
@@ -70,6 +71,6 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Method is not implemented."); "Method is not implemented.");
} }
{{ endfor }} {{ endfor- }}
} }
{{ endif }} {{ endif }}

View File

@@ -16,6 +16,12 @@ flag_value {
state: ENABLED state: ENABLED
permission: READ_WRITE permission: READ_WRITE
} }
flag_value {
package: "com.android.aconfig.test"
name: "disabled_rw_2"
state: DISABLED
permission: READ_WRITE
}
flag_value { flag_value {
package: "com.android.aconfig.test" package: "com.android.aconfig.test"
name: "enabled_fixed_ro" name: "enabled_fixed_ro"

View File

@@ -51,3 +51,10 @@ flag {
bug: "" bug: ""
is_fixed_read_only: true is_fixed_read_only: true
} }
flag {
name: "disabled_rw_2"
namespace: "other_namespace"
description: "This flag is DISABLED + READ_WRITE"
bug: "999"
}