Merge "Add brightness-related `TARGET_RECOVERY_UI_` properties"
diff --git a/core/Makefile b/core/Makefile
index a90ac89..649982d 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -412,7 +412,7 @@
unzip -qoDD -d $$(PRIVATE_MODULE_DIR) $$(PRIVATE_MODULE_ARCHIVE); \
mkdir -p $$(PRIVATE_OUTPUT_DIR)/lib; \
cp -r $(3)/$(DEPMOD_STAGING_SUBDIR)/$(2)/lib/modules $$(PRIVATE_OUTPUT_DIR)/lib/; \
- find $$(PRIVATE_MODULE_DIR) -type f -name *.ko | xargs basename -a > $$(PRIVATE_LOAD_FILE); \
+ find $$(PRIVATE_MODULE_DIR) -type f -name '*.ko' | xargs basename -a > $$(PRIVATE_LOAD_FILE); \
)
$(if $(1),\
cp $$(PRIVATE_MODULES) $$(PRIVATE_MODULE_DIR)/; \
diff --git a/core/main.mk b/core/main.mk
index 7b3584e..5a591f9 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -2157,10 +2157,12 @@
# See the second foreach loop in the rule of sbom-metadata.csv for the detailed info of static libraries collected in _all_static_libs.
# is_static_lib: whether the file is a static library
+metadata_list := $(OUT_DIR)/.module_paths/METADATA.list
+metadata_files := $(subst $(newline),$(space),$(file <$(metadata_list)))
# (TODO: b/272358583 find another way of always rebuilding this target)
# Remove the sbom-metadata.csv whenever makefile is evaluated
$(shell rm $(PRODUCT_OUT)/sbom-metadata.csv >/dev/null 2>&1)
-$(PRODUCT_OUT)/sbom-metadata.csv: $(installed_files)
+$(PRODUCT_OUT)/sbom-metadata.csv: $(installed_files) $(metadata_list) $(metadata_files)
rm -f $@
echo installed_file,module_path,soong_module_type,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,build_output_path,static_libraries,whole_static_libraries,is_static_lib >> $@
$(eval _all_static_libs :=)
@@ -2215,17 +2217,47 @@
$(call dist-for-goals,droid,$(PRODUCT_OUT)/sbom.spdx.json:sbom/sbom.spdx.json)
else
-apps_only_sbom_files := $(sort $(patsubst %,%.spdx.json,$(filter %.apk,$(apps_only_installed_files))))
-$(apps_only_sbom_files): $(PRODUCT_OUT)/sbom-metadata.csv $(GEN_SBOM)
- rm -rf $@
- $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --unbundled_apk
+# Create build rules for generating SBOMs of unbundled APKs and APEXs
+# $1: sbom file
+# $2: sbom fragment file
+# $3: installed file
+# $4: sbom-metadata.csv file
+define generate-app-sbom
+$(eval _path_on_device := $(patsubst $(PRODUCT_OUT)/%,%,$(3)))
+$(eval _module_name := $(ALL_INSTALLED_FILES.$(3)))
+$(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH))))
+$(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE))))
+$(eval _dep_modules := $(filter %.$(_module_name),$(ALL_MODULES)) $(filter %.$(_module_name)$(TARGET_2ND_ARCH_MODULE_SUFFIX),$(ALL_MODULES)))
+$(eval _is_apex := $(filter %.apex,$(3)))
+
+$(4): $(3) $(metadata_list) $(metadata_files)
+ rm -rf $$@
+ echo installed_file,module_path,soong_module_type,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,build_output_path,static_libraries,whole_static_libraries,is_static_lib >> $$@
+ echo /$(_path_on_device),$(_module_path),$(_soong_module_type),,,,,$(3),,, >> $$@
+ $(if $(filter %.apex,$(3)),\
+ $(foreach m,$(_dep_modules),\
+ echo $(patsubst $(PRODUCT_OUT)/apex/$(_module_name)/%,%,$(ALL_MODULES.$m.INSTALLED)),$(sort $(ALL_MODULES.$m.PATH)),$(sort $(ALL_MODULES.$m.SOONG_MODULE_TYPE)),,,,,$(strip $(ALL_MODULES.$m.BUILT)),,, >> $$@;))
+
+$(2): $(1)
+$(1): $(4) $(GEN_SBOM)
+ rm -rf $$@
+ $(GEN_SBOM) --output_file $$@ --metadata $(4) --build_version $$(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --json $(if $(filter %.apk,$(3)),--unbundled_apk,--unbundled_apex)
+endef
+
+apps_only_sbom_files :=
+apps_only_fragment_files :=
+$(foreach f,$(filter %.apk %.apex,$(installed_files)), \
+ $(eval _metadata_csv_file := $(patsubst %,%-sbom-metadata.csv,$f)) \
+ $(eval _sbom_file := $(patsubst %,%.spdx.json,$f)) \
+ $(eval _fragment_file := $(patsubst %,%-fragment.spdx,$f)) \
+ $(eval apps_only_sbom_files += $(_sbom_file)) \
+ $(eval apps_only_fragment_files += $(_fragment_file)) \
+ $(eval $(call generate-app-sbom,$(_sbom_file),$(_fragment_file),$f,$(_metadata_csv_file))) \
+)
sbom: $(apps_only_sbom_files)
-$(foreach f,$(apps_only_sbom_files),$(eval $(patsubst %.spdx.json,%-fragment.spdx,$f): $f))
-apps_only_fragment_files := $(patsubst %.spdx.json,%-fragment.spdx,$(apps_only_sbom_files))
$(foreach f,$(apps_only_fragment_files),$(eval apps_only_fragment_dist_files += :sbom/$(notdir $f)))
-
$(foreach f,$(apps_only_sbom_files),$(eval apps_only_sbom_dist_files += :sbom/$(notdir $f)))
$(call dist-for-goals,apps_only,$(join $(apps_only_sbom_files),$(apps_only_sbom_dist_files)) $(join $(apps_only_fragment_files),$(apps_only_fragment_dist_files)))
endif
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/envsetup.sh b/envsetup.sh
index d292dbb..f4755dd 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -62,8 +62,8 @@
invocations of 'm' etc.
- tapas: tapas [<App1> <App2> ...] [arm|x86|arm64|x86_64] [eng|userdebug|user]
Sets up the build environment for building unbundled apps (APKs).
-- banchan: banchan <module1> [<module2> ...] [arm|x86|arm64|x86_64|arm64_only|x86_64only] \
- [eng|userdebug|user]
+- banchan: banchan <module1> [<module2> ...] \
+ [arm|x86|arm64|riscv64|x86_64|arm64_only|x86_64only] [eng|userdebug|user]
Sets up the build environment for building unbundled modules (APEXes).
- croot: Changes directory to the top of the tree, or a subdirectory thereof.
- m: Makes from the top of the tree.
@@ -952,9 +952,9 @@
function banchan()
{
local showHelp="$(echo $* | xargs -n 1 echo | \grep -E '^(help)$' | xargs)"
- local product="$(echo $* | xargs -n 1 echo | \grep -E '^(.*_)?(arm|x86|arm64|x86_64|arm64only|x86_64only)$' | xargs)"
+ local product="$(echo $* | xargs -n 1 echo | \grep -E '^(.*_)?(arm|x86|arm64|riscv64|x86_64|arm64only|x86_64only)$' | xargs)"
local variant="$(echo $* | xargs -n 1 echo | \grep -E '^(user|userdebug|eng)$' | xargs)"
- local apps="$(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|(.*_)?(arm|x86|arm64|x86_64))$' | xargs)"
+ local apps="$(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|(.*_)?(arm|x86|arm64|riscv64|x86_64))$' | xargs)"
if [ "$showHelp" != "" ]; then
$(gettop)/build/make/banchanHelp.sh
@@ -980,6 +980,7 @@
arm) product=module_arm;;
x86) product=module_x86;;
arm64) product=module_arm64;;
+ riscv64) product=module_riscv64;;
x86_64) product=module_x86_64;;
arm64only) product=module_arm64only;;
x86_64only) product=module_x86_64only;;
diff --git a/target/board/module_riscv64/BoardConfig.mk b/target/board/module_riscv64/BoardConfig.mk
new file mode 100644
index 0000000..8bc1999
--- /dev/null
+++ b/target/board/module_riscv64/BoardConfig.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+TARGET_ARCH := riscv64
+TARGET_ARCH_VARIANT :=
+TARGET_CPU_VARIANT := generic
+TARGET_CPU_ABI := riscv64
+
+# Temporary hack while prebuilt modules are missing riscv64.
+ALLOW_MISSING_DEPENDENCIES := true
diff --git a/target/board/module_riscv64/README.md b/target/board/module_riscv64/README.md
new file mode 100644
index 0000000..edebaa9
--- /dev/null
+++ b/target/board/module_riscv64/README.md
@@ -0,0 +1,2 @@
+This device is suitable for an unbundled module targeted specifically to a
+riscv64 device. This is a 64-bit only device (no 32-bit support).
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 133dc73..473a275 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -83,6 +83,7 @@
$(LOCAL_DIR)/module_arm.mk \
$(LOCAL_DIR)/module_arm64.mk \
$(LOCAL_DIR)/module_arm64only.mk \
+ $(LOCAL_DIR)/module_riscv64.mk \
$(LOCAL_DIR)/module_x86.mk \
$(LOCAL_DIR)/module_x86_64.mk \
$(LOCAL_DIR)/module_x86_64only.mk \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index a23fdd5..7fc33b0 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -70,6 +70,7 @@
com.android.scheduling \
com.android.sdkext \
com.android.tethering \
+ com.android.threadnetwork \
com.android.tzdata \
com.android.uwb \
com.android.virt \
diff --git a/target/product/cfi-common.mk b/target/product/cfi-common.mk
index 559963c..5cc7ae5 100644
--- a/target/product/cfi-common.mk
+++ b/target/product/cfi-common.mk
@@ -33,7 +33,7 @@
hardware/qcom/wlan/wcn6740/qcwcn/wpa_supplicant_8_lib \
hardware/interfaces/keymaster \
hardware/interfaces/security \
- packages/modules/Bluetooth/system \
+ packages/modules/Bluetooth \
system/chre \
system/core/libnetutils \
system/libziparchive \
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 375b7cb..e39af92 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -80,3 +80,6 @@
# Additional settings used in all GSI builds
PRODUCT_PRODUCT_PROPERTIES += \
ro.crypto.metadata_init_delete_all_keys.enabled=false \
+
+# Window Extensions
+$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)
\ No newline at end of file
diff --git a/target/product/module_riscv64.mk b/target/product/module_riscv64.mk
new file mode 100644
index 0000000..4fd38c0
--- /dev/null
+++ b/target/product/module_riscv64.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/module_common.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+
+PRODUCT_NAME := module_riscv64
+PRODUCT_DEVICE := module_riscv64
diff --git a/tests/b_tests.sh b/tests/b_tests.sh
index 491d762..68a13e3 100755
--- a/tests/b_tests.sh
+++ b/tests/b_tests.sh
@@ -23,6 +23,10 @@
test_target=//build/bazel/scripts/difftool:difftool
+if b build //build/bazel:nonexistent_module &>/dev/null ; then
+ echo "b did not fail when building a nonexistent module" >&2
+ exit 1
+fi
b build "$test_target"
b build -- "$test_target"
b build "$test_target" --run-soong-tests
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 5b7234e..c349907 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -2,6 +2,28 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+// proto libraries for consumers of `aconfig dump --format=protobuf` output
+
+java_library {
+ name: "libaconfig_java_proto_lite",
+ host_supported: true,
+ srcs: ["protos/aconfig.proto"],
+ static_libs: ["libprotobuf-java-lite"],
+ proto: {
+ type: "lite",
+ },
+ sdk_version: "current",
+}
+
+java_library_host {
+ name: "libaconfig_java_proto_full",
+ srcs: ["protos/aconfig.proto"],
+ static_libs: ["libprotobuf-java-full"],
+ proto: {
+ type: "full",
+ },
+}
+
// host binary: aconfig
rust_protobuf_host {
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
new file mode 100644
index 0000000..86124dd
--- /dev/null
+++ b/tools/aconfig/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ // Ensure changes on aconfig auto generated library is compatible with
+ // test testing filtering logic. Breakage on this test means all tests
+ // that using the flag annotations to do filtering will get affected.
+ "name": "FlagAnnotationTests",
+ "options": [
+ {
+ "include-filter": "android.cts.flags.tests.FlagAnnotationTest"
+ }
+ ]
+ }
+ ]
+}
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/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 15eb2d6..8ab6ffa 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -233,8 +233,9 @@
let expected_featureflagsimpl_content = r#"
package com.android.aconfig.test;
import static java.util.stream.Collectors.toMap;
- import java.util.stream.Stream;
import java.util.HashMap;
+ import java.util.Map;
+ import java.util.stream.Stream;
public final class FeatureFlagsImpl implements FeatureFlags {
@Override
public boolean disabledRo() {
@@ -258,6 +259,11 @@
}
this.mFlagMap.put(flagName, value);
}
+ public void resetAll() {
+ for (Map.Entry entry : mFlagMap.entrySet()) {
+ entry.setValue(null);
+ }
+ }
private boolean getFlag(String flagName) {
Boolean value = this.mFlagMap.get(flagName);
if (value == null) {
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/FeatureFlags.java.template b/tools/aconfig/templates/FeatureFlags.java.template
index b9e2cc7..e0f201f 100644
--- a/tools/aconfig/templates/FeatureFlags.java.template
+++ b/tools/aconfig/templates/FeatureFlags.java.template
@@ -1,7 +1,7 @@
package {package_name};
public interface FeatureFlags \{
- {{ for item in class_elements}}
+{{ for item in class_elements}}
boolean {item.method_name}();
- {{ endfor }}
-}
\ No newline at end of file
+{{ endfor }}
+}
diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
index dafd99e..082d476 100644
--- a/tools/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -2,15 +2,16 @@
{{ -if is_test_mode }}
import static java.util.stream.Collectors.toMap;
-import java.util.stream.Stream;
import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
{{ else}}
{{ if is_read_write- }}
import android.provider.DeviceConfig;
{{ -endif- }}
{{ endif }}
public final class FeatureFlagsImpl implements FeatureFlags \{
- {{ for item in class_elements}}
+{{ for item in class_elements}}
@Override
public boolean {item.method_name}() \{
{{ -if not is_test_mode- }}
@@ -20,16 +21,15 @@
"{item.device_config_flag}",
{item.default_value}
);
- {{ else }}
+ {{ -else }}
return {item.default_value};
{{ -endif- }}
{{ else }}
return getFlag(Flags.FLAG_{item.flag_name_constant_suffix});
{{ -endif }}
}
- {{ endfor }}
-
- {{ if is_test_mode- }}
+{{ endfor- }}
+{{ if is_test_mode }}
public void setFlag(String flagName, boolean value) \{
if (!this.mFlagMap.containsKey(flagName)) \{
throw new IllegalArgumentException("no such flag" + flagName);
@@ -37,6 +37,12 @@
this.mFlagMap.put(flagName, value);
}
+ public void resetAll() \{
+ for (Map.Entry entry : mFlagMap.entrySet()) \{
+ entry.setValue(null);
+ }
+ }
+
private boolean getFlag(String flagName) \{
Boolean value = this.mFlagMap.get(flagName);
if (value == null) \{
@@ -55,7 +61,5 @@
(map, elem) -> map.put(elem, null),
HashMap::putAll
);
- {{ -endif }}
+{{ -endif }}
}
-
-
diff --git a/tools/aconfig/templates/Flags.java.template b/tools/aconfig/templates/Flags.java.template
index eef98eb..c244b15 100644
--- a/tools/aconfig/templates/Flags.java.template
+++ b/tools/aconfig/templates/Flags.java.template
@@ -1,15 +1,15 @@
package {package_name};
public final class Flags \{
- {{- for item in class_elements}}
+{{- for item in class_elements}}
public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}";
- {{- endfor }}
- {{ for item in class_elements}}
+{{- endfor }}
+{{ for item in class_elements}}
public static boolean {item.method_name}() \{
return FEATURE_FLAGS.{item.method_name}();
}
- {{ endfor }}
- {{ if is_test_mode }}
+{{ endfor }}
+{{ -if is_test_mode }}
public static void setFeatureFlagsImpl(FeatureFlags featureFlags) \{
Flags.FEATURE_FLAGS = featureFlags;
}
@@ -17,8 +17,7 @@
public static void unsetFeatureFlagsImpl() \{
Flags.FEATURE_FLAGS = null;
}
- {{ -endif}}
-
+{{ endif}}
private static FeatureFlags FEATURE_FLAGS{{ -if not is_test_mode }} = new FeatureFlagsImpl(){{ -endif- }};
}
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
diff --git a/tools/list_files.py b/tools/list_files.py
index 3afa81f..4f666aa 100644
--- a/tools/list_files.py
+++ b/tools/list_files.py
@@ -18,6 +18,7 @@
from glob import glob
from pathlib import Path
from os.path import join, relpath
+from itertools import chain
import argparse
class FileLister:
@@ -27,7 +28,8 @@
self.folder_dir = args.dir
self.extensions = [e if e.startswith(".") else "." + e for e in args.extensions]
self.root = args.root
- self.files_list = list()
+ self.files_list : List[str] = list()
+ self.classes = args.classes
def get_files(self) -> None:
"""Get all files directory in the input directory including the files in the subdirectories
@@ -61,6 +63,26 @@
def list(self) -> None:
self.get_files()
self.files_list = [f for f in self.files_list if not self.extensions or Path(f).suffix in self.extensions]
+
+ # If files_list is as below:
+ # A/B/C.java
+ # A/B/D.java
+ # A/B/E.txt
+ # --classes flag converts files_list in the following format:
+ # A/B/C.class
+ # A/B/C$*.class
+ # A/B/D.class
+ # A/B/D$*.class
+ # Additional `$*`-suffixed line is appended after each line
+ # to take multiple top level classes in a single java file into account.
+ # Note that non-java files in files_list are filtered out.
+ if self.classes:
+ self.files_list = list(chain.from_iterable([
+ (class_files := str(Path(ff).with_suffix(".class")),
+ class_files.replace(".class", "$*.class"))
+ for ff in self.files_list if ff.endswith(".java")
+ ]))
+
self.write()
def write(self) -> None:
@@ -95,6 +117,10 @@
help="optional directory to replace the root directories of output.")
parser.add_argument('--extensions', nargs='*', default=list(), dest='extensions',
help="Extensions to include in the output. If not set, all files are included")
+ parser.add_argument('--classes', dest='classes', action=argparse.BooleanOptionalAction,
+ help="Optional flag. If passed, outputs a list of pattern of class files \
+ that will be produced by compiling java files in the input dir. \
+ Non-java files in the input directory will be ignored.")
args = parser.parse_args()