Loading tools/aconfig/src/codegen_cpp.rs +74 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } Loading @@ -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(); Loading Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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); Loading Loading @@ -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 { Loading @@ -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<int8_t> cache_ = std::vector<int8_t>(3, -1); std::vector<int8_t> cache_ = std::vector<int8_t>(4, -1); }; std::unique_ptr<flag_provider_interface> provider_ = Loading @@ -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(); } Loading Loading @@ -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()) { Loading Loading @@ -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); } Loading Loading @@ -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() ) Loading @@ -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() ) Loading tools/aconfig/src/codegen_java.rs +232 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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"))?; Loading Loading @@ -103,6 +105,7 @@ struct Context { pub is_read_write: bool, pub properties_set: BTreeSet<String>, pub package_name: String, pub library_exported: bool, } #[derive(Serialize, Debug)] Loading @@ -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 { Loading @@ -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), } } Loading Loading @@ -179,6 +184,8 @@ mod tests { @UnsupportedAppUsage boolean disabledRw(); @UnsupportedAppUsage boolean disabledRwExported(); @UnsupportedAppUsage boolean disabledRwInOtherNamespace(); @com.android.aconfig.annotations.AssumeTrueForR8 @UnsupportedAppUsage Loading @@ -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"; Loading @@ -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(); } Loading Loading @@ -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); } Loading Loading @@ -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), Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading Loading @@ -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<String, Boolean> 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(); Loading Loading @@ -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."); Loading tools/aconfig/src/codegen_rust.rs +50 −0 Original line number Diff line number Diff line Loading @@ -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)?; Loading Loading @@ -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", Loading @@ -115,6 +124,7 @@ lazy_static::lazy_static! { "aconfig_flags.aconfig_test", "com.android.aconfig.test.enabled_rw", "true") == "true"; } impl FlagProvider { Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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( Loading Loading @@ -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 { Loading Loading @@ -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() ) Loading tools/aconfig/src/commands.rs +4 −3 Original line number Diff line number Diff line Loading @@ -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<Vec<OutputFile>> { Loading Loading @@ -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; Loading Loading @@ -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] Loading @@ -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] Loading tools/aconfig/src/test.rs +21 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
tools/aconfig/src/codegen_cpp.rs +74 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } Loading @@ -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(); Loading Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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); Loading Loading @@ -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 { Loading @@ -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<int8_t> cache_ = std::vector<int8_t>(3, -1); std::vector<int8_t> cache_ = std::vector<int8_t>(4, -1); }; std::unique_ptr<flag_provider_interface> provider_ = Loading @@ -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(); } Loading Loading @@ -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()) { Loading Loading @@ -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); } Loading Loading @@ -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() ) Loading @@ -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() ) Loading
tools/aconfig/src/codegen_java.rs +232 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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"))?; Loading Loading @@ -103,6 +105,7 @@ struct Context { pub is_read_write: bool, pub properties_set: BTreeSet<String>, pub package_name: String, pub library_exported: bool, } #[derive(Serialize, Debug)] Loading @@ -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 { Loading @@ -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), } } Loading Loading @@ -179,6 +184,8 @@ mod tests { @UnsupportedAppUsage boolean disabledRw(); @UnsupportedAppUsage boolean disabledRwExported(); @UnsupportedAppUsage boolean disabledRwInOtherNamespace(); @com.android.aconfig.annotations.AssumeTrueForR8 @UnsupportedAppUsage Loading @@ -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"; Loading @@ -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(); } Loading Loading @@ -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); } Loading Loading @@ -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), Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading Loading @@ -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<String, Boolean> 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(); Loading Loading @@ -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."); Loading
tools/aconfig/src/codegen_rust.rs +50 −0 Original line number Diff line number Diff line Loading @@ -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)?; Loading Loading @@ -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", Loading @@ -115,6 +124,7 @@ lazy_static::lazy_static! { "aconfig_flags.aconfig_test", "com.android.aconfig.test.enabled_rw", "true") == "true"; } impl FlagProvider { Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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( Loading Loading @@ -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 { Loading Loading @@ -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() ) Loading
tools/aconfig/src/commands.rs +4 −3 Original line number Diff line number Diff line Loading @@ -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<Vec<OutputFile>> { Loading Loading @@ -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; Loading Loading @@ -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] Loading @@ -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] Loading
tools/aconfig/src/test.rs +21 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes