Merge "Quote pattern in 'find' command used to generate modules.load"
diff --git a/core/tasks/tools/compatibility.mk b/core/tasks/tools/compatibility.mk
index dd2305e..4e78d89 100644
--- a/core/tasks/tools/compatibility.mk
+++ b/core/tasks/tools/compatibility.mk
@@ -36,6 +36,7 @@
$(HOST_OUT_JAVA_LIBRARIES)/$(test_suite_tradefed).jar \
$(HOST_OUT_JAVA_LIBRARIES)/$(test_suite_tradefed)-tests.jar \
$(HOST_OUT_EXECUTABLES)/$(test_suite_tradefed) \
+ $(HOST_OUT_EXECUTABLES)/test-utils-script \
$(test_suite_readme)
$(foreach f,$(test_suite_readme),$(if $(strip $(ALL_TARGETS.$(f).META_LIC)),,$(eval ALL_TARGETS.$(f).META_LIC := $(module_license_metadata))))
diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs
index 2944e8a..a802725 100644
--- a/tools/aconfig/src/codegen_cpp.rs
+++ b/tools/aconfig/src/codegen_cpp.rs
@@ -16,13 +16,18 @@
use anyhow::{ensure, Result};
use serde::Serialize;
+use std::path::PathBuf;
use tinytemplate::TinyTemplate;
use crate::codegen;
-use crate::commands::OutputFile;
+use crate::commands::{CodegenMode, OutputFile};
use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
-pub fn generate_cpp_code<'a, I>(package: &str, parsed_flags_iter: I) -> Result<OutputFile>
+pub fn generate_cpp_code<'a, I>(
+ package: &str,
+ parsed_flags_iter: I,
+ codegen_mode: CodegenMode,
+) -> Result<Vec<OutputFile>>
where
I: Iterator<Item = &'a ProtoParsedFlag>,
{
@@ -37,29 +42,66 @@
cpp_namespace,
package: package.to_string(),
readwrite,
+ for_prod: codegen_mode == CodegenMode::Production,
class_elements,
};
+
+ let files = [
+ FileSpec {
+ name: &format!("{}.h", header),
+ template: include_str!("../templates/cpp_exported_header.template"),
+ dir: "include",
+ },
+ FileSpec {
+ name: &format!("{}.cc", header),
+ template: include_str!("../templates/cpp_source_file.template"),
+ dir: "",
+ },
+ FileSpec {
+ name: &format!("{}_flag_provider.h", header),
+ template: match codegen_mode {
+ CodegenMode::Production => {
+ include_str!("../templates/cpp_prod_flag_provider.template")
+ }
+ CodegenMode::Test => include_str!("../templates/cpp_test_flag_provider.template"),
+ },
+ dir: "",
+ },
+ ];
+ files.iter().map(|file| generate_file(file, &context)).collect()
+}
+
+pub fn generate_file(file: &FileSpec, context: &Context) -> Result<OutputFile> {
let mut template = TinyTemplate::new();
- template.add_template("cpp_code_gen", include_str!("../templates/cpp.template"))?;
- let contents = template.render("cpp_code_gen", &context)?;
- let path = ["aconfig", &(header + ".h")].iter().collect();
+ template.add_template(file.name, file.template)?;
+ let contents = template.render(file.name, &context)?;
+ let path: PathBuf = [&file.dir, &file.name].iter().collect();
Ok(OutputFile { contents: contents.into(), path })
}
#[derive(Serialize)]
-struct Context {
+pub struct FileSpec<'a> {
+ pub name: &'a str,
+ pub template: &'a str,
+ pub dir: &'a str,
+}
+
+#[derive(Serialize)]
+pub struct Context {
pub header: String,
pub cpp_namespace: String,
pub package: String,
pub readwrite: bool,
+ pub for_prod: bool,
pub class_elements: Vec<ClassElement>,
}
#[derive(Serialize)]
-struct ClassElement {
+pub struct ClassElement {
pub readwrite: bool,
pub default_value: String,
pub flag_name: String,
+ pub uppercase_flag_name: String,
pub device_config_namespace: String,
pub device_config_flag: String,
}
@@ -73,6 +115,7 @@
"false".to_string()
},
flag_name: pf.name().to_string(),
+ uppercase_flag_name: pf.name().to_string().to_ascii_uppercase(),
device_config_namespace: pf.namespace().to_string(),
device_config_flag: codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time"),
@@ -82,51 +125,325 @@
#[cfg(test)]
mod tests {
use super::*;
+ use std::collections::HashMap;
- #[test]
- fn test_generate_cpp_code() {
- let parsed_flags = crate::test::parse_test_flags();
- let generated =
- generate_cpp_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter()).unwrap();
- assert_eq!("aconfig/com_android_aconfig_test.h", format!("{}", generated.path.display()));
- let expected = r#"
+ const EXPORTED_PROD_HEADER_EXPECTED: &str = r#"
#ifndef com_android_aconfig_test_HEADER_H
#define com_android_aconfig_test_HEADER_H
-#include <server_configurable_flags/get_flags.h>
+#include <string>
+#include <memory>
+#include <server_configurable_flags/get_flags.h>
using namespace server_configurable_flags;
namespace com::android::aconfig::test {
- static const bool disabled_ro() {
+class flag_provider_interface {
+public:
+
+ virtual ~flag_provider_interface() = default;
+
+ virtual bool disabled_ro() = 0;
+
+ virtual bool disabled_rw() = 0;
+
+ virtual bool enabled_ro() = 0;
+
+ virtual bool enabled_rw() = 0;
+
+ virtual void override_flag(std::string const&, bool) {}
+
+ virtual void reset_overrides() {}
+};
+
+extern std::unique_ptr<flag_provider_interface> provider_;
+
+extern std::string const DISABLED_RO;
+extern std::string const DISABLED_RW;
+extern std::string const ENABLED_RO;
+extern std::string const ENABLED_RW;
+
+inline bool disabled_ro() {
+ return false;
+}
+
+inline bool disabled_rw() {
+ return provider_->disabled_rw();
+}
+
+inline bool enabled_ro() {
+ return true;
+}
+
+inline bool enabled_rw() {
+ return provider_->enabled_rw();
+}
+
+inline void override_flag(std::string const& name, bool val) {
+ return provider_->override_flag(name, val);
+}
+
+inline void reset_overrides() {
+ return provider_->reset_overrides();
+}
+
+}
+#endif
+"#;
+
+ const EXPORTED_TEST_HEADER_EXPECTED: &str = r#"
+#ifndef com_android_aconfig_test_HEADER_H
+#define com_android_aconfig_test_HEADER_H
+
+#include <string>
+#include <memory>
+#include <server_configurable_flags/get_flags.h>
+using namespace server_configurable_flags;
+
+namespace com::android::aconfig::test {
+class flag_provider_interface {
+public:
+
+ virtual ~flag_provider_interface() = default;
+
+ virtual bool disabled_ro() = 0;
+
+ virtual bool disabled_rw() = 0;
+
+ virtual bool enabled_ro() = 0;
+
+ virtual bool enabled_rw() = 0;
+
+ virtual void override_flag(std::string const&, bool) {}
+
+ virtual void reset_overrides() {}
+};
+
+extern std::unique_ptr<flag_provider_interface> provider_;
+
+extern std::string const DISABLED_RO;
+extern std::string const DISABLED_RW;
+extern std::string const ENABLED_RO;
+extern std::string const ENABLED_RW;
+
+inline bool disabled_ro() {
+ return provider_->disabled_ro();
+}
+
+inline bool disabled_rw() {
+ return provider_->disabled_rw();
+}
+
+inline bool enabled_ro() {
+ return provider_->enabled_ro();
+}
+
+inline bool enabled_rw() {
+ return provider_->enabled_rw();
+}
+
+inline void override_flag(std::string const& name, bool val) {
+ return provider_->override_flag(name, val);
+}
+
+inline void reset_overrides() {
+ return provider_->reset_overrides();
+}
+
+}
+#endif
+"#;
+
+ const PROD_FLAG_PROVIDER_HEADER_EXPECTED: &str = r#"
+#ifndef com_android_aconfig_test_flag_provider_HEADER_H
+#define com_android_aconfig_test_flag_provider_HEADER_H
+
+#include "com_android_aconfig_test.h"
+
+namespace com::android::aconfig::test {
+class flag_provider : public flag_provider_interface {
+public:
+
+ virtual bool disabled_ro() override {
return false;
}
- static const bool disabled_rw() {
+ virtual bool disabled_rw() override {
return GetServerConfigurableFlag(
"aconfig_test",
"com.android.aconfig.test.disabled_rw",
"false") == "true";
}
- static const bool enabled_ro() {
+ virtual bool enabled_ro() override {
return true;
}
- static const bool enabled_rw() {
+ virtual bool enabled_rw() override {
return GetServerConfigurableFlag(
"aconfig_test",
"com.android.aconfig.test.enabled_rw",
"true") == "true";
}
+};
}
#endif
"#;
+
+ const TEST_FLAG_PROVIDER_HEADER_EXPECTED: &str = r#"
+#ifndef com_android_aconfig_test_flag_provider_HEADER_H
+#define com_android_aconfig_test_flag_provider_HEADER_H
+
+#include "com_android_aconfig_test.h"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <cassert>
+
+namespace com::android::aconfig::test {
+class flag_provider : public flag_provider_interface {
+private:
+ std::unordered_map<std::string, bool> overrides_;
+ std::unordered_set<std::string> flag_names_;
+
+public:
+
+ flag_provider()
+ : overrides_(),
+ flag_names_() {
+ flag_names_.insert(DISABLED_RO);
+ flag_names_.insert(DISABLED_RW);
+ flag_names_.insert(ENABLED_RO);
+ flag_names_.insert(ENABLED_RW);
+ }
+
+ virtual bool disabled_ro() override {
+ auto it = overrides_.find(DISABLED_RO);
+ if (it != overrides_.end()) {
+ return it->second;
+ } else {
+ return false;
+ }
+ }
+
+ virtual bool disabled_rw() override {
+ auto it = overrides_.find(DISABLED_RW);
+ if (it != overrides_.end()) {
+ return it->second;
+ } else {
+ return GetServerConfigurableFlag(
+ "aconfig_test",
+ "com.android.aconfig.test.disabled_rw",
+ "false") == "true";
+ }
+ }
+
+ virtual bool enabled_ro() override {
+ auto it = overrides_.find(ENABLED_RO);
+ if (it != overrides_.end()) {
+ return it->second;
+ } else {
+ return true;
+ }
+ }
+
+ virtual bool enabled_rw() override {
+ auto it = overrides_.find(ENABLED_RW);
+ if (it != overrides_.end()) {
+ return it->second;
+ } else {
+ return GetServerConfigurableFlag(
+ "aconfig_test",
+ "com.android.aconfig.test.enabled_rw",
+ "true") == "true";
+ }
+ }
+
+ virtual void override_flag(std::string const& flag, bool val) override {
+ assert(flag_names_.count(flag));
+ overrides_[flag] = val;
+ }
+
+ virtual void reset_overrides() override {
+ overrides_.clear();
+ }
+};
+}
+#endif
+"#;
+
+ const SOURCE_FILE_EXPECTED: &str = r#"
+#include "com_android_aconfig_test.h"
+#include "com_android_aconfig_test_flag_provider.h"
+
+namespace com::android::aconfig::test {
+
+ std::string const DISABLED_RO = "com.android.aconfig.test.disabled_ro";
+ std::string const DISABLED_RW = "com.android.aconfig.test.disabled_rw";
+ std::string const ENABLED_RO = "com.android.aconfig.test.enabled_ro";
+ std::string const ENABLED_RW = "com.android.aconfig.test.enabled_rw";
+
+ std::unique_ptr<flag_provider_interface> provider_ =
+ std::make_unique<flag_provider>();
+}
+"#;
+
+ fn test_generate_cpp_code(mode: CodegenMode) {
+ let parsed_flags = crate::test::parse_test_flags();
+ let generated =
+ generate_cpp_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter(), mode)
+ .unwrap();
+ let mut generated_files_map = HashMap::new();
+ for file in generated {
+ generated_files_map.insert(
+ String::from(file.path.to_str().unwrap()),
+ String::from_utf8(file.contents.clone()).unwrap(),
+ );
+ }
+
+ let mut target_file_path = String::from("include/com_android_aconfig_test.h");
+ assert!(generated_files_map.contains_key(&target_file_path));
assert_eq!(
None,
crate::test::first_significant_code_diff(
- expected,
- &String::from_utf8(generated.contents).unwrap()
+ match mode {
+ CodegenMode::Production => EXPORTED_PROD_HEADER_EXPECTED,
+ CodegenMode::Test => EXPORTED_TEST_HEADER_EXPECTED,
+ },
+ generated_files_map.get(&target_file_path).unwrap()
)
);
+
+ target_file_path = String::from("com_android_aconfig_test_flag_provider.h");
+ assert!(generated_files_map.contains_key(&target_file_path));
+ assert_eq!(
+ None,
+ crate::test::first_significant_code_diff(
+ match mode {
+ CodegenMode::Production => PROD_FLAG_PROVIDER_HEADER_EXPECTED,
+ CodegenMode::Test => TEST_FLAG_PROVIDER_HEADER_EXPECTED,
+ },
+ generated_files_map.get(&target_file_path).unwrap()
+ )
+ );
+
+ target_file_path = String::from("com_android_aconfig_test.cc");
+ assert!(generated_files_map.contains_key(&target_file_path));
+ assert_eq!(
+ None,
+ crate::test::first_significant_code_diff(
+ SOURCE_FILE_EXPECTED,
+ generated_files_map.get(&target_file_path).unwrap()
+ )
+ );
+ }
+
+ #[test]
+ fn test_generate_cpp_code_for_prod() {
+ test_generate_cpp_code(CodegenMode::Production);
+ }
+
+ #[test]
+ fn test_generate_cpp_code_for_test() {
+ test_generate_cpp_code(CodegenMode::Test);
}
}
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index dd2087b..687f319 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -143,12 +143,12 @@
generate_java_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
}
-pub fn create_cpp_lib(mut input: Input) -> Result<OutputFile> {
+pub fn create_cpp_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
let parsed_flags = input.try_parse_flags()?;
let Some(package) = find_unique_package(&parsed_flags) else {
bail!("no parsed flags, or the parsed flags use different packages");
};
- generate_cpp_code(package, parsed_flags.parsed_flag.iter())
+ generate_cpp_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
}
pub fn create_rust_lib(mut input: Input) -> Result<OutputFile> {
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index e20c60c..72feb94 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -60,7 +60,13 @@
.subcommand(
Command::new("create-cpp-lib")
.arg(Arg::new("cache").long("cache").required(true))
- .arg(Arg::new("out").long("out").required(true)),
+ .arg(Arg::new("out").long("out").required(true))
+ .arg(
+ Arg::new("mode")
+ .long("mode")
+ .value_parser(EnumValueParser::<commands::CodegenMode>::new())
+ .default_value("production"),
+ ),
)
.subcommand(
Command::new("create-rust-lib")
@@ -163,9 +169,12 @@
}
Some(("create-cpp-lib", sub_matches)) => {
let cache = open_single_file(sub_matches, "cache")?;
- let generated_file = commands::create_cpp_lib(cache)?;
+ let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
+ let generated_files = commands::create_cpp_lib(cache, *mode)?;
let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
- write_output_file_realtive_to_dir(&dir, &generated_file)?;
+ generated_files
+ .iter()
+ .try_for_each(|file| write_output_file_realtive_to_dir(&dir, file))?;
}
Some(("create-rust-lib", sub_matches)) => {
let cache = open_single_file(sub_matches, "cache")?;
diff --git a/tools/aconfig/templates/cpp_exported_header.template b/tools/aconfig/templates/cpp_exported_header.template
new file mode 100644
index 0000000..e244de3
--- /dev/null
+++ b/tools/aconfig/templates/cpp_exported_header.template
@@ -0,0 +1,48 @@
+#ifndef {header}_HEADER_H
+#define {header}_HEADER_H
+
+#include <string>
+#include <memory>
+{{ if readwrite }}
+#include <server_configurable_flags/get_flags.h>
+using namespace server_configurable_flags;
+{{ endif }}
+namespace {cpp_namespace} \{
+
+class flag_provider_interface \{
+public:
+ virtual ~flag_provider_interface() = default;
+ {{ for item in class_elements}}
+ virtual bool {item.flag_name}() = 0;
+ {{ endfor }}
+ virtual void override_flag(std::string const&, bool) \{}
+
+ virtual void reset_overrides() \{}
+};
+
+extern std::unique_ptr<flag_provider_interface> provider_;
+{{ for item in class_elements}}
+extern std::string const {item.uppercase_flag_name};{{ endfor }}
+{{ for item in class_elements}}
+inline bool {item.flag_name}() \{
+ {{ if for_prod }}
+ {{ if not item.readwrite- }}
+ return {item.default_value};
+ {{ -else- }}
+ return provider_->{item.flag_name}();
+ {{ -endif }}
+ {{ -else- }}
+ return provider_->{item.flag_name}();
+ {{ -endif }}
+}
+{{ endfor }}
+inline void override_flag(std::string const& name, bool val) \{
+ return provider_->override_flag(name, val);
+}
+
+inline void reset_overrides() \{
+ return provider_->reset_overrides();
+}
+
+}
+#endif
diff --git a/tools/aconfig/templates/cpp.template b/tools/aconfig/templates/cpp_prod_flag_provider.template
similarity index 63%
rename from tools/aconfig/templates/cpp.template
rename to tools/aconfig/templates/cpp_prod_flag_provider.template
index aa36d94..c966ed4 100644
--- a/tools/aconfig/templates/cpp.template
+++ b/tools/aconfig/templates/cpp_prod_flag_provider.template
@@ -1,12 +1,12 @@
-#ifndef {header}_HEADER_H
-#define {header}_HEADER_H
-{{ if readwrite }}
-#include <server_configurable_flags/get_flags.h>
-using namespace server_configurable_flags;
-{{ endif }}
+#ifndef {header}_flag_provider_HEADER_H
+#define {header}_flag_provider_HEADER_H
+#include "{header}.h"
+
namespace {cpp_namespace} \{
+class flag_provider : public flag_provider_interface \{
+public:
{{ for item in class_elements}}
- static const bool {item.flag_name}() \{
+ virtual bool {item.flag_name}() override \{
{{ if item.readwrite- }}
return GetServerConfigurableFlag(
"{item.device_config_namespace}",
@@ -17,5 +17,6 @@
{{ -endif }}
}
{{ endfor }}
+};
}
#endif
diff --git a/tools/aconfig/templates/cpp_source_file.template b/tools/aconfig/templates/cpp_source_file.template
new file mode 100644
index 0000000..1b4f336
--- /dev/null
+++ b/tools/aconfig/templates/cpp_source_file.template
@@ -0,0 +1,10 @@
+
+#include "{header}.h"
+#include "{header}_flag_provider.h"
+
+namespace {cpp_namespace} \{
+{{ for item in class_elements}}
+std::string const {item.uppercase_flag_name} = "{item.device_config_flag}";{{ endfor }}
+std::unique_ptr<flag_provider_interface> provider_ =
+ std::make_unique<flag_provider>();
+}
diff --git a/tools/aconfig/templates/cpp_test_flag_provider.template b/tools/aconfig/templates/cpp_test_flag_provider.template
new file mode 100644
index 0000000..bd597e7
--- /dev/null
+++ b/tools/aconfig/templates/cpp_test_flag_provider.template
@@ -0,0 +1,49 @@
+#ifndef {header}_flag_provider_HEADER_H
+#define {header}_flag_provider_HEADER_H
+#include "{header}.h"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <cassert>
+
+namespace {cpp_namespace} \{
+class flag_provider : public flag_provider_interface \{
+private:
+ std::unordered_map<std::string, bool> overrides_;
+ std::unordered_set<std::string> flag_names_;
+
+public:
+ flag_provider()
+ : overrides_(),
+ flag_names_() \{
+ {{ for item in class_elements}}
+ flag_names_.insert({item.uppercase_flag_name});{{ endfor }}
+ }
+ {{ for item in class_elements}}
+ virtual bool {item.flag_name}() override \{
+ auto it = overrides_.find({item.uppercase_flag_name});
+ if (it != overrides_.end()) \{
+ return it->second;
+ } else \{
+ {{ if item.readwrite- }}
+ return GetServerConfigurableFlag(
+ "{item.device_config_namespace}",
+ "{item.device_config_flag}",
+ "{item.default_value}") == "true";
+ {{ -else- }}
+ return {item.default_value};
+ {{ -endif }}
+ }
+ }
+ {{ endfor }}
+ virtual void override_flag(std::string const& flag, bool val) override \{
+ assert(flag_names_.count(flag));
+ overrides_[flag] = val;
+ }
+
+ virtual void reset_overrides() override \{
+ overrides_.clear();
+ }
+};
+}
+#endif