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

Commit bce58b3c authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Change java codegen to read from new storage" into main

parents acbc35aa 9f8ed739
Loading
Loading
Loading
Loading
+60 −27
Original line number Diff line number Diff line
@@ -20,22 +20,24 @@ use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use tinytemplate::TinyTemplate;

use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};

use crate::codegen;
use crate::codegen::CodegenMode;
use crate::commands::OutputFile;
use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
use std::collections::HashMap;

pub fn generate_java_code<I>(
    package: &str,
    parsed_flags_iter: I,
    codegen_mode: CodegenMode,
    flag_ids: HashMap<String, u16>,
    allow_instrumentation: bool,
) -> Result<Vec<OutputFile>>
where
    I: Iterator<Item = ProtoParsedFlag>,
{
    let flag_elements: Vec<FlagElement> =
        parsed_flags_iter.map(|pf| create_flag_element(package, &pf)).collect();
        parsed_flags_iter.map(|pf| create_flag_element(package, &pf, flag_ids.clone())).collect();
    let namespace_flags = gen_flags_by_namespace(&flag_elements);
    let properties_set: BTreeSet<String> =
        flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect();
@@ -43,6 +45,7 @@ where
    let library_exported = codegen_mode == CodegenMode::Exported;
    let runtime_lookup_required =
        flag_elements.iter().any(|elem| elem.is_read_write) || library_exported;
    let container = (flag_elements.first().expect("zero template flags").container).to_string();

    let context = Context {
        flag_elements,
@@ -52,6 +55,8 @@ where
        properties_set,
        package_name: package.to_string(),
        library_exported,
        allow_instrumentation,
        container,
    };
    let mut template = TinyTemplate::new();
    template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
@@ -117,6 +122,8 @@ struct Context {
    pub properties_set: BTreeSet<String>,
    pub package_name: String,
    pub library_exported: bool,
    pub allow_instrumentation: bool,
    pub container: String,
}

#[derive(Serialize, Debug)]
@@ -127,23 +134,31 @@ struct NamespaceFlags {

#[derive(Serialize, Clone, Debug)]
struct FlagElement {
    pub container: String,
    pub default_value: bool,
    pub device_config_namespace: String,
    pub device_config_flag: String,
    pub flag_name_constant_suffix: String,
    pub flag_offset: u16,
    pub is_read_write: bool,
    pub method_name: String,
    pub properties: String,
}

fn create_flag_element(package: &str, pf: &ProtoParsedFlag) -> FlagElement {
fn create_flag_element(
    package: &str,
    pf: &ProtoParsedFlag,
    flag_offsets: HashMap<String, u16>,
) -> FlagElement {
    let device_config_flag = codegen::create_device_config_ident(package, pf.name())
        .expect("values checked at flag parse time");
    FlagElement {
        container: pf.container().to_string(),
        default_value: pf.state() == ProtoFlagState::ENABLED,
        device_config_namespace: pf.namespace().to_string(),
        device_config_flag,
        flag_name_constant_suffix: pf.name().to_ascii_uppercase(),
        flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
        is_read_write: pf.permission() == ProtoFlagPermission::READ_WRITE,
        method_name: format_java_method_name(pf.name()),
        properties: format_property_name(pf.namespace()),
@@ -179,6 +194,7 @@ fn format_property_name(property_name: &str) -> String {
#[cfg(test)]
mod tests {
    use super::*;
    use crate::commands::assign_flag_ids;
    use std::collections::HashMap;

    const EXPECTED_FEATUREFLAGS_COMMON_CONTENT: &str = r#"
@@ -477,8 +493,15 @@ mod tests {
        let mode = CodegenMode::Production;
        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)
        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,
            false,
        )
        .unwrap();
        let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
            + r#"
@@ -647,8 +670,15 @@ mod tests {
        let mode = CodegenMode::Exported;
        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)
        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,
            false,
        )
        .unwrap();

        let expect_flags_content = r#"
@@ -833,8 +863,15 @@ mod tests {
        let mode = CodegenMode::Test;
        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)
        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,
            false,
        )
        .unwrap();

        let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
@@ -850,69 +887,58 @@ mod tests {
        "#;
        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
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean disabledRo() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean disabledRw() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean disabledRwExported() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean disabledRwInOtherNamespace() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean enabledFixedRo() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean enabledFixedRoExported() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean enabledRo() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean enabledRoExported() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
            }
            @Override
            @com.android.aconfig.annotations.AconfigFlagAccessor
            @UnsupportedAppUsage
            public boolean enabledRw() {
                throw new UnsupportedOperationException(
                    "Method is not implemented.");
@@ -958,8 +984,15 @@ mod tests {
        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)
        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,
            false,
        )
        .unwrap();
        let expect_featureflags_content = r#"
        package com.android.aconfig.test;
+13 −3
Original line number Diff line number Diff line
@@ -191,15 +191,25 @@ pub fn parse_flags(
    Ok(output)
}

pub fn create_java_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
pub fn create_java_lib(
    mut input: Input,
    codegen_mode: CodegenMode,
    allow_instrumentation: bool,
) -> Result<Vec<OutputFile>> {
    let parsed_flags = input.try_parse_flags()?;
    let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode)?;
    let Some(package) = find_unique_package(&modified_parsed_flags) else {
        bail!("no parsed flags, or the parsed flags use different packages");
    };
    let package = package.to_string();
    let _flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
    generate_java_code(&package, modified_parsed_flags.into_iter(), codegen_mode)
    let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
    generate_java_code(
        &package,
        modified_parsed_flags.into_iter(),
        codegen_mode,
        flag_ids,
        allow_instrumentation,
    )
}

pub fn create_cpp_lib(
+10 −2
Original line number Diff line number Diff line
@@ -72,6 +72,12 @@ fn cli() -> Command {
                        .long("mode")
                        .value_parser(EnumValueParser::<CodegenMode>::new())
                        .default_value("production"),
                )
                .arg(
                    Arg::new("allow-instrumentation")
                        .long("allow-instrumentation")
                        .value_parser(clap::value_parser!(bool))
                        .default_value("false"),
                ),
        )
        .subcommand(
@@ -237,8 +243,10 @@ fn main() -> Result<()> {
        Some(("create-java-lib", sub_matches)) => {
            let cache = open_single_file(sub_matches, "cache")?;
            let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
            let generated_files =
                commands::create_java_lib(cache, *mode).context("failed to create java lib")?;
            let allow_instrumentation =
                get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
            let generated_files = commands::create_java_lib(cache, *mode, *allow_instrumentation)
                .context("failed to create java lib")?;
            let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
            generated_files
                .iter()
+45 −3
Original line number Diff line number Diff line
package {package_name};
{{ -if not is_test_mode }}
{{ if not library_exported- }}
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
{{ -endif }}
{{ -if not is_test_mode }}

{{ -if runtime_lookup_required }}
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
{{ endif }}


{{ -if allow_instrumentation }}
import android.aconfig.storage.StorageInternalReader;
import android.util.Log;

import java.io.File;
{{ -endif }}

{{ -endif }}
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{
{{ -if runtime_lookup_required }}
@@ -20,14 +30,47 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
    private static boolean {flag.method_name} = {flag.default_value};
{{ -endif }}
{{ -endfor }}
{{ -if allow_instrumentation }}
    StorageInternalReader reader;
    boolean readFromNewStorage;

    private final static String TAG = "AconfigJavaCodegen";

    public FeatureFlagsImpl() \{
        File file = new File("/metadata/aconfig_test_missions/mission_1");
        if (file.exists()) \{
            readFromNewStorage = true;
            reader = new StorageInternalReader("{container}", "{package_name}");
        }
    }
{{ -endif }}
{{ for namespace_with_flags in namespace_flags }}
    private void load_overrides_{namespace_with_flags.namespace}() \{
        try \{
{{ -if allow_instrumentation }}
            boolean val;
{{ -endif }}
            Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
{{ -for flag in namespace_with_flags.flags }}
{{ -if flag.is_read_write }}
            {flag.method_name} =
                properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value});
{{ -if allow_instrumentation }}
            if (readFromNewStorage) \{
                try \{
                    val = reader.getBooleanFlagValue({flag.flag_offset});
                    if (val == {flag.method_name}) \{
                        Log.i(TAG, "success: {flag.method_name} value matches");
                    } else \{
                        Log.i(TAG, String.format(
                            "error: {flag.method_name} value mismatch, new storage value is %s, old storage value is %s",
                            val, {flag.method_name}));
                    }
                } catch (Exception e) \{
                    Log.e(TAG,"error: failed to read flag value of {flag.method_name}");
                }
            }
{{ -endif }}
{{ -endif }}
{{ -endfor }}
        } catch (NullPointerException e) \{
@@ -70,7 +113,6 @@ public final class FeatureFlagsImpl implements FeatureFlags \{
    @Override
{{ -if not library_exported }}
    @com.android.aconfig.annotations.AconfigFlagAccessor
    @UnsupportedAppUsage
{{ -endif }}
    public boolean {flag.method_name}() \{
        throw new UnsupportedOperationException(