Merge "Change java codegen to read from new storage" into main am: bce58b3c94
Original change: https://android-review.googlesource.com/c/platform/build/+/3174140 Change-Id: Ib7fe640a084f692bb10c00ddb49f781dc8947c08 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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(
|
||||
@@ -243,8 +249,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