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
This commit is contained in:
@@ -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,9 +493,16 @@ 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)
|
||||
.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 @@ 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)
|
||||
.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 @@ 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)
|
||||
.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 @@ 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,9 +984,16 @@ 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)
|
||||
.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.
|
||||
|
@@ -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(
|
||||
|
@@ -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()
|
||||
|
@@ -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 @@ 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(
|
||||
|
Reference in New Issue
Block a user