Loading tools/aconfig/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ rust_defaults { "libaconfig_protos", "libanyhow", "libclap", "libitertools", "libprotobuf", "libserde", "libserde_json", Loading tools/aconfig/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -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"] } Loading tools/aconfig/src/codegen_java.rs +39 −41 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ use anyhow::Result; use itertools::Itertools; use serde::Serialize; use std::collections::BTreeSet; use std::path::PathBuf; Loading @@ -34,12 +35,18 @@ where { let flag_elements: Vec<FlagElement> = 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> = 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_set, is_test_mode, is_read_write, properties_set, Loading Loading @@ -75,6 +82,7 @@ where #[derive(Serialize)] struct Context { pub flag_elements: Vec<FlagElement>, pub namespace_set: BTreeSet<String>, pub is_test_mode: bool, pub is_read_write: bool, pub properties_set: BTreeSet<String>, Loading Loading @@ -289,7 +297,31 @@ 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 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 @UnsupportedAppUsage public boolean disabledRo() { Loading @@ -298,18 +330,10 @@ 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 Loading @@ -324,36 +348,10 @@ mod tests { @Override @UnsupportedAppUsage public boolean enabledRw() { if (mPropertiesAconfigTest == null) { mPropertiesAconfigTest = getProperties( "aconfig_test", "com.android.aconfig.test.enabled_rw" ); } 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 ); if (!aconfig_test_is_cached) { load_overrides_aconfig_test(); } return properties; return enabledRw; } } "#; Loading tools/aconfig/templates/FeatureFlagsImpl.java.template +38 −37 Original line number Diff line number Diff line Loading @@ -8,57 +8,58 @@ 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}; {{ endfor }} {{ endif- }} {{- if is_read_write }} {{- for namespace in namespace_set }} private static boolean {namespace}_is_cached = false; {{- endfor- }} {{ for flag in flag_elements }} @Override @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}" ); } return {flag.properties} .getBoolean( "{flag.device_config_flag}", {flag.default_value} ); {{ else }} return {flag.default_value}; {{ endif- }} } private static boolean {flag.method_name} = {flag.default_value}; {{- endif- }} {{ endfor }} {{ -if is_read_write }} private Properties getProperties( String namespace, String flagName) \{ Properties properties = null; {{ for namespace in namespace_set }} private void load_overrides_{namespace}() \{ try \{ properties = DeviceConfig.getProperties(namespace); 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 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.", "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- }} return properties; {{ for flag in flag_elements }} @Override @UnsupportedAppUsage public boolean {flag.method_name}() \{ {{ -if flag.is_read_write }} if (!{flag.device_config_namespace}_is_cached) \{ load_overrides_{flag.device_config_namespace}(); } return {flag.method_name}; {{ else }} return {flag.default_value}; {{ endif- }} } {{ endfor }} } {{ else }} {#- Generate only stub if in test mode #} /** @hide */ Loading @@ -70,6 +71,6 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ throw new UnsupportedOperationException( "Method is not implemented."); } {{ endfor }} {{ endfor- }} } {{ endif }} Loading
tools/aconfig/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ rust_defaults { "libaconfig_protos", "libanyhow", "libclap", "libitertools", "libprotobuf", "libserde", "libserde_json", Loading
tools/aconfig/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -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"] } Loading
tools/aconfig/src/codegen_java.rs +39 −41 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ use anyhow::Result; use itertools::Itertools; use serde::Serialize; use std::collections::BTreeSet; use std::path::PathBuf; Loading @@ -34,12 +35,18 @@ where { let flag_elements: Vec<FlagElement> = 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> = 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_set, is_test_mode, is_read_write, properties_set, Loading Loading @@ -75,6 +82,7 @@ where #[derive(Serialize)] struct Context { pub flag_elements: Vec<FlagElement>, pub namespace_set: BTreeSet<String>, pub is_test_mode: bool, pub is_read_write: bool, pub properties_set: BTreeSet<String>, Loading Loading @@ -289,7 +297,31 @@ 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 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 @UnsupportedAppUsage public boolean disabledRo() { Loading @@ -298,18 +330,10 @@ 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 Loading @@ -324,36 +348,10 @@ mod tests { @Override @UnsupportedAppUsage public boolean enabledRw() { if (mPropertiesAconfigTest == null) { mPropertiesAconfigTest = getProperties( "aconfig_test", "com.android.aconfig.test.enabled_rw" ); } 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 ); if (!aconfig_test_is_cached) { load_overrides_aconfig_test(); } return properties; return enabledRw; } } "#; Loading
tools/aconfig/templates/FeatureFlagsImpl.java.template +38 −37 Original line number Diff line number Diff line Loading @@ -8,57 +8,58 @@ 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}; {{ endfor }} {{ endif- }} {{- if is_read_write }} {{- for namespace in namespace_set }} private static boolean {namespace}_is_cached = false; {{- endfor- }} {{ for flag in flag_elements }} @Override @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}" ); } return {flag.properties} .getBoolean( "{flag.device_config_flag}", {flag.default_value} ); {{ else }} return {flag.default_value}; {{ endif- }} } private static boolean {flag.method_name} = {flag.default_value}; {{- endif- }} {{ endfor }} {{ -if is_read_write }} private Properties getProperties( String namespace, String flagName) \{ Properties properties = null; {{ for namespace in namespace_set }} private void load_overrides_{namespace}() \{ try \{ properties = DeviceConfig.getProperties(namespace); 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 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.", "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- }} return properties; {{ for flag in flag_elements }} @Override @UnsupportedAppUsage public boolean {flag.method_name}() \{ {{ -if flag.is_read_write }} if (!{flag.device_config_namespace}_is_cached) \{ load_overrides_{flag.device_config_namespace}(); } return {flag.method_name}; {{ else }} return {flag.default_value}; {{ endif- }} } {{ endfor }} } {{ else }} {#- Generate only stub if in test mode #} /** @hide */ Loading @@ -70,6 +71,6 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ throw new UnsupportedOperationException( "Method is not implemented."); } {{ endfor }} {{ endfor- }} } {{ endif }}