Merge "Cache Java codegen'd flags in static member variables." into main
This commit is contained in:
@@ -58,6 +58,7 @@ rust_defaults {
|
|||||||
"libaconfig_protos",
|
"libaconfig_protos",
|
||||||
"libanyhow",
|
"libanyhow",
|
||||||
"libclap",
|
"libclap",
|
||||||
|
"libitertools",
|
||||||
"libprotobuf",
|
"libprotobuf",
|
||||||
"libserde",
|
"libserde",
|
||||||
"libserde_json",
|
"libserde_json",
|
||||||
|
@@ -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"] }
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use itertools::Itertools;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -34,12 +35,18 @@ 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_set: BTreeSet<String> = flag_elements
|
||||||
|
.iter()
|
||||||
|
.unique_by(|f| &f.device_config_namespace)
|
||||||
|
.map(|f| f.device_config_namespace.clone())
|
||||||
|
.collect();
|
||||||
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_set,
|
||||||
is_test_mode,
|
is_test_mode,
|
||||||
is_read_write,
|
is_read_write,
|
||||||
properties_set,
|
properties_set,
|
||||||
@@ -75,6 +82,7 @@ where
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Context {
|
struct Context {
|
||||||
pub flag_elements: Vec<FlagElement>,
|
pub flag_elements: Vec<FlagElement>,
|
||||||
|
pub namespace_set: BTreeSet<String>,
|
||||||
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>,
|
||||||
@@ -289,7 +297,31 @@ 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 disabledRw = 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;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public boolean disabledRo() {
|
public boolean disabledRo() {
|
||||||
@@ -298,18 +330,10 @@ 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",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@@ -324,36 +348,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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
@@ -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 in namespace_set }}
|
||||||
private Properties {properties};
|
private static boolean {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 in namespace_set }}
|
||||||
|
private void load_overrides_{namespace}() \{
|
||||||
|
try \{
|
||||||
|
Properties properties = DeviceConfig.getProperties("{namespace}");
|
||||||
|
|
||||||
|
{{- for flag in flag_elements }}
|
||||||
|
{{- 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} "
|
||||||
|
+ "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}_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 }}
|
||||||
|
Reference in New Issue
Block a user