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

This commit is contained in:
Ted Bauer 2023-11-16 18:48:00 +00:00 committed by Gerrit Code Review
commit ca355c09a2
10 changed files with 305 additions and 90 deletions

View file

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

View file

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

View file

@ -32,8 +32,9 @@ where
I: Iterator<Item = &'a ProtoParsedFlag>,
{
let mut readwrite_count = 0;
let class_elements: Vec<ClassElement> =
parsed_flags_iter.map(|pf| create_class_element(package, pf, &mut readwrite_count)).collect();
let class_elements: Vec<ClassElement> = parsed_flags_iter
.map(|pf| create_class_element(package, pf, &mut readwrite_count))
.collect();
let readwrite = readwrite_count > 0;
let has_fixed_read_only = class_elements.iter().any(|item| item.is_fixed_read_only);
let header = package.replace('.', "_");
@ -110,7 +111,9 @@ pub struct ClassElement {
fn create_class_element(package: &str, pf: &ProtoParsedFlag, rw_count: &mut i32) -> ClassElement {
ClassElement {
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 {
-1
},
@ -162,6 +165,8 @@ public:
virtual bool disabled_rw() = 0;
virtual bool disabled_rw_2() = 0;
virtual bool enabled_fixed_ro() = 0;
virtual bool enabled_ro() = 0;
@ -179,6 +184,10 @@ inline bool disabled_rw() {
return provider_->disabled_rw();
}
inline bool disabled_rw_2() {
return provider_->disabled_rw_2();
}
inline bool 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_2();
bool com_android_aconfig_test_enabled_fixed_ro();
bool com_android_aconfig_test_enabled_ro();
@ -233,6 +244,10 @@ public:
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 void enabled_fixed_ro(bool val) = 0;
@ -266,6 +281,14 @@ inline void disabled_rw(bool 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() {
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);
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();
void set_com_android_aconfig_test_enabled_fixed_ro(bool val);
@ -352,6 +379,16 @@ namespace com::android::aconfig::test {
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 {
return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
}
@ -361,18 +398,18 @@ namespace com::android::aconfig::test {
}
virtual bool enabled_rw() override {
if (cache_[1] == -1) {
cache_[1] = server_configurable_flags::GetServerConfigurableFlag(
if (cache_[2] == -1) {
cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.aconfig_test",
"com.android.aconfig.test.enabled_rw",
"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::make_unique<flag_provider>();
@ -386,6 +423,10 @@ bool 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() {
return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
}
@ -446,6 +487,22 @@ namespace com::android::aconfig::test {
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 {
auto it = overrides_.find("enabled_fixed_ro");
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);
}
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() {
return com::android::aconfig::test::enabled_fixed_ro();

View file

@ -16,7 +16,7 @@
use anyhow::Result;
use serde::Serialize;
use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use tinytemplate::TinyTemplate;
@ -34,12 +34,14 @@ where
{
let flag_elements: Vec<FlagElement> =
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> =
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_test_mode = codegen_mode == CodegenMode::Test;
let context = Context {
flag_elements,
namespace_flags,
is_test_mode,
is_read_write,
properties_set,
@ -72,16 +74,44 @@ where
.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)]
struct Context {
pub flag_elements: Vec<FlagElement>,
pub namespace_flags: Vec<NamespaceFlags>,
pub is_test_mode: bool,
pub is_read_write: bool,
pub properties_set: BTreeSet<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 {
pub default_value: bool,
pub device_config_namespace: String,
@ -148,6 +178,8 @@ mod tests {
boolean disabledRo();
@UnsupportedAppUsage
boolean disabledRw();
@UnsupportedAppUsage
boolean disabledRw2();
@com.android.aconfig.annotations.AssumeTrueForR8
@UnsupportedAppUsage
boolean enabledFixedRo();
@ -170,6 +202,8 @@ mod tests {
/** @hide */
public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
/** @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";
/** @hide */
public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
@ -185,6 +219,10 @@ mod tests {
public static boolean disabledRw() {
return FEATURE_FLAGS.disabledRw();
}
@UnsupportedAppUsage
public static boolean disabledRw2() {
return FEATURE_FLAGS.disabledRw2();
}
@com.android.aconfig.annotations.AssumeTrueForR8
@UnsupportedAppUsage
public static boolean enabledFixedRo() {
@ -224,6 +262,11 @@ mod tests {
}
@Override
@UnsupportedAppUsage
public boolean disabledRw2() {
return getValue(Flags.FLAG_DISABLED_RW_2);
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO);
}
@ -259,6 +302,7 @@ mod tests {
Map.ofEntries(
Map.entry(Flags.FLAG_DISABLED_RO, 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_RO, false),
Map.entry(Flags.FLAG_ENABLED_RW, false)
@ -289,7 +333,52 @@ mod tests {
import android.provider.DeviceConfig.Properties;
/** @hide */
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
@UnsupportedAppUsage
public boolean disabledRo() {
@ -298,18 +387,18 @@ mod tests {
@Override
@UnsupportedAppUsage
public boolean disabledRw() {
if (mPropertiesAconfigTest == null) {
mPropertiesAconfigTest =
getProperties(
"aconfig_test",
"com.android.aconfig.test.disabled_rw"
);
if (!aconfig_test_is_cached) {
load_overrides_aconfig_test();
}
return mPropertiesAconfigTest
.getBoolean(
"com.android.aconfig.test.disabled_rw",
false
);
return disabledRw;
}
@Override
@UnsupportedAppUsage
public boolean disabledRw2() {
if (!other_namespace_is_cached) {
load_overrides_other_namespace();
}
return disabledRw2;
}
@Override
@UnsupportedAppUsage
@ -324,36 +413,10 @@ mod tests {
@Override
@UnsupportedAppUsage
public boolean enabledRw() {
if (mPropertiesAconfigTest == null) {
mPropertiesAconfigTest =
getProperties(
"aconfig_test",
"com.android.aconfig.test.enabled_rw"
);
if (!aconfig_test_is_cached) {
load_overrides_aconfig_test();
}
return mPropertiesAconfigTest
.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;
return enabledRw;
}
}
"#;
@ -426,6 +489,12 @@ mod tests {
}
@Override
@UnsupportedAppUsage
public boolean disabledRw2() {
throw new UnsupportedOperationException(
"Method is not implemented.");
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() {
throw new UnsupportedOperationException(
"Method is not implemented.");

View file

@ -104,6 +104,12 @@ lazy_static::lazy_static! {
"com.android.aconfig.test.disabled_rw",
"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
static ref CACHED_enabled_rw: bool = flags_rust::GetServerConfigurableFlag(
"aconfig_flags.aconfig_test",
@ -122,6 +128,11 @@ impl FlagProvider {
*CACHED_disabled_rw
}
/// query flag disabled_rw_2
pub fn disabled_rw_2(&self) -> bool {
*CACHED_disabled_rw_2
}
/// query flag enabled_fixed_ro
pub fn enabled_fixed_ro(&self) -> bool {
true
@ -153,6 +164,12 @@ pub fn disabled_rw() -> bool {
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
#[inline(always)]
pub fn enabled_fixed_ro() -> bool {
@ -211,6 +228,21 @@ impl FlagProvider {
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
pub fn enabled_fixed_ro(&self) -> bool {
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);
}
/// 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
#[inline(always)]
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!(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() {
if pf.name() == "enabled_fixed_ro" {
continue;
@ -433,7 +433,7 @@ mod tests {
let input = parse_test_flags_as_input();
let bytes = create_device_config_defaults(input).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]
@ -441,7 +441,7 @@ mod tests {
let input = parse_test_flags_as_input();
let bytes = create_device_config_sysprops(input).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]

View file

@ -58,6 +58,26 @@ parsed_flag {
}
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 {
package: "com.android.aconfig.test"
name: "enabled_fixed_ro"

View file

@ -8,10 +8,41 @@ import android.provider.DeviceConfig.Properties;
{{ endif }}
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{
{{ if is_read_write- }}
{{ for properties in properties_set }}
private Properties {properties};
{{- if is_read_write }}
{{- for namespace_with_flags in namespace_flags }}
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 }}
{{ 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- }}
{{ for flag in flag_elements }}
@ -19,45 +50,15 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
@UnsupportedAppUsage
public boolean {flag.method_name}() \{
{{ -if flag.is_read_write }}
if ({flag.properties} == null) \{
{flag.properties} =
getProperties(
"{flag.device_config_namespace}",
"{flag.device_config_flag}"
);
if (!{flag.device_config_namespace}_is_cached) \{
load_overrides_{flag.device_config_namespace}();
}
return {flag.properties}
.getBoolean(
"{flag.device_config_flag}",
{flag.default_value}
);
return {flag.method_name};
{{ else }}
return {flag.default_value};
{{ endif- }}
}
{{ 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 }}
{#- Generate only stub if in test mode #}
@ -70,6 +71,6 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
throw new UnsupportedOperationException(
"Method is not implemented.");
}
{{ endfor }}
{{ endfor- }}
}
{{ endif }}

View file

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

View file

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