Change java codegen to read from new storage
This change adds code in java code to read from new storage. However the
generated code won't geneerate code contains code for new storage, since
the build system won't pass `allow-instrumentation` to java codegen.
Test: atest aconfig.test.java
Bug: 349874828
Change-Id: I70983fa97de6633f467d968109d134d46f895a89
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index d3f074a..ec22ebc 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -20,22 +20,24 @@
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 @@
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 @@
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 @@
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 @@
#[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 @@
#[cfg(test)]
mod tests {
use super::*;
+ use crate::commands::assign_flag_ids;
use std::collections::HashMap;
const EXPECTED_FEATUREFLAGS_COMMON_CONTENT: &str = r#"
@@ -477,9 +493,16 @@
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)
- .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,
+ false,
+ )
+ .unwrap();
let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
+ r#"
private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
@@ -647,9 +670,16 @@
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)
- .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,
+ false,
+ )
+ .unwrap();
let expect_flags_content = r#"
package com.android.aconfig.test;
@@ -833,9 +863,16 @@
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)
- .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,
+ false,
+ )
+ .unwrap();
let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
+ r#"
@@ -850,69 +887,58 @@
"#;
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,9 +984,16 @@
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 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;
// TODO(b/303773055): Remove the annotation after access issue is resolved.
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 6945fd4..6d1c2f5 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -191,15 +191,25 @@
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(
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index 72be1c9..7ec272f 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -72,6 +72,12 @@
.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 @@
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()
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index 63c4f2d..cd2e3db 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,13 +1,23 @@
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 @@
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 @@
@Override
{{ -if not library_exported }}
@com.android.aconfig.annotations.AconfigFlagAccessor
- @UnsupportedAppUsage
{{ -endif }}
public boolean {flag.method_name}() \{
throw new UnsupportedOperationException(