Loading tools/aconfig/aconfig/src/codegen/java.rs +189 −0 Original line number Diff line number Diff line Loading @@ -874,6 +874,195 @@ mod tests { assert!(file_set.is_empty()); } #[test] fn test_generate_java_code_new_exported() { let parsed_flags = crate::test::parse_test_flags(); let mode = CodegenMode::Exported; let modified_parsed_flags = crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap(); let flag_ids = assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap(); let generated_files = generate_java_code( crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode, flag_ids, true, 5801144784618221668, true, ) .unwrap(); let expect_flags_content = r#" package com.android.aconfig.test; /** @hide */ public final class Flags { /** @hide */ public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported"; /** @hide */ public static final String FLAG_ENABLED_FIXED_RO_EXPORTED = "com.android.aconfig.test.enabled_fixed_ro_exported"; /** @hide */ public static final String FLAG_ENABLED_RO_EXPORTED = "com.android.aconfig.test.enabled_ro_exported"; public static boolean disabledRwExported() { return FEATURE_FLAGS.disabledRwExported(); } public static boolean enabledFixedRoExported() { return FEATURE_FLAGS.enabledFixedRoExported(); } public static boolean enabledRoExported() { return FEATURE_FLAGS.enabledRoExported(); } private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); } "#; let expect_feature_flags_content = r#" package com.android.aconfig.test; /** @hide */ public interface FeatureFlags { boolean disabledRwExported(); boolean enabledFixedRoExported(); boolean enabledRoExported(); } "#; let expect_feature_flags_impl_content = r#" package com.android.aconfig.test; import android.os.flagging.AconfigPackage; import android.util.Log; /** @hide */ public final class FeatureFlagsImpl implements FeatureFlags { private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl_exported"; private static volatile boolean isCached = false; private static boolean disabledRwExported = false; private static boolean enabledFixedRoExported = false; private static boolean enabledRoExported = false; private void init() { try { AconfigPackage reader = AconfigPackage.load("com.android.aconfig.test"); disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false); enabledFixedRoExported = reader.getBooleanFlagValue("enabled_fixed_ro_exported", false); enabledRoExported = reader.getBooleanFlagValue("enabled_ro_exported", false); } catch (Exception e) { // pass Log.e(TAG, e.toString()); } catch (NoClassDefFoundError e) { // for mainline module running on older devices. // This should be replaces to version check, after the version bump. Log.e(TAG, e.toString()); } isCached = true; } @Override public boolean disabledRwExported() { if (!isCached) { init(); } return disabledRwExported; } @Override public boolean enabledFixedRoExported() { if (!isCached) { init(); } return enabledFixedRoExported; } @Override public boolean enabledRoExported() { if (!isCached) { init(); } return enabledRoExported; } }"#; let expect_custom_feature_flags_content = r#" package com.android.aconfig.test; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.BiPredicate; import java.util.function.Predicate; /** @hide */ public class CustomFeatureFlags implements FeatureFlags { private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { mGetValueImpl = getValueImpl; } @Override public boolean disabledRwExported() { return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, FeatureFlags::disabledRwExported); } @Override public boolean enabledFixedRoExported() { return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, FeatureFlags::enabledFixedRoExported); } @Override public boolean enabledRoExported() { return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, FeatureFlags::enabledRoExported); } protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { return mGetValueImpl.test(flagName, getter); } public List<String> getFlagNames() { return Arrays.asList( Flags.FLAG_DISABLED_RW_EXPORTED, Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, Flags.FLAG_ENABLED_RO_EXPORTED ); } private Set<String> mReadOnlyFlagsSet = new HashSet<>( Arrays.asList( "" ) ); } "#; 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/CustomFeatureFlags.java", expect_custom_feature_flags_content, ), ( "com/android/aconfig/test/FakeFeatureFlagsImpl.java", EXPECTED_FAKEFEATUREFLAGSIMPL_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 tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template +40 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,45 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ {{ endfor }} } {{ -else- }}{#- device config for exproted mode #} {{ -if new_exported }} import android.os.flagging.AconfigPackage; import android.util.Log; /** @hide */ public final class FeatureFlagsImpl implements FeatureFlags \{ private static final String TAG = "{package_name}.FeatureFlagsImpl_exported"; private static volatile boolean isCached = false; {{ for flag in flag_elements }} private static boolean {flag.method_name} = {flag.default_value}; {{ -endfor }} private void init() \{ try \{ AconfigPackage reader = AconfigPackage.load("{package_name}"); {{ -for namespace_with_flags in namespace_flags }} {{ -for flag in namespace_with_flags.flags }} {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value}); {{ -endfor }} {{ -endfor }} } catch (Exception e) \{ // pass Log.e(TAG, e.toString()); } catch (NoClassDefFoundError e) \{ // for mainline module running on older devices. // This should be replaces to version check, after the version bump. Log.e(TAG, e.toString()); } isCached = true; } {{ -for flag in flag_elements }} @Override public boolean {flag.method_name}() \{ if (!isCached) \{ init(); } return {flag.method_name}; } {{ endfor }} } {{ else }} import android.os.Binder; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; Loading Loading @@ -116,6 +155,7 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ } {{ endfor }} } {{ -endif- }} {#- end new_exported mode #} {{ -endif- }} {#- end exported mode #} {{ else }} {#- else for allow_instrumentation is not enabled #} {{ if not library_exported- }} Loading Loading
tools/aconfig/aconfig/src/codegen/java.rs +189 −0 Original line number Diff line number Diff line Loading @@ -874,6 +874,195 @@ mod tests { assert!(file_set.is_empty()); } #[test] fn test_generate_java_code_new_exported() { let parsed_flags = crate::test::parse_test_flags(); let mode = CodegenMode::Exported; let modified_parsed_flags = crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap(); let flag_ids = assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap(); let generated_files = generate_java_code( crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode, flag_ids, true, 5801144784618221668, true, ) .unwrap(); let expect_flags_content = r#" package com.android.aconfig.test; /** @hide */ public final class Flags { /** @hide */ public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported"; /** @hide */ public static final String FLAG_ENABLED_FIXED_RO_EXPORTED = "com.android.aconfig.test.enabled_fixed_ro_exported"; /** @hide */ public static final String FLAG_ENABLED_RO_EXPORTED = "com.android.aconfig.test.enabled_ro_exported"; public static boolean disabledRwExported() { return FEATURE_FLAGS.disabledRwExported(); } public static boolean enabledFixedRoExported() { return FEATURE_FLAGS.enabledFixedRoExported(); } public static boolean enabledRoExported() { return FEATURE_FLAGS.enabledRoExported(); } private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); } "#; let expect_feature_flags_content = r#" package com.android.aconfig.test; /** @hide */ public interface FeatureFlags { boolean disabledRwExported(); boolean enabledFixedRoExported(); boolean enabledRoExported(); } "#; let expect_feature_flags_impl_content = r#" package com.android.aconfig.test; import android.os.flagging.AconfigPackage; import android.util.Log; /** @hide */ public final class FeatureFlagsImpl implements FeatureFlags { private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl_exported"; private static volatile boolean isCached = false; private static boolean disabledRwExported = false; private static boolean enabledFixedRoExported = false; private static boolean enabledRoExported = false; private void init() { try { AconfigPackage reader = AconfigPackage.load("com.android.aconfig.test"); disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false); enabledFixedRoExported = reader.getBooleanFlagValue("enabled_fixed_ro_exported", false); enabledRoExported = reader.getBooleanFlagValue("enabled_ro_exported", false); } catch (Exception e) { // pass Log.e(TAG, e.toString()); } catch (NoClassDefFoundError e) { // for mainline module running on older devices. // This should be replaces to version check, after the version bump. Log.e(TAG, e.toString()); } isCached = true; } @Override public boolean disabledRwExported() { if (!isCached) { init(); } return disabledRwExported; } @Override public boolean enabledFixedRoExported() { if (!isCached) { init(); } return enabledFixedRoExported; } @Override public boolean enabledRoExported() { if (!isCached) { init(); } return enabledRoExported; } }"#; let expect_custom_feature_flags_content = r#" package com.android.aconfig.test; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.BiPredicate; import java.util.function.Predicate; /** @hide */ public class CustomFeatureFlags implements FeatureFlags { private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { mGetValueImpl = getValueImpl; } @Override public boolean disabledRwExported() { return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, FeatureFlags::disabledRwExported); } @Override public boolean enabledFixedRoExported() { return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, FeatureFlags::enabledFixedRoExported); } @Override public boolean enabledRoExported() { return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, FeatureFlags::enabledRoExported); } protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { return mGetValueImpl.test(flagName, getter); } public List<String> getFlagNames() { return Arrays.asList( Flags.FLAG_DISABLED_RW_EXPORTED, Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, Flags.FLAG_ENABLED_RO_EXPORTED ); } private Set<String> mReadOnlyFlagsSet = new HashSet<>( Arrays.asList( "" ) ); } "#; 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/CustomFeatureFlags.java", expect_custom_feature_flags_content, ), ( "com/android/aconfig/test/FakeFeatureFlagsImpl.java", EXPECTED_FAKEFEATUREFLAGSIMPL_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
tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template +40 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,45 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ {{ endfor }} } {{ -else- }}{#- device config for exproted mode #} {{ -if new_exported }} import android.os.flagging.AconfigPackage; import android.util.Log; /** @hide */ public final class FeatureFlagsImpl implements FeatureFlags \{ private static final String TAG = "{package_name}.FeatureFlagsImpl_exported"; private static volatile boolean isCached = false; {{ for flag in flag_elements }} private static boolean {flag.method_name} = {flag.default_value}; {{ -endfor }} private void init() \{ try \{ AconfigPackage reader = AconfigPackage.load("{package_name}"); {{ -for namespace_with_flags in namespace_flags }} {{ -for flag in namespace_with_flags.flags }} {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value}); {{ -endfor }} {{ -endfor }} } catch (Exception e) \{ // pass Log.e(TAG, e.toString()); } catch (NoClassDefFoundError e) \{ // for mainline module running on older devices. // This should be replaces to version check, after the version bump. Log.e(TAG, e.toString()); } isCached = true; } {{ -for flag in flag_elements }} @Override public boolean {flag.method_name}() \{ if (!isCached) \{ init(); } return {flag.method_name}; } {{ endfor }} } {{ else }} import android.os.Binder; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; Loading Loading @@ -116,6 +155,7 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ } {{ endfor }} } {{ -endif- }} {#- end new_exported mode #} {{ -endif- }} {#- end exported mode #} {{ else }} {#- else for allow_instrumentation is not enabled #} {{ if not library_exported- }} Loading