diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs index 5aa373aab9..c536260042 100644 --- a/tools/aconfig/src/codegen_cpp.rs +++ b/tools/aconfig/src/codegen_cpp.rs @@ -162,6 +162,8 @@ public: virtual bool disabled_rw() = 0; + virtual bool disabled_rw_exported() = 0; + virtual bool disabled_rw_in_other_namespace() = 0; virtual bool enabled_fixed_ro() = 0; @@ -181,6 +183,10 @@ inline bool disabled_rw() { return provider_->disabled_rw(); } +inline bool disabled_rw_exported() { + return provider_->disabled_rw_exported(); +} + inline bool disabled_rw_in_other_namespace() { return provider_->disabled_rw_in_other_namespace(); } @@ -206,6 +212,8 @@ bool com_android_aconfig_test_disabled_ro(); bool com_android_aconfig_test_disabled_rw(); +bool com_android_aconfig_test_disabled_rw_exported(); + bool com_android_aconfig_test_disabled_rw_in_other_namespace(); bool com_android_aconfig_test_enabled_fixed_ro(); @@ -241,6 +249,10 @@ public: virtual void disabled_rw(bool val) = 0; + virtual bool disabled_rw_exported() = 0; + + virtual void disabled_rw_exported(bool val) = 0; + virtual bool disabled_rw_in_other_namespace() = 0; virtual void disabled_rw_in_other_namespace(bool val) = 0; @@ -278,6 +290,14 @@ inline void disabled_rw(bool val) { provider_->disabled_rw(val); } +inline bool disabled_rw_exported() { + return provider_->disabled_rw_exported(); +} + +inline void disabled_rw_exported(bool val) { + provider_->disabled_rw_exported(val); +} + inline bool disabled_rw_in_other_namespace() { return provider_->disabled_rw_in_other_namespace(); } @@ -327,6 +347,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_exported(); + +void set_com_android_aconfig_test_disabled_rw_exported(bool val); + bool com_android_aconfig_test_disabled_rw_in_other_namespace(); void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val); @@ -377,14 +401,24 @@ namespace com::android::aconfig::test { return cache_[0]; } - virtual bool disabled_rw_in_other_namespace() override { + virtual bool disabled_rw_exported() override { if (cache_[1] == -1) { cache_[1] = server_configurable_flags::GetServerConfigurableFlag( + "aconfig_flags.aconfig_test", + "com.android.aconfig.test.disabled_rw_exported", + "false") == "true"; + } + return cache_[1]; + } + + virtual bool disabled_rw_in_other_namespace() override { + if (cache_[2] == -1) { + cache_[2] = server_configurable_flags::GetServerConfigurableFlag( "aconfig_flags.other_namespace", "com.android.aconfig.test.disabled_rw_in_other_namespace", "false") == "true"; } - return cache_[1]; + return cache_[2]; } virtual bool enabled_fixed_ro() override { @@ -396,17 +430,17 @@ namespace com::android::aconfig::test { } virtual bool enabled_rw() override { - if (cache_[2] == -1) { - cache_[2] = server_configurable_flags::GetServerConfigurableFlag( + if (cache_[3] == -1) { + cache_[3] = server_configurable_flags::GetServerConfigurableFlag( "aconfig_flags.aconfig_test", "com.android.aconfig.test.enabled_rw", "true") == "true"; } - return cache_[2]; + return cache_[3]; } private: - std::vector cache_ = std::vector(3, -1); + std::vector cache_ = std::vector(4, -1); }; std::unique_ptr provider_ = @@ -421,6 +455,10 @@ bool com_android_aconfig_test_disabled_rw() { return com::android::aconfig::test::disabled_rw(); } +bool com_android_aconfig_test_disabled_rw_exported() { + return com::android::aconfig::test::disabled_rw_exported(); +} + bool com_android_aconfig_test_disabled_rw_in_other_namespace() { return com::android::aconfig::test::disabled_rw_in_other_namespace(); } @@ -485,6 +523,22 @@ namespace com::android::aconfig::test { overrides_["disabled_rw"] = val; } + virtual bool disabled_rw_exported() override { + auto it = overrides_.find("disabled_rw_exported"); + if (it != overrides_.end()) { + return it->second; + } else { + return server_configurable_flags::GetServerConfigurableFlag( + "aconfig_flags.aconfig_test", + "com.android.aconfig.test.disabled_rw_exported", + "false") == "true"; + } + } + + virtual void disabled_rw_exported(bool val) override { + overrides_["disabled_rw_exported"] = val; + } + virtual bool disabled_rw_in_other_namespace() override { auto it = overrides_.find("disabled_rw_in_other_namespace"); if (it != overrides_.end()) { @@ -570,11 +624,20 @@ void set_com_android_aconfig_test_disabled_rw(bool val) { com::android::aconfig::test::disabled_rw(val); } + +bool com_android_aconfig_test_disabled_rw_exported() { + return com::android::aconfig::test::disabled_rw_exported(); +} + +void set_com_android_aconfig_test_disabled_rw_exported(bool val) { + com::android::aconfig::test::disabled_rw_exported(val); +} + + bool com_android_aconfig_test_disabled_rw_in_other_namespace() { return com::android::aconfig::test::disabled_rw_in_other_namespace(); } - void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val) { com::android::aconfig::test::disabled_rw_in_other_namespace(val); } @@ -634,6 +697,8 @@ void com_android_aconfig_test_reset_flags() { match mode { CodegenMode::Production => EXPORTED_PROD_HEADER_EXPECTED, CodegenMode::Test => EXPORTED_TEST_HEADER_EXPECTED, + CodegenMode::Exported => + todo!("exported mode not yet supported for cpp, see b/313894653."), }, generated_files_map.get(&target_file_path).unwrap() ) @@ -647,6 +712,8 @@ void com_android_aconfig_test_reset_flags() { match mode { CodegenMode::Production => PROD_SOURCE_FILE_EXPECTED, CodegenMode::Test => TEST_SOURCE_FILE_EXPECTED, + CodegenMode::Exported => + todo!("exported mode not yet supported for cpp, see b/313894653."), }, generated_files_map.get(&target_file_path).unwrap() ) diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs index a822cd5fd1..b3e5e6cf6f 100644 --- a/tools/aconfig/src/codegen_java.rs +++ b/tools/aconfig/src/codegen_java.rs @@ -39,6 +39,7 @@ where 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 library_exported = codegen_mode == CodegenMode::Exported; let context = Context { flag_elements, namespace_flags, @@ -46,6 +47,7 @@ where is_read_write, properties_set, package_name: package.to_string(), + library_exported, }; let mut template = TinyTemplate::new(); template.add_template("Flags.java", include_str!("../templates/Flags.java.template"))?; @@ -103,6 +105,7 @@ struct Context { pub is_read_write: bool, pub properties_set: BTreeSet, pub package_name: String, + pub library_exported: bool, } #[derive(Serialize, Debug)] @@ -120,6 +123,7 @@ struct FlagElement { pub is_read_write: bool, pub method_name: String, pub properties: String, + pub exported: bool, } fn create_flag_element(package: &str, pf: &ProtoParsedFlag) -> FlagElement { @@ -133,6 +137,7 @@ fn create_flag_element(package: &str, pf: &ProtoParsedFlag) -> FlagElement { is_read_write: pf.permission() == ProtoFlagPermission::READ_WRITE, method_name: format_java_method_name(pf.name()), properties: format_property_name(pf.namespace()), + exported: pf.is_exported.unwrap_or(false), } } @@ -179,6 +184,8 @@ mod tests { @UnsupportedAppUsage boolean disabledRw(); @UnsupportedAppUsage + boolean disabledRwExported(); + @UnsupportedAppUsage boolean disabledRwInOtherNamespace(); @com.android.aconfig.annotations.AssumeTrueForR8 @UnsupportedAppUsage @@ -202,6 +209,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_EXPORTED = "com.android.aconfig.test.disabled_rw_exported"; + /** @hide */ public static final String FLAG_DISABLED_RW_IN_OTHER_NAMESPACE = "com.android.aconfig.test.disabled_rw_in_other_namespace"; /** @hide */ public static final String FLAG_ENABLED_FIXED_RO = "com.android.aconfig.test.enabled_fixed_ro"; @@ -220,6 +229,10 @@ mod tests { return FEATURE_FLAGS.disabledRw(); } @UnsupportedAppUsage + public static boolean disabledRwExported() { + return FEATURE_FLAGS.disabledRwExported(); + } + @UnsupportedAppUsage public static boolean disabledRwInOtherNamespace() { return FEATURE_FLAGS.disabledRwInOtherNamespace(); } @@ -262,6 +275,11 @@ mod tests { } @Override @UnsupportedAppUsage + public boolean disabledRwExported() { + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); + } + @Override + @UnsupportedAppUsage public boolean disabledRwInOtherNamespace() { return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); } @@ -302,6 +320,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_EXPORTED, false), Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), Map.entry(Flags.FLAG_ENABLED_RO, false), @@ -336,6 +355,7 @@ mod tests { private static boolean aconfig_test_is_cached = false; private static boolean other_namespace_is_cached = false; private static boolean disabledRw = false; + private static boolean disabledRwExported = false; private static boolean disabledRwInOtherNamespace = false; private static boolean enabledRw = true; @@ -345,6 +365,8 @@ mod tests { Properties properties = DeviceConfig.getProperties("aconfig_test"); disabledRw = properties.getBoolean("com.android.aconfig.test.disabled_rw", false); + disabledRwExported = + properties.getBoolean("com.android.aconfig.test.disabled_rw_exported", false); enabledRw = properties.getBoolean("com.android.aconfig.test.enabled_rw", true); } catch (NullPointerException e) { @@ -394,6 +416,14 @@ mod tests { } @Override @UnsupportedAppUsage + public boolean disabledRwExported() { + if (!aconfig_test_is_cached) { + load_overrides_aconfig_test(); + } + return disabledRwExported; + } + @Override + @UnsupportedAppUsage public boolean disabledRwInOtherNamespace() { if (!other_namespace_is_cached) { load_overrides_other_namespace(); @@ -448,6 +478,202 @@ mod tests { assert!(file_set.is_empty()); } + #[test] + fn test_generate_java_code_exported() { + let parsed_flags = crate::test::parse_test_flags(); + let generated_files = generate_java_code( + crate::test::TEST_PACKAGE, + parsed_flags.parsed_flag.iter(), + CodegenMode::Exported, + ) + .unwrap(); + + let expect_flags_content = r#" + package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. + import android.compat.annotation.UnsupportedAppUsage; + /** @hide */ + public final class Flags { + /** @hide */ + public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw"; + /** @hide */ + public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported"; + + @UnsupportedAppUsage + public static boolean disabledRw() { + return FEATURE_FLAGS.disabledRw(); + } + @UnsupportedAppUsage + public static boolean disabledRwExported() { + return FEATURE_FLAGS.disabledRwExported(); + } + private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); + } + "#; + + let expect_feature_flags_content = r#" + package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. + import android.compat.annotation.UnsupportedAppUsage; + /** @hide */ + public interface FeatureFlags { + @UnsupportedAppUsage + boolean disabledRw(); + @UnsupportedAppUsage + boolean disabledRwExported(); + } + "#; + + let expect_feature_flags_impl_content = r#" + package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. + import android.compat.annotation.UnsupportedAppUsage; + import android.provider.DeviceConfig; + import android.provider.DeviceConfig.Properties; + /** @hide */ + public final class FeatureFlagsImpl implements FeatureFlags { + private static boolean aconfig_test_is_cached = false; + private static boolean other_namespace_is_cached = false; + private static boolean disabledRw = false; + private static boolean disabledRwExported = false; + + + private void load_overrides_aconfig_test() { + try { + Properties properties = DeviceConfig.getProperties("aconfig_test"); + disabledRw = + properties.getBoolean("com.android.aconfig.test.disabled_rw", false); + disabledRwExported = + properties.getBoolean("com.android.aconfig.test.disabled_rw_exported", false); + } 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"); + } 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 disabledRw() { + if (!aconfig_test_is_cached) { + load_overrides_aconfig_test(); + } + return disabledRw; + } + + @Override + @UnsupportedAppUsage + public boolean disabledRwExported() { + if (!aconfig_test_is_cached) { + load_overrides_aconfig_test(); + } + return disabledRwExported; + } + }"#; + + let expect_fake_feature_flags_impl_content = r#" + package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. + import android.compat.annotation.UnsupportedAppUsage; + import java.util.HashMap; + import java.util.Map; + /** @hide */ + public class FakeFeatureFlagsImpl implements FeatureFlags { + public FakeFeatureFlagsImpl() { + resetAll(); + } + @Override + @UnsupportedAppUsage + public boolean disabledRw() { + return getValue(Flags.FLAG_DISABLED_RW); + } + @Override + @UnsupportedAppUsage + public boolean disabledRwExported() { + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); + } + public void setFlag(String flagName, boolean value) { + if (!this.mFlagMap.containsKey(flagName)) { + throw new IllegalArgumentException("no such flag " + flagName); + } + this.mFlagMap.put(flagName, value); + } + public void resetAll() { + for (Map.Entry entry : mFlagMap.entrySet()) { + entry.setValue(null); + } + } + private boolean getValue(String flagName) { + Boolean value = this.mFlagMap.get(flagName); + if (value == null) { + throw new IllegalArgumentException(flagName + " is not set"); + } + return value; + } + private Map mFlagMap = new HashMap<>( + Map.ofEntries( + Map.entry(Flags.FLAG_DISABLED_RO, false), + Map.entry(Flags.FLAG_DISABLED_RW, false), + Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), + Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), + Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), + Map.entry(Flags.FLAG_ENABLED_RO, false), + Map.entry(Flags.FLAG_ENABLED_RW, false) + ) + ); + } + "#; + + let mut file_set = HashMap::from([ + ("com/android/aconfig/test/Flags.java", expect_flags_content), + ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content), + ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content), + ( + "com/android/aconfig/test/FakeFeatureFlagsImpl.java", + expect_fake_feature_flags_impl_content, + ), + ]); + + for file in generated_files { + let file_path = file.path.to_str().unwrap(); + assert!(file_set.contains_key(file_path), "Cannot find {}", file_path); + assert_eq!( + None, + crate::test::first_significant_code_diff( + file_set.get(file_path).unwrap(), + &String::from_utf8(file.contents).unwrap() + ), + "File {} content is not correct", + file_path + ); + file_set.remove(file_path); + } + + assert!(file_set.is_empty()); + } + #[test] fn test_generate_java_code_test() { let parsed_flags = crate::test::parse_test_flags(); @@ -489,6 +715,12 @@ mod tests { } @Override @UnsupportedAppUsage + public boolean disabledRwExported() { + throw new UnsupportedOperationException( + "Method is not implemented."); + } + @Override + @UnsupportedAppUsage public boolean disabledRwInOtherNamespace() { throw new UnsupportedOperationException( "Method is not implemented."); diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs index d8675e7031..502cec8cd3 100644 --- a/tools/aconfig/src/codegen_rust.rs +++ b/tools/aconfig/src/codegen_rust.rs @@ -45,6 +45,9 @@ where match codegen_mode { CodegenMode::Production => include_str!("../templates/rust_prod.template"), CodegenMode::Test => include_str!("../templates/rust_test.template"), + CodegenMode::Exported => { + todo!("exported mode not yet supported for rust, see b/313894653.") + } }, )?; let contents = template.render("rust_code_gen", &context)?; @@ -104,6 +107,12 @@ lazy_static::lazy_static! { "com.android.aconfig.test.disabled_rw", "false") == "true"; + /// flag value cache for disabled_rw_exported + static ref CACHED_disabled_rw_exported: bool = flags_rust::GetServerConfigurableFlag( + "aconfig_flags.aconfig_test", + "com.android.aconfig.test.disabled_rw_exported", + "false") == "true"; + /// flag value cache for disabled_rw_in_other_namespace static ref CACHED_disabled_rw_in_other_namespace: bool = flags_rust::GetServerConfigurableFlag( "aconfig_flags.other_namespace", @@ -115,6 +124,7 @@ lazy_static::lazy_static! { "aconfig_flags.aconfig_test", "com.android.aconfig.test.enabled_rw", "true") == "true"; + } impl FlagProvider { @@ -128,6 +138,11 @@ impl FlagProvider { *CACHED_disabled_rw } + /// query flag disabled_rw_exported + pub fn disabled_rw_exported(&self) -> bool { + *CACHED_disabled_rw_exported + } + /// query flag disabled_rw_in_other_namespace pub fn disabled_rw_in_other_namespace(&self) -> bool { *CACHED_disabled_rw_in_other_namespace @@ -164,6 +179,12 @@ pub fn disabled_rw() -> bool { PROVIDER.disabled_rw() } +/// query flag disabled_rw_exported +#[inline(always)] +pub fn disabled_rw_exported() -> bool { + PROVIDER.disabled_rw_exported() +} + /// query flag disabled_rw_in_other_namespace #[inline(always)] pub fn disabled_rw_in_other_namespace() -> bool { @@ -228,6 +249,21 @@ impl FlagProvider { self.overrides.insert("disabled_rw", val); } + /// query flag disabled_rw_exported + pub fn disabled_rw_exported(&self) -> bool { + self.overrides.get("disabled_rw_exported").copied().unwrap_or( + flags_rust::GetServerConfigurableFlag( + "aconfig_flags.aconfig_test", + "com.android.aconfig.test.disabled_rw_exported", + "false") == "true" + ) + } + + /// set flag disabled_rw_exported + pub fn set_disabled_rw_exported(&mut self, val: bool) { + self.overrides.insert("disabled_rw_exported", val); + } + /// query flag disabled_rw_in_other_namespace pub fn disabled_rw_in_other_namespace(&self) -> bool { self.overrides.get("disabled_rw_in_other_namespace").copied().unwrap_or( @@ -317,6 +353,18 @@ pub fn set_disabled_rw(val: bool) { PROVIDER.lock().unwrap().set_disabled_rw(val); } +/// query flag disabled_rw_exported +#[inline(always)] +pub fn disabled_rw_exported() -> bool { + PROVIDER.lock().unwrap().disabled_rw_exported() +} + +/// set flag disabled_rw_exported +#[inline(always)] +pub fn set_disabled_rw_exported(val: bool) { + PROVIDER.lock().unwrap().set_disabled_rw_exported(val); +} + /// query flag disabled_rw_in_other_namespace #[inline(always)] pub fn disabled_rw_in_other_namespace() -> bool { @@ -383,6 +431,8 @@ pub fn reset_flags() { match mode { CodegenMode::Production => PROD_EXPECTED, CodegenMode::Test => TEST_EXPECTED, + CodegenMode::Exported => + todo!("exported mode not yet supported for rust, see b/313894653."), }, &String::from_utf8(generated.contents).unwrap() ) diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs index ff0df1f56d..47e90ac67e 100644 --- a/tools/aconfig/src/commands.rs +++ b/tools/aconfig/src/commands.rs @@ -171,6 +171,7 @@ pub fn parse_flags( pub enum CodegenMode { Production, Test, + Exported, } pub fn create_java_lib(mut input: Input, codegen_mode: CodegenMode) -> Result> { @@ -335,7 +336,7 @@ mod tests { assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state()); assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission()); - assert_eq!(6, parsed_flags.parsed_flag.len()); + assert_eq!(7, parsed_flags.parsed_flag.len()); for pf in parsed_flags.parsed_flag.iter() { if pf.name() == "enabled_fixed_ro" { continue; @@ -434,7 +435,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\nother_namespace:com.android.aconfig.test.disabled_rw_in_other_namespace=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text); + assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.disabled_rw_exported=disabled\nother_namespace:com.android.aconfig.test.disabled_rw_in_other_namespace=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text); } #[test] @@ -442,7 +443,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.disabled_rw_in_other_namespace=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_exported=false\npersist.device_config.com.android.aconfig.test.disabled_rw_in_other_namespace=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text); } #[test] diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs index 31c67b3ce4..9f598d0021 100644 --- a/tools/aconfig/src/test.rs +++ b/tools/aconfig/src/test.rs @@ -60,6 +60,27 @@ parsed_flag { is_fixed_read_only: false is_exported: true } +parsed_flag { + package: "com.android.aconfig.test" + name: "disabled_rw_exported" + namespace: "aconfig_test" + description: "This flag is exported" + bug: "111" + 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 + is_exported: true +} parsed_flag { package: "com.android.aconfig.test" name: "disabled_rw_in_other_namespace" diff --git a/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template b/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template index 933d6a77cb..fd2e26a934 100644 --- a/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template +++ b/tools/aconfig/templates/FakeFeatureFlagsImpl.java.template @@ -12,11 +12,23 @@ public class FakeFeatureFlagsImpl implements FeatureFlags \{ } {{ for item in flag_elements}} +{{ if library_exported }} + +{{ if item.exported }} @Override @UnsupportedAppUsage public boolean {item.method_name}() \{ return getValue(Flags.FLAG_{item.flag_name_constant_suffix}); } +{{ endif }} + +{{ else }} + @Override + @UnsupportedAppUsage + public boolean {item.method_name}() \{ + return getValue(Flags.FLAG_{item.flag_name_constant_suffix}); + } +{{ endif }} {{ endfor}} public void setFlag(String flagName, boolean value) \{ if (!this.mFlagMap.containsKey(flagName)) \{ diff --git a/tools/aconfig/templates/FeatureFlags.java.template b/tools/aconfig/templates/FeatureFlags.java.template index da850aec4f..180f8828d2 100644 --- a/tools/aconfig/templates/FeatureFlags.java.template +++ b/tools/aconfig/templates/FeatureFlags.java.template @@ -5,6 +5,15 @@ import android.compat.annotation.UnsupportedAppUsage; /** @hide */ public interface FeatureFlags \{ {{ for item in flag_elements }} +{{ if library_exported }} + +{{ if item.exported }} + @UnsupportedAppUsage + boolean {item.method_name}(); +{{ endif }} + +{{ else }} + {{ -if not item.is_read_write }} {{ -if item.default_value }} @com.android.aconfig.annotations.AssumeTrueForR8 @@ -14,5 +23,7 @@ public interface FeatureFlags \{ {{ endif }} @UnsupportedAppUsage boolean {item.method_name}(); + +{{ endif }} {{ endfor }} } diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template index ec8822c49c..a15c85952f 100644 --- a/tools/aconfig/templates/FeatureFlagsImpl.java.template +++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template @@ -14,9 +14,17 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ {{- endfor- }} {{ for flag in flag_elements }} +{{ if library_exported }} +{{ if flag.exported }} + private static boolean {flag.method_name} = false; +{{ endif }} + +{{ else }} + {{- if flag.is_read_write }} private static boolean {flag.method_name} = {flag.default_value}; {{- endif- }} +{{ endif }} {{ endfor }} {{ for namespace_with_flags in namespace_flags }} @@ -25,10 +33,21 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}"); {{- for flag in namespace_with_flags.flags }} - {{- if flag.is_read_write }} + {{ if library_exported }} + + {{ if flag.exported }} + {flag.method_name} = + properties.getBoolean("{flag.device_config_flag}", false); + {{ endif }} + + {{ else }} + + {{ if flag.is_read_write }} {flag.method_name} = properties.getBoolean("{flag.device_config_flag}", {flag.default_value}); - {{- endif- }} + {{ endif }} + + {{ endif }} {{ endfor }} } catch (NullPointerException e) \{ throw new RuntimeException( @@ -46,6 +65,9 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ {{ endif- }} {{ for flag in flag_elements }} +{{ if library_exported }} + +{{ if flag.exported }} @Override @UnsupportedAppUsage public boolean {flag.method_name}() \{ @@ -58,6 +80,23 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ return {flag.default_value}; {{ endif- }} } +{{ endif }} + +{{ else }} + @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- }} + } +{{ endif }} + {{ endfor }} } {{ else }} diff --git a/tools/aconfig/templates/Flags.java.template b/tools/aconfig/templates/Flags.java.template index cf6604cfa3..9f4c52f978 100644 --- a/tools/aconfig/templates/Flags.java.template +++ b/tools/aconfig/templates/Flags.java.template @@ -6,10 +6,28 @@ import android.compat.annotation.UnsupportedAppUsage; /** @hide */ public final class Flags \{ {{- for item in flag_elements}} + {{ if library_exported }} + {{ if item.exported }} /** @hide */ public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}"; + {{ endif }} + {{ else }} + /** @hide */ + public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}"; + {{ endif }} {{- endfor }} {{ for item in flag_elements}} +{{ if library_exported }} + +{{ if item.exported }} + @UnsupportedAppUsage + public static boolean {item.method_name}() \{ + return FEATURE_FLAGS.{item.method_name}(); + } +{{ endif }} + +{{ else }} + {{ -if not item.is_read_write }} {{ -if item.default_value }} @com.android.aconfig.annotations.AssumeTrueForR8 @@ -21,6 +39,7 @@ public final class Flags \{ public static boolean {item.method_name}() \{ return FEATURE_FLAGS.{item.method_name}(); } +{{ endif }} {{ endfor }} {{ -if is_test_mode }} public static void setFeatureFlags(FeatureFlags featureFlags) \{ diff --git a/tools/aconfig/tests/first.values b/tools/aconfig/tests/first.values index 07d8d1ded2..b248d43dbd 100644 --- a/tools/aconfig/tests/first.values +++ b/tools/aconfig/tests/first.values @@ -28,3 +28,9 @@ flag_value { state: ENABLED permission: READ_ONLY } +flag_value { + package: "com.android.aconfig.test" + name: "disabled_rw_exported" + state: DISABLED + permission: READ_WRITE +} diff --git a/tools/aconfig/tests/test.aconfig b/tools/aconfig/tests/test.aconfig index b49b6656fd..8a1a913363 100644 --- a/tools/aconfig/tests/test.aconfig +++ b/tools/aconfig/tests/test.aconfig @@ -59,3 +59,11 @@ flag { description: "This flag is DISABLED + READ_WRITE, and is defined in another namespace" bug: "999" } + +flag { + name: "disabled_rw_exported" + namespace: "aconfig_test" + description: "This flag is exported" + bug: "111" + is_exported: true +} \ No newline at end of file