Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f659f752 authored by Zhi Dou's avatar Zhi Dou Committed by Gerrit Code Review
Browse files

Merge changes from topic "fro" into main

* changes:
  aconfig: add ForceReadOnly mode to aconfig java codegen
  aconfig: add new codegen mode force_read_only
parents 7f915994 e567abdf
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -96,6 +96,12 @@ aconfig_declarations {
    srcs: ["tests/test_exported.aconfig"],
}

aconfig_declarations {
    name: "aconfig.test.forcereadonly.flags",
    package: "com.android.aconfig.test.forcereadonly",
    srcs: ["tests/test_force_read_only.aconfig"],
}

aconfig_values {
    name: "aconfig.test.flag.values",
    package: "com.android.aconfig.test",
@@ -125,6 +131,12 @@ java_aconfig_library {
    mode: "exported",
}

java_aconfig_library {
    name: "aconfig_test_java_library_forcereadonly",
    aconfig_declarations: "aconfig.test.forcereadonly.flags",
    mode: "force-read-only",
}

android_test {
    name: "aconfig.test.java",
    srcs: [
@@ -135,6 +147,7 @@ android_test {
    static_libs: [
        "aconfig_test_java_library",
        "aconfig_test_java_library_exported",
        "aconfig_test_java_library_forcereadonly",
        "androidx.test.rules",
        "testng",
    ],
+222 −0
Original line number Diff line number Diff line
@@ -833,6 +833,228 @@ mod tests {
        assert!(file_set.is_empty());
    }

    #[test]
    fn test_generate_java_code_force_read_only() {
        let parsed_flags = crate::test::parse_test_flags();
        let mode = CodegenMode::ForceReadOnly;
        let modified_parsed_flags =
            crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
        let generated_files =
            generate_java_code(crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode)
                .unwrap();
        let expect_featureflags_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 {
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            boolean disabledRo();
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            boolean disabledRw();
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            boolean disabledRwInOtherNamespace();
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            boolean enabledFixedRo();
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            boolean enabledRo();
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            boolean enabledRw();
        }"#;

        let expect_featureflagsimpl_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 FeatureFlagsImpl implements FeatureFlags {
            @Override
            @UnsupportedAppUsage
            public boolean disabledRo() {
                return false;
            }
            @Override
            @UnsupportedAppUsage
            public boolean disabledRw() {
                return false;
            }
            @Override
            @UnsupportedAppUsage
            public boolean disabledRwInOtherNamespace() {
                return false;
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledFixedRo() {
                return true;
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledRo() {
                return true;
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledRw() {
                return true;
            }
        }
        "#;

        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_RO = "com.android.aconfig.test.disabled_ro";
            /** @hide */
            public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
            /** @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";
            /** @hide */
            public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
            /** @hide */
            public static final String FLAG_ENABLED_RW = "com.android.aconfig.test.enabled_rw";
    
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            public static boolean disabledRo() {
                return FEATURE_FLAGS.disabledRo();
            }
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            public static boolean disabledRw() {
                return FEATURE_FLAGS.disabledRw();
            }
            @com.android.aconfig.annotations.AssumeFalseForR8
            @UnsupportedAppUsage
            public static boolean disabledRwInOtherNamespace() {
                return FEATURE_FLAGS.disabledRwInOtherNamespace();
            }
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            public static boolean enabledFixedRo() {
                return FEATURE_FLAGS.enabledFixedRo();
            }
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            public static boolean enabledRo() {
                return FEATURE_FLAGS.enabledRo();
            }
            @com.android.aconfig.annotations.AssumeTrueForR8
            @UnsupportedAppUsage
            public static boolean enabledRw() {
                return FEATURE_FLAGS.enabledRw();
            }
            private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
        }"#;

        let expect_fakefeatureflags_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 disabledRo() {
                return getValue(Flags.FLAG_DISABLED_RO);
            }
            @Override
            @UnsupportedAppUsage
            public boolean disabledRw() {
                return getValue(Flags.FLAG_DISABLED_RW);
            }
            @Override
            @UnsupportedAppUsage
            public boolean disabledRwInOtherNamespace() {
                return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledFixedRo() {
                return getValue(Flags.FLAG_ENABLED_FIXED_RO);
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledRo() {
                return getValue(Flags.FLAG_ENABLED_RO);
            }
            @Override
            @UnsupportedAppUsage
            public boolean enabledRw() {
                return getValue(Flags.FLAG_ENABLED_RW);
            }
            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_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/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
            ("com/android/aconfig/test/FeatureFlags.java", expect_featureflags_content),
            ("com/android/aconfig/test/FakeFeatureFlagsImpl.java", expect_fakefeatureflags_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_format_java_method_name() {
        let expected = "someSnakeName";
+2 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ pub fn create_device_config_ident(package: &str, flag_name: &str) -> Result<Stri
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum CodegenMode {
    Exported,
    ForceReadOnly,
    Production,
    Test,
}
@@ -64,6 +65,7 @@ impl std::fmt::Display for CodegenMode {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            CodegenMode::Exported => write!(f, "exported"),
            CodegenMode::ForceReadOnly => write!(f, "force-read-only"),
            CodegenMode::Production => write!(f, "production"),
            CodegenMode::Test => write!(f, "test"),
        }
+2 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ where
            CodegenMode::Production => include_str!("../../templates/rust_prod.template"),
            CodegenMode::Test => include_str!("../../templates/rust_test.template"),
            CodegenMode::Exported => include_str!("../../templates/rust_exported.template"),
            CodegenMode::ForceReadOnly => todo!(),
        },
    )?;
    let contents = template.render("rust_code_gen", &context)?;
@@ -569,6 +570,7 @@ pub fn enabled_ro_exported() -> bool {
                    CodegenMode::Production => PROD_EXPECTED,
                    CodegenMode::Test => TEST_EXPECTED,
                    CodegenMode::Exported => EXPORTED_EXPECTED,
                    codegen::CodegenMode::ForceReadOnly => todo!(),
                },
                &String::from_utf8(generated.contents).unwrap()
            )
+32 −0
Original line number Diff line number Diff line
@@ -332,6 +332,11 @@ pub fn modify_parsed_flags_based_on_mode(
        parsed_flag
    }

    fn force_read_only_mode_flag_modifier(mut parsed_flag: ProtoParsedFlag) -> ProtoParsedFlag {
        parsed_flag.set_permission(ProtoFlagPermission::READ_ONLY);
        parsed_flag
    }

    let modified_parsed_flags: Vec<_> = match codegen_mode {
        CodegenMode::Exported => parsed_flags
            .parsed_flag
@@ -339,6 +344,12 @@ pub fn modify_parsed_flags_based_on_mode(
            .filter(|pf| pf.is_exported())
            .map(exported_mode_flag_modifier)
            .collect(),
        CodegenMode::ForceReadOnly => parsed_flags
            .parsed_flag
            .into_iter()
            .filter(|pf| !pf.is_exported())
            .map(force_read_only_mode_flag_modifier)
            .collect(),
        CodegenMode::Production | CodegenMode::Test => {
            parsed_flags.parsed_flag.into_iter().collect()
        }
@@ -694,4 +705,25 @@ mod tests {
        ]);
        assert_eq!(flag_ids, expected_flag_ids);
    }

    #[test]
    fn test_modify_parsed_flags_based_on_mode_force_read_only() {
        let parsed_flags = crate::test::parse_test_flags();
        let p_parsed_flags =
            modify_parsed_flags_based_on_mode(parsed_flags.clone(), CodegenMode::ForceReadOnly)
                .unwrap();
        assert_eq!(6, p_parsed_flags.len());
        for pf in p_parsed_flags {
            assert_eq!(ProtoFlagPermission::READ_ONLY, pf.permission());
        }

        let mut parsed_flags = crate::test::parse_test_flags();
        parsed_flags.parsed_flag.retain_mut(|pf| pf.is_exported());
        let error = modify_parsed_flags_based_on_mode(parsed_flags, CodegenMode::ForceReadOnly)
            .unwrap_err();
        assert_eq!(
            "force-read-only library contains no force-read-only flags",
            format!("{:?}", error)
        );
    }
}
Loading