Merge "Use per-app package list to avoid unnecessary dexpreopt."
diff --git a/core/Makefile b/core/Makefile
index 6dbbef1..00ab3f8 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -4827,25 +4827,24 @@
intermediates := $(call intermediates-dir-for,PACKAGING,check_vintf_all)
check_vintf_all_deps :=
-APEX_OUT := $(PRODUCT_OUT)/apex
# -----------------------------------------------------------------
-# Create apex-info-file.xml
+# Activate vendor APEXes for checkvintf
apex_dirs := \
- $(TARGET_OUT)/apex/% \
- $(TARGET_OUT_SYSTEM_EXT)/apex/% \
$(TARGET_OUT_VENDOR)/apex/% \
- $(TARGET_OUT_ODM)/apex/% \
- $(TARGET_OUT_PRODUCT)/apex/% \
apex_files := $(sort $(filter $(apex_dirs), $(INTERNAL_ALLIMAGES_FILES)))
+
+APEX_OUT := $(intermediates)/apex
APEX_INFO_FILE := $(APEX_OUT)/apex-info-list.xml
-# dump_apex_info scans $(PRODUCT_OUT)/apex and writes apex-info-list.xml there.
-# This relies on the fact that rules for .apex files install the contents in $(PRODUCT_OUT)/apex.
-$(APEX_INFO_FILE): $(HOST_OUT_EXECUTABLES)/dump_apex_info $(apex_files)
- @echo "Creating apex-info-file in $(PRODUCT_OUT) "
- $< --root_dir $(PRODUCT_OUT)
+# apexd_host scans/activates APEX files and writes /apex/apex-info-list.xml
+$(APEX_INFO_FILE): $(HOST_OUT_EXECUTABLES)/apexd_host $(apex_files)
+ @echo "Extracting apexes..."
+ @rm -rf $(APEX_OUT)
+ @mkdir -p $(APEX_OUT)
+ $< --vendor_path $(TARGET_OUT_VENDOR) \
+ --apex_path $(APEX_OUT)
apex_files :=
apex_dirs :=
@@ -4893,6 +4892,8 @@
check_vintf_all_deps += $(vintffm_log)
$(vintffm_log): $(HOST_OUT_EXECUTABLES)/vintffm $(check_vintf_system_deps)
@( $< --check --dirmap /system:$(TARGET_OUT) \
+ --dirmap /system_ext:$(TARGET_OUT_SYSTEM_EXT) \
+ --dirmap /product:$(TARGET_OUT_PRODUCT) \
$(VINTF_FRAMEWORK_MANIFEST_FROZEN_DIR) > $@ 2>&1 ) || ( cat $@ && exit 1 )
$(call declare-1p-target,$(vintffm_log))
@@ -5295,11 +5296,11 @@
# Additional tools to unpack and repack the apex file.
INTERNAL_OTATOOLS_MODULES += \
+ apexd_host \
apexer \
apex_compression_tool \
deapexer \
debugfs_static \
- dump_apex_info \
fsck.erofs \
make_erofs \
merge_zips \
@@ -5408,6 +5409,9 @@
ifneq ($(INSTALLED_VENDOR_KERNEL_BOOTIMAGE_TARGET),)
$(hide) echo "flash vendor_kernel_boot" >> $@
endif
+ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
+ $(hide) echo "flash recovery" >> $@
+endif
ifeq ($(BOARD_USES_PVMFWIMAGE),true)
$(hide) echo "flash pvmfw" >> $@
endif
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 5dba2d1..f132d13 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -114,7 +114,7 @@
# are controlled by the MODULE_BUILD_FROM_SOURCE environment variable by
# default.
INDIVIDUALLY_TOGGLEABLE_PREBUILT_MODULES := \
- bluetooth \
+ btservices \
permission \
rkpd \
uwb \
diff --git a/core/base_rules.mk b/core/base_rules.mk
index c61c653..9ad1cc5 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -450,6 +450,12 @@
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_IS_HOST_MODULE := $(LOCAL_IS_HOST_MODULE)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_HOST:= $(my_host)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_PREFIX := $(my_prefix)
+$(LOCAL_INTERMEDIATE_TARGETS) : .KATI_TAGS += ;module_name=$(LOCAL_MODULE)
+ifeq ($(LOCAL_MODULE_CLASS),)
+$(error "$(LOCAL_MODULE) in $(LOCAL_PATH) does not set $(LOCAL_MODULE_CLASS)")
+else
+$(LOCAL_INTERMEDIATE_TARGETS) : .KATI_TAGS += ;module_type=$(LOCAL_MODULE_CLASS)
+endif
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_INTERMEDIATES_DIR:= $(intermediates)
$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_2ND_ARCH_VAR_PREFIX := $(LOCAL_2ND_ARCH_VAR_PREFIX)
diff --git a/core/config.mk b/core/config.mk
index 5191917..c166ef7 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -899,6 +899,7 @@
31.0 \
32.0 \
33.0 \
+ 34.0 \
.KATI_READONLY := \
PLATFORM_SEPOLICY_COMPAT_VERSIONS \
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index 252e812..7fa190f 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -180,6 +180,7 @@
ifneq ($(filter address,$(my_sanitize)),)
my_sanitize := $(filter-out cfi,$(my_sanitize))
my_sanitize := $(filter-out memtag_stack,$(my_sanitize))
+ my_sanitize := $(filter-out memtag_globals,$(my_sanitize))
my_sanitize := $(filter-out memtag_heap,$(my_sanitize))
my_sanitize_diag := $(filter-out cfi,$(my_sanitize_diag))
endif
@@ -187,8 +188,8 @@
# Disable memtag for host targets. Host executables in AndroidMk files are
# deprecated, but some partners still have them floating around.
ifdef LOCAL_IS_HOST_MODULE
- my_sanitize := $(filter-out memtag_heap memtag_stack,$(my_sanitize))
- my_sanitize_diag := $(filter-out memtag_heap memtag_stack,$(my_sanitize_diag))
+ my_sanitize := $(filter-out memtag_heap memtag_stack memtag_globals,$(my_sanitize))
+ my_sanitize_diag := $(filter-out memtag_heap memtag_stack memtag_globals,$(my_sanitize_diag))
endif
# Disable sanitizers which need the UBSan runtime for host targets.
@@ -223,11 +224,13 @@
my_sanitize := $(filter-out hwaddress,$(my_sanitize))
my_sanitize := $(filter-out memtag_heap,$(my_sanitize))
my_sanitize := $(filter-out memtag_stack,$(my_sanitize))
+ my_sanitize := $(filter-out memtag_globals,$(my_sanitize))
endif
ifneq ($(filter hwaddress,$(my_sanitize)),)
my_sanitize := $(filter-out address,$(my_sanitize))
my_sanitize := $(filter-out memtag_stack,$(my_sanitize))
+ my_sanitize := $(filter-out memtag_globals,$(my_sanitize))
my_sanitize := $(filter-out memtag_heap,$(my_sanitize))
my_sanitize := $(filter-out thread,$(my_sanitize))
my_sanitize := $(filter-out cfi,$(my_sanitize))
@@ -244,7 +247,7 @@
endif
endif
-ifneq ($(filter memtag_heap memtag_stack,$(my_sanitize)),)
+ifneq ($(filter memtag_heap memtag_stack memtag_globals,$(my_sanitize)),)
ifneq ($(filter memtag_heap,$(my_sanitize_diag)),)
my_cflags += -fsanitize-memtag-mode=sync
my_sanitize_diag := $(filter-out memtag_heap,$(my_sanitize_diag))
@@ -273,6 +276,14 @@
my_sanitize := $(filter-out memtag_stack,$(my_sanitize))
endif
+ifneq ($(filter memtag_globals,$(my_sanitize)),)
+ my_cflags += -fsanitize=memtag-globals
+ # TODO(mitchp): For now, enable memtag-heap with memtag-globals because the
+ # linker isn't new enough
+ # (https://reviews.llvm.org/differential/changeset/?ref=4243566).
+ my_sanitize := $(filter-out memtag_globals,$(my_sanitize))
+endif
+
# TSAN is not supported on 32-bit architectures. For non-multilib cases, make
# its use an error. For multilib cases, don't use it for the 32-bit case.
ifneq ($(filter thread,$(my_sanitize)),)
diff --git a/core/main.mk b/core/main.mk
index 77b01a2..7b3584e 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -4,7 +4,7 @@
$(error done)
endif
-$(info [1/1] initializing build system ...)
+$(info [1/1] initializing legacy Make module parser ...)
# Absolute path of the present working direcotry.
# This overrides the shell variable $PWD, which does not necessarily points to
@@ -554,7 +554,7 @@
subdir_makefiles_total := $(words init post finish)
endif
-$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] finishing build rules ...)
+$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] finishing legacy Make module parsing ...)
# -------------------------------------------------------------------
# All module makefiles have been included at this point.
@@ -2232,4 +2232,4 @@
$(call dist-write-file,$(KATI_PACKAGE_MK_DIR)/dist.mk)
-$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] writing build rules ...)
+$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] writing legacy Make module rules ...)
diff --git a/core/tasks/art-host-tests.mk b/core/tasks/art-host-tests.mk
index ff9eb09..c95f6e7 100644
--- a/core/tasks/art-host-tests.mk
+++ b/core/tasks/art-host-tests.mk
@@ -50,7 +50,8 @@
grep $(TARGET_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/target.list || true
$(hide) $(SOONG_ZIP) -d -o $@ -P host -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/host.list \
-P target -C $(PRODUCT_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/target.list \
- -P host/testcases -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list
+ -P host/testcases -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list \
+ -sha256
grep -e .*\\.config$$ $(PRIVATE_INTERMEDIATES_DIR)/host.list > $(PRIVATE_INTERMEDIATES_DIR)/host-test-configs.list || true
grep -e .*\\.config$$ $(PRIVATE_INTERMEDIATES_DIR)/target.list > $(PRIVATE_INTERMEDIATES_DIR)/target-test-configs.list || true
$(hide) $(SOONG_ZIP) -d -o $(PRIVATE_art_host_tests_configs_zip) \
diff --git a/core/tasks/sts-lite.mk b/core/tasks/sts-lite.mk
index dee25d4..65c65c3 100644
--- a/core/tasks/sts-lite.mk
+++ b/core/tasks/sts-lite.mk
@@ -29,7 +29,8 @@
$(ZIP2ZIP) -i $(STS_LITE_ZIP) -o $(STS_LITE_ZIP)_filtered \
-x android-sts-lite/tools/sts-tradefed-tests.jar \
'android-sts-lite/tools/*:sts-test/libs/' \
- 'android-sts-lite/testcases/*:sts-test/utils/'
+ 'android-sts-lite/testcases/*:sts-test/utils/' \
+ 'android-sts-lite/jdk/**/*:sts-test/jdk/'
$(MERGE_ZIPS) $@ $(STS_LITE_ZIP)_filtered $(STS_SDK_SAMPLES)
rm -f $(STS_LITE_ZIP)_filtered
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 4a42783..c107254 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -103,7 +103,7 @@
# It must be of the form "YYYY-MM-DD" on production devices.
# It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
# If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
- PLATFORM_SECURITY_PATCH := 2023-05-05
+ PLATFORM_SECURITY_PATCH := 2023-06-05
endif
include $(BUILD_SYSTEM)/version_util.mk
diff --git a/packaging/distdir.mk b/packaging/distdir.mk
index c9508af..153ecf6 100644
--- a/packaging/distdir.mk
+++ b/packaging/distdir.mk
@@ -30,6 +30,7 @@
$(eval _dist_$$(goal):)))
define copy-one-dist-file
+$(2): .KATI_TAGS += ;rule_name=dist-cp
$(2): $(1)
@echo "Dist: $$@"
rm -f $$@
diff --git a/target/product/cfi-common.mk b/target/product/cfi-common.mk
index 11c01a2..559963c 100644
--- a/target/product/cfi-common.mk
+++ b/target/product/cfi-common.mk
@@ -28,6 +28,7 @@
hardware/broadcom/wlan/bcmdhd/wpa_supplicant_8_lib \
hardware/synaptics/wlan/synadhd/wpa_supplicant_8_lib \
hardware/interfaces/nfc \
+ hardware/qcom/wlan/qcwcn/wpa_supplicant_8_lib \
hardware/qcom/wlan/legacy/qcwcn/wpa_supplicant_8_lib \
hardware/qcom/wlan/wcn6740/qcwcn/wpa_supplicant_8_lib \
hardware/interfaces/keymaster \
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index aa43785..5b7234e 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -27,6 +27,9 @@
"libserde_json",
"libtinytemplate",
],
+ proc_macros: [
+ "libpaste",
+ ]
}
rust_binary_host {
diff --git a/tools/aconfig/Cargo.toml b/tools/aconfig/Cargo.toml
index b3c73b8..941b30d 100644
--- a/tools/aconfig/Cargo.toml
+++ b/tools/aconfig/Cargo.toml
@@ -11,6 +11,7 @@
[dependencies]
anyhow = "1.0.69"
clap = { version = "4.1.8", features = ["derive"] }
+paste = "1.0.11"
protobuf = "3.2.0"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
diff --git a/tools/aconfig/protos/aconfig.proto b/tools/aconfig/protos/aconfig.proto
index b59fdfc..4cad69a 100644
--- a/tools/aconfig/protos/aconfig.proto
+++ b/tools/aconfig/protos/aconfig.proto
@@ -38,6 +38,7 @@
optional string name = 1;
optional string namespace = 2;
optional string description = 3;
+ repeated string bug = 4;
};
message flag_declarations {
@@ -70,9 +71,10 @@
optional string name = 2;
optional string namespace = 3;
optional string description = 4;
- optional flag_state state = 5;
- optional flag_permission permission = 6;
- repeated tracepoint trace = 7;
+ repeated string bug = 5;
+ optional flag_state state = 6;
+ optional flag_permission permission = 7;
+ repeated tracepoint trace = 8;
}
message parsed_flags {
diff --git a/tools/aconfig/src/codegen.rs b/tools/aconfig/src/codegen.rs
index d96d4f9..b7fb08f 100644
--- a/tools/aconfig/src/codegen.rs
+++ b/tools/aconfig/src/codegen.rs
@@ -32,12 +32,15 @@
}
pub fn is_valid_package_ident(s: &str) -> bool {
+ if !s.contains('.') {
+ return false;
+ }
s.split('.').all(is_valid_name_ident)
}
pub fn create_device_config_ident(package: &str, flag_name: &str) -> Result<String> {
ensure!(is_valid_package_ident(package), "bad package");
- ensure!(is_valid_package_ident(flag_name), "bad flag name");
+ ensure!(is_valid_name_ident(flag_name), "bad flag name");
Ok(format!("{}.{}", package, flag_name))
}
@@ -61,12 +64,13 @@
#[test]
fn test_is_valid_package_ident() {
- assert!(is_valid_package_ident("foo"));
- assert!(is_valid_package_ident("foo_bar_123"));
assert!(is_valid_package_ident("foo.bar"));
+ assert!(is_valid_package_ident("foo.bar_baz"));
assert!(is_valid_package_ident("foo.bar.a123"));
- assert!(!is_valid_package_ident("foo._bar"));
+ assert!(!is_valid_package_ident("foo_bar_123"));
+ assert!(!is_valid_package_ident("foo"));
+ assert!(!is_valid_package_ident("foo._bar"));
assert!(!is_valid_package_ident(""));
assert!(!is_valid_package_ident("123_foo"));
assert!(!is_valid_package_ident("foo-bar"));
@@ -75,6 +79,7 @@
assert!(!is_valid_package_ident(".foo.bar"));
assert!(!is_valid_package_ident("foo.bar."));
assert!(!is_valid_package_ident("."));
+ assert!(!is_valid_package_ident(".."));
assert!(!is_valid_package_ident("foo..bar"));
assert!(!is_valid_package_ident("foo.__bar"));
}
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 47516b7..15eb2d6 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -20,17 +20,23 @@
use tinytemplate::TinyTemplate;
use crate::codegen;
-use crate::commands::OutputFile;
+use crate::commands::{CodegenMode, OutputFile};
use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
-pub fn generate_java_code<'a, I>(package: &str, parsed_flags_iter: I) -> Result<Vec<OutputFile>>
+pub fn generate_java_code<'a, I>(
+ package: &str,
+ parsed_flags_iter: I,
+ codegen_mode: CodegenMode,
+) -> Result<Vec<OutputFile>>
where
I: Iterator<Item = &'a ProtoParsedFlag>,
{
let class_elements: Vec<ClassElement> =
parsed_flags_iter.map(|pf| create_class_element(package, pf)).collect();
let is_read_write = class_elements.iter().any(|elem| elem.is_read_write);
- let context = Context { package_name: package.to_string(), is_read_write, class_elements };
+ let is_test_mode = codegen_mode == CodegenMode::Test;
+ let context =
+ Context { class_elements, is_test_mode, is_read_write, package_name: package.to_string() };
let mut template = TinyTemplate::new();
template.add_template("Flags.java", include_str!("../templates/Flags.java.template"))?;
template.add_template(
@@ -56,14 +62,15 @@
#[derive(Serialize)]
struct Context {
- pub package_name: String,
- pub is_read_write: bool,
pub class_elements: Vec<ClassElement>,
+ pub is_test_mode: bool,
+ pub is_read_write: bool,
+ pub package_name: String,
}
#[derive(Serialize)]
struct ClassElement {
- pub default_value: String,
+ pub default_value: bool,
pub device_config_namespace: String,
pub device_config_flag: String,
pub flag_name_constant_suffix: String,
@@ -75,11 +82,7 @@
let device_config_flag = codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time");
ClassElement {
- default_value: if pf.state() == ProtoFlagState::ENABLED {
- "true".to_string()
- } else {
- "false".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(),
@@ -109,34 +112,50 @@
use super::*;
use std::collections::HashMap;
- #[test]
- fn test_generate_java_code() {
- let parsed_flags = crate::test::parse_test_flags();
- let generated_files =
- generate_java_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter()).unwrap();
- let expect_flags_content = r#"
- package com.android.aconfig.test;
- public final class Flags {
- public static final String FLAG_DISABLED_RO = "com.android.aconfig.test.disabled_ro";
- public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
- public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
- public static final String FLAG_ENABLED_RW = "com.android.aconfig.test.enabled_rw";
+ const EXPECTED_FEATUREFLAGS_CONTENT: &str = r#"
+ package com.android.aconfig.test;
+ public interface FeatureFlags {
+ boolean disabledRo();
+ boolean disabledRw();
+ boolean enabledRo();
+ boolean enabledRw();
+ }"#;
- public static boolean disabledRo() {
- return FEATURE_FLAGS.disabledRo();
- }
- public static boolean disabledRw() {
- return FEATURE_FLAGS.disabledRw();
- }
- public static boolean enabledRo() {
- return FEATURE_FLAGS.enabledRo();
- }
- public static boolean enabledRw() {
- return FEATURE_FLAGS.enabledRw();
- }
- private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+ const EXPECTED_FLAG_COMMON_CONTENT: &str = r#"
+ package com.android.aconfig.test;
+ public final class Flags {
+ public static final String FLAG_DISABLED_RO = "com.android.aconfig.test.disabled_ro";
+ public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
+ public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
+ public static final String FLAG_ENABLED_RW = "com.android.aconfig.test.enabled_rw";
+
+ public static boolean disabledRo() {
+ return FEATURE_FLAGS.disabledRo();
}
- "#;
+ public static boolean disabledRw() {
+ return FEATURE_FLAGS.disabledRw();
+ }
+ public static boolean enabledRo() {
+ return FEATURE_FLAGS.enabledRo();
+ }
+ public static boolean enabledRw() {
+ return FEATURE_FLAGS.enabledRw();
+ }
+ "#;
+
+ #[test]
+ fn test_generate_java_code_production() {
+ let parsed_flags = crate::test::parse_test_flags();
+ let generated_files = generate_java_code(
+ crate::test::TEST_PACKAGE,
+ parsed_flags.parsed_flag.iter(),
+ CodegenMode::Production,
+ )
+ .unwrap();
+ let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
+ + r#"
+ private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+ }"#;
let expected_featureflagsimpl_content = r#"
package com.android.aconfig.test;
import android.provider.DeviceConfig;
@@ -167,19 +186,102 @@
}
}
"#;
- let expected_featureflags_content = r#"
+ let mut file_set = HashMap::from([
+ ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()),
+ ("com/android/aconfig/test/FeatureFlagsImpl.java", expected_featureflagsimpl_content),
+ ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_CONTENT),
+ ]);
+
+ for file in generated_files {
+ let file_path = file.path.to_str().unwrap();
+ assert!(file_set.contains_key(file_path), "Cannot find {}", file_path);
+ assert_eq!(
+ None,
+ crate::test::first_significant_code_diff(
+ file_set.get(file_path).unwrap(),
+ &String::from_utf8(file.contents.clone()).unwrap()
+ ),
+ "File {} content is not correct",
+ file_path
+ );
+ file_set.remove(file_path);
+ }
+
+ assert!(file_set.is_empty());
+ }
+
+ #[test]
+ fn test_generate_java_code_test() {
+ let parsed_flags = crate::test::parse_test_flags();
+ let generated_files = generate_java_code(
+ crate::test::TEST_PACKAGE,
+ parsed_flags.parsed_flag.iter(),
+ CodegenMode::Test,
+ )
+ .unwrap();
+ let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
+ + r#"
+ public static void setFeatureFlagsImpl(FeatureFlags featureFlags) {
+ Flags.FEATURE_FLAGS = featureFlags;
+ }
+ public static void unsetFeatureFlagsImpl() {
+ Flags.FEATURE_FLAGS = null;
+ }
+ private static FeatureFlags FEATURE_FLAGS;
+ }
+ "#;
+ let expected_featureflagsimpl_content = r#"
package com.android.aconfig.test;
- public interface FeatureFlags {
- boolean disabledRo();
- boolean disabledRw();
- boolean enabledRo();
- boolean enabledRw();
+ import static java.util.stream.Collectors.toMap;
+ import java.util.stream.Stream;
+ import java.util.HashMap;
+ public final class FeatureFlagsImpl implements FeatureFlags {
+ @Override
+ public boolean disabledRo() {
+ return getFlag(Flags.FLAG_DISABLED_RO);
+ }
+ @Override
+ public boolean disabledRw() {
+ return getFlag(Flags.FLAG_DISABLED_RW);
+ }
+ @Override
+ public boolean enabledRo() {
+ return getFlag(Flags.FLAG_ENABLED_RO);
+ }
+ @Override
+ public boolean enabledRw() {
+ return getFlag(Flags.FLAG_ENABLED_RW);
+ }
+ public void setFlag(String flagName, boolean value) {
+ if (!this.mFlagMap.containsKey(flagName)) {
+ throw new IllegalArgumentException("no such flag" + flagName);
+ }
+ this.mFlagMap.put(flagName, value);
+ }
+ private boolean getFlag(String flagName) {
+ Boolean value = this.mFlagMap.get(flagName);
+ if (value == null) {
+ throw new IllegalArgumentException(flagName + " is not set");
+ }
+ return value;
+ }
+ private HashMap<String, Boolean> mFlagMap = Stream.of(
+ Flags.FLAG_DISABLED_RO,
+ Flags.FLAG_DISABLED_RW,
+ Flags.FLAG_ENABLED_RO,
+ Flags.FLAG_ENABLED_RW
+ )
+ .collect(
+ HashMap::new,
+ (map, elem) -> map.put(elem, null),
+ HashMap::putAll
+ );
}
"#;
let mut file_set = HashMap::from([
- ("com/android/aconfig/test/Flags.java", expect_flags_content),
+ ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()),
("com/android/aconfig/test/FeatureFlagsImpl.java", expected_featureflagsimpl_content),
- ("com/android/aconfig/test/FeatureFlags.java", expected_featureflags_content),
+ ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_CONTENT),
]);
for file in generated_files {
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index f295697..dd2087b 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -74,6 +74,7 @@
parsed_flag.set_name(flag_declaration.take_name());
parsed_flag.set_namespace(flag_declaration.take_namespace());
parsed_flag.set_description(flag_declaration.take_description());
+ parsed_flag.bug.append(&mut flag_declaration.bug);
parsed_flag.set_state(DEFAULT_FLAG_STATE);
parsed_flag.set_permission(DEFAULT_FLAG_PERMISSION);
let mut tracepoint = ProtoTracepoint::new();
@@ -128,12 +129,18 @@
Ok(output)
}
-pub fn create_java_lib(mut input: Input) -> Result<Vec<OutputFile>> {
+#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
+pub enum CodegenMode {
+ Production,
+ Test,
+}
+
+pub fn create_java_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_java_code(package, parsed_flags.parsed_flag.iter())
+ generate_java_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
}
pub fn create_cpp_lib(mut input: Input) -> Result<OutputFile> {
@@ -202,6 +209,7 @@
Text,
Debug,
Protobuf,
+ Textproto,
}
pub fn dump_parsed_flags(mut input: Vec<Input>, format: DumpFormat) -> Result<Vec<u8>> {
@@ -233,6 +241,10 @@
DumpFormat::Protobuf => {
parsed_flags.write_to_vec(&mut output)?;
}
+ DumpFormat::Textproto => {
+ let s = protobuf::text_format::print_to_string_pretty(&parsed_flags);
+ output.extend_from_slice(s.as_bytes());
+ }
}
Ok(output)
}
@@ -311,6 +323,29 @@
assert!(text.contains("com.android.aconfig.test/disabled_ro: DISABLED READ_ONLY"));
}
+ #[test]
+ fn test_dump_protobuf_format() {
+ let expected = protobuf::text_format::parse_from_str::<ProtoParsedFlags>(
+ crate::test::TEST_FLAGS_TEXTPROTO,
+ )
+ .unwrap()
+ .write_to_bytes()
+ .unwrap();
+
+ let input = parse_test_flags_as_input();
+ let actual = dump_parsed_flags(vec![input], DumpFormat::Protobuf).unwrap();
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn test_dump_textproto_format() {
+ let input = parse_test_flags_as_input();
+ let bytes = dump_parsed_flags(vec![input], DumpFormat::Textproto).unwrap();
+ let text = std::str::from_utf8(&bytes).unwrap();
+ assert_eq!(crate::test::TEST_FLAGS_TEXTPROTO.trim(), text.trim());
+ }
+
fn parse_test_flags_as_input() -> Input {
let parsed_flags = crate::test::parse_test_flags();
let binary_proto = parsed_flags.write_to_bytes().unwrap();
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index e6a325d..e20c60c 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -34,7 +34,7 @@
#[cfg(test)]
mod test;
-use commands::{DumpFormat, Input, OutputFile};
+use commands::{CodegenMode, DumpFormat, Input, OutputFile};
fn cli() -> Command {
Command::new("aconfig")
@@ -49,7 +49,13 @@
.subcommand(
Command::new("create-java-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-cpp-lib")
@@ -148,7 +154,8 @@
}
Some(("create-java-lib", sub_matches)) => {
let cache = open_single_file(sub_matches, "cache")?;
- let generated_files = commands::create_java_lib(cache)?;
+ let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
+ let generated_files = commands::create_java_lib(cache, *mode)?;
let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
generated_files
.iter()
diff --git a/tools/aconfig/src/protos.rs b/tools/aconfig/src/protos.rs
index beebd93..17019be 100644
--- a/tools/aconfig/src/protos.rs
+++ b/tools/aconfig/src/protos.rs
@@ -62,29 +62,39 @@
pub use auto_generated::*;
use anyhow::Result;
+use paste::paste;
fn try_from_text_proto<T>(s: &str) -> Result<T>
where
T: protobuf::MessageFull,
{
- // warning: parse_from_str does not check if required fields are set
protobuf::text_format::parse_from_str(s).map_err(|e| e.into())
}
+macro_rules! ensure_required_fields {
+ ($type:expr, $struct:expr, $($field:expr),+) => {
+ $(
+ paste! {
+ ensure!($struct.[<has_ $field>](), "bad {}: missing {}", $type, $field);
+ }
+ )+
+ };
+}
+
pub mod flag_declaration {
use super::*;
use crate::codegen;
use anyhow::ensure;
pub fn verify_fields(pdf: &ProtoFlagDeclaration) -> Result<()> {
- ensure!(pdf.has_name(), "bad flag declaration: missing name");
- ensure!(pdf.has_namespace(), "bad flag declaration: missing namespace");
- ensure!(pdf.has_description(), "bad flag declaration: missing description");
+ ensure_required_fields!("flag declaration", pdf, "name", "namespace", "description");
ensure!(codegen::is_valid_name_ident(pdf.name()), "bad flag declaration: bad name");
ensure!(codegen::is_valid_name_ident(pdf.namespace()), "bad flag declaration: bad name");
ensure!(!pdf.description().is_empty(), "bad flag declaration: empty description");
+ // ProtoFlagDeclaration.bug: Vec<String>: may be empty, no checks needed
+
Ok(())
}
}
@@ -101,7 +111,7 @@
}
pub fn verify_fields(pdf: &ProtoFlagDeclarations) -> Result<()> {
- ensure!(pdf.has_package(), "bad flag declarations: missing package");
+ ensure_required_fields!("flag declarations", pdf, "package");
ensure!(
codegen::is_valid_package_ident(pdf.package()),
@@ -121,10 +131,7 @@
use anyhow::ensure;
pub fn verify_fields(fv: &ProtoFlagValue) -> Result<()> {
- ensure!(fv.has_package(), "bad flag value: missing package");
- ensure!(fv.has_name(), "bad flag value: missing name");
- ensure!(fv.has_state(), "bad flag value: missing state");
- ensure!(fv.has_permission(), "bad flag value: missing permission");
+ ensure_required_fields!("flag value", fv, "package", "name", "state", "permission");
ensure!(codegen::is_valid_package_ident(fv.package()), "bad flag value: bad package");
ensure!(codegen::is_valid_name_ident(fv.name()), "bad flag value: bad name");
@@ -155,9 +162,7 @@
use anyhow::ensure;
pub fn verify_fields(tp: &ProtoTracepoint) -> Result<()> {
- ensure!(tp.has_source(), "bad tracepoint: missing source");
- ensure!(tp.has_state(), "bad tracepoint: missing state");
- ensure!(tp.has_permission(), "bad tracepoint: missing permission");
+ ensure_required_fields!("tracepoint", tp, "source", "state", "permission");
ensure!(!tp.source().is_empty(), "bad tracepoint: empty source");
@@ -171,12 +176,16 @@
use anyhow::ensure;
pub fn verify_fields(pf: &ProtoParsedFlag) -> Result<()> {
- ensure!(pf.has_package(), "bad parsed flag: missing package");
- ensure!(pf.has_name(), "bad parsed flag: missing name");
- ensure!(pf.has_namespace(), "bad parsed flag: missing namespace");
- ensure!(pf.has_description(), "bad parsed flag: missing description");
- ensure!(pf.has_state(), "bad parsed flag: missing state");
- ensure!(pf.has_permission(), "bad parsed flag: missing permission");
+ ensure_required_fields!(
+ "parsed flag",
+ pf,
+ "package",
+ "name",
+ "namespace",
+ "description",
+ "state",
+ "permission"
+ );
ensure!(codegen::is_valid_package_ident(pf.package()), "bad parsed flag: bad package");
ensure!(codegen::is_valid_name_ident(pf.name()), "bad parsed flag: bad name");
@@ -187,6 +196,8 @@
super::tracepoint::verify_fields(tp)?;
}
+ // ProtoParsedFlag.bug: Vec<String>: may be empty, no checks needed
+
Ok(())
}
}
@@ -251,6 +262,8 @@
name: "first"
namespace: "first_ns"
description: "This is the description of the first flag."
+ bug: "123"
+ bug: "abc"
}
flag {
name: "second"
@@ -265,10 +278,14 @@
assert_eq!(first.name(), "first");
assert_eq!(first.namespace(), "first_ns");
assert_eq!(first.description(), "This is the description of the first flag.");
+ assert_eq!(first.bug.len(), 2);
+ assert_eq!(first.bug[0], "123");
+ assert_eq!(first.bug[1], "abc");
let second = flag_declarations.flag.iter().find(|pf| pf.name() == "second").unwrap();
assert_eq!(second.name(), "second");
assert_eq!(second.namespace(), "second_ns");
assert_eq!(second.description(), "This is the description of the second flag.");
+ assert_eq!(second.bug.len(), 0);
// bad input: missing package in flag declarations
let error = flag_declarations::try_from_text_proto(
@@ -532,7 +549,7 @@
// bad input: parsed_flag not sorted by package
let text_proto = r#"
parsed_flag {
- package: "bbb"
+ package: "bbb.bbb"
name: "first"
namespace: "first_ns"
description: "This is the description of the first flag."
@@ -545,7 +562,7 @@
}
}
parsed_flag {
- package: "aaa"
+ package: "aaa.aaa"
name: "second"
namespace: "second_ns"
description: "This is the description of the second flag."
@@ -561,7 +578,7 @@
let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
assert_eq!(
format!("{:?}", error),
- "bad parsed flags: not sorted: bbb.first comes before aaa.second"
+ "bad parsed flags: not sorted: bbb.bbb.first comes before aaa.aaa.second"
);
// bad input: parsed_flag not sorted by name
diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs
index abe9015..04bbe28 100644
--- a/tools/aconfig/src/test.rs
+++ b/tools/aconfig/src/test.rs
@@ -22,6 +22,85 @@
pub const TEST_PACKAGE: &str = "com.android.aconfig.test";
+ pub const TEST_FLAGS_TEXTPROTO: &str = r#"
+parsed_flag {
+ package: "com.android.aconfig.test"
+ name: "disabled_ro"
+ namespace: "aconfig_test"
+ description: "This flag is DISABLED + READ_ONLY"
+ bug: "123"
+ state: DISABLED
+ permission: READ_ONLY
+ trace {
+ source: "tests/test.aconfig"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ trace {
+ source: "tests/first.values"
+ state: DISABLED
+ permission: READ_ONLY
+ }
+}
+parsed_flag {
+ package: "com.android.aconfig.test"
+ name: "disabled_rw"
+ namespace: "aconfig_test"
+ description: "This flag is DISABLED + READ_WRITE"
+ bug: "456"
+ state: DISABLED
+ permission: READ_WRITE
+ trace {
+ source: "tests/test.aconfig"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+}
+parsed_flag {
+ package: "com.android.aconfig.test"
+ name: "enabled_ro"
+ namespace: "aconfig_test"
+ description: "This flag is ENABLED + READ_ONLY"
+ bug: "789"
+ bug: "abc"
+ state: ENABLED
+ permission: READ_ONLY
+ trace {
+ source: "tests/test.aconfig"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ trace {
+ source: "tests/first.values"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ trace {
+ source: "tests/second.values"
+ state: ENABLED
+ permission: READ_ONLY
+ }
+}
+parsed_flag {
+ package: "com.android.aconfig.test"
+ name: "enabled_rw"
+ namespace: "aconfig_test"
+ description: "This flag is ENABLED + READ_WRITE"
+ state: ENABLED
+ permission: READ_WRITE
+ trace {
+ source: "tests/test.aconfig"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ trace {
+ source: "tests/first.values"
+ state: ENABLED
+ permission: READ_WRITE
+ }
+}
+"#;
+
pub fn parse_test_flags() -> ProtoParsedFlags {
let bytes = crate::commands::parse_flags(
"com.android.aconfig.test",
diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
index 2b031f1..dafd99e 100644
--- a/tools/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,20 +1,61 @@
package {package_name};
-{{ if is_read_write }}
+{{ -if is_test_mode }}
+import static java.util.stream.Collectors.toMap;
+
+import java.util.stream.Stream;
+import java.util.HashMap;
+{{ else}}
+{{ if is_read_write- }}
import android.provider.DeviceConfig;
+{{ -endif- }}
{{ endif }}
public final class FeatureFlagsImpl implements FeatureFlags \{
{{ for item in class_elements}}
@Override
public boolean {item.method_name}() \{
- {{ if item.is_read_write- }}
+ {{ -if not is_test_mode- }}
+ {{ if item.is_read_write }}
return DeviceConfig.getBoolean(
"{item.device_config_namespace}",
"{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 }}
-}
\ No newline at end of file
+
+ {{ if is_test_mode- }}
+ public void setFlag(String flagName, boolean value) \{
+ if (!this.mFlagMap.containsKey(flagName)) \{
+ throw new IllegalArgumentException("no such flag" + flagName);
+ }
+ this.mFlagMap.put(flagName, value);
+ }
+
+ private boolean getFlag(String flagName) \{
+ Boolean value = this.mFlagMap.get(flagName);
+ if (value == null) \{
+ throw new IllegalArgumentException(flagName + " is not set");
+ }
+ return value;
+ }
+
+ private HashMap<String, Boolean> mFlagMap = Stream.of(
+ {{-for item in class_elements}}
+ Flags.FLAG_{item.flag_name_constant_suffix}{{ if not @last }},{{ endif }}
+ {{ -endfor }}
+ )
+ .collect(
+ HashMap::new,
+ (map, elem) -> map.put(elem, null),
+ HashMap::putAll
+ );
+ {{ -endif }}
+}
+
+
diff --git a/tools/aconfig/templates/Flags.java.template b/tools/aconfig/templates/Flags.java.template
index 62116c5..eef98eb 100644
--- a/tools/aconfig/templates/Flags.java.template
+++ b/tools/aconfig/templates/Flags.java.template
@@ -9,6 +9,16 @@
return FEATURE_FLAGS.{item.method_name}();
}
{{ endfor }}
- private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+ {{ if is_test_mode }}
+ public static void setFeatureFlagsImpl(FeatureFlags featureFlags) \{
+ Flags.FEATURE_FLAGS = featureFlags;
+ }
+
+ public static void unsetFeatureFlagsImpl() \{
+ Flags.FEATURE_FLAGS = null;
+ }
+ {{ -endif}}
+
+ private static FeatureFlags FEATURE_FLAGS{{ -if not is_test_mode }} = new FeatureFlagsImpl(){{ -endif- }};
}
diff --git a/tools/aconfig/tests/test.aconfig b/tools/aconfig/tests/test.aconfig
index d09396a..a8f6652 100644
--- a/tools/aconfig/tests/test.aconfig
+++ b/tools/aconfig/tests/test.aconfig
@@ -7,6 +7,7 @@
name: "disabled_ro"
namespace: "aconfig_test"
description: "This flag is DISABLED + READ_ONLY"
+ bug: "123"
}
# This flag's final value is calculated from:
@@ -15,6 +16,7 @@
name: "disabled_rw"
namespace: "aconfig_test"
description: "This flag is DISABLED + READ_WRITE"
+ bug: "456"
}
# This flag's final value is calculated from:
@@ -25,6 +27,8 @@
name: "enabled_ro"
namespace: "aconfig_test"
description: "This flag is ENABLED + READ_ONLY"
+ bug: "789"
+ bug: "abc"
}
# This flag's final value is calculated from:
@@ -34,4 +38,5 @@
name: "enabled_rw"
namespace: "aconfig_test"
description: "This flag is ENABLED + READ_WRITE"
+ # no bug field: bug is not mandatory
}
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index a76dc8a..7a2dcb7 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -99,9 +99,8 @@
"releasetools_common",
],
required: [
+ "apexd_host",
"checkvintf",
- "deapexer",
- "dump_apex_info",
],
}
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index 906ad1f..33624f5 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -129,8 +129,9 @@
dirmap = GetDirmap(input_tmp)
- # Simulate apexd from target-files.
- dirmap['/apex'] = PrepareApexDirectory(input_tmp)
+ # Simulate apexd with target-files.
+ # add a mapping('/apex' => ${input_tmp}/APEX) to dirmap
+ PrepareApexDirectory(input_tmp, dirmap)
args_for_skus = GetArgsForSkus(info_dict)
shipping_api_level_args = GetArgsForShippingApiLevel(info_dict)
@@ -204,7 +205,8 @@
return patterns
-def PrepareApexDirectory(inp):
+
+def PrepareApexDirectory(inp, dirmap):
""" Prepare /apex directory before running checkvintf
Apex binaries do not support dirmaps, in order to use these binaries we
@@ -212,93 +214,25 @@
expected device locations.
This simulates how apexd activates APEXes.
- 1. create {inp}/APEX which is treated as a "/" on device.
- 2. copy apexes from target-files to {root}/{partition}/apex.
- 3. mount apexes under {root}/{partition}/apex at {root}/apex.
- 4. generate info files with dump_apex_info.
-
- We'll get the following layout
- {inp}/APEX/apex # Activated APEXes + some info files
- {inp}/APEX/system/apex # System APEXes
- {inp}/APEX/vendor/apex # Vendor APEXes
- ...
-
- Args:
- inp: path to the directory that contains the extracted target files archive.
-
- Returns:
- directory representing /apex on device
+ 1. create {inp}/APEX which is treated as a "/apex" on device.
+ 2. invoke apexd_host with vendor APEXes.
"""
- deapexer = 'deapexer'
- debugfs_path = 'debugfs'
- fsckerofs_path = 'fsck.erofs'
- if OPTIONS.search_path:
- debugfs_path = os.path.join(OPTIONS.search_path, 'bin', 'debugfs_static')
- deapexer_path = os.path.join(OPTIONS.search_path, 'bin', 'deapexer')
- fsckerofs_path = os.path.join(OPTIONS.search_path, 'bin', 'fsck.erofs')
- if os.path.isfile(deapexer_path):
- deapexer = deapexer_path
-
- def ExtractApexes(path, outp):
- # Extract all APEXes found in input path.
- logger.info('Extracting APEXs in %s', path)
- for f in os.listdir(path):
- logger.info(' adding APEX %s', os.path.basename(f))
- apex = os.path.join(path, f)
- if os.path.isdir(apex) and os.path.isfile(os.path.join(apex, 'apex_manifest.pb')):
- info = ParseApexManifest(os.path.join(apex, 'apex_manifest.pb'))
- # Flattened APEXes may have symlinks for libs (linked to /system/lib)
- # We need to blindly copy them all.
- shutil.copytree(apex, os.path.join(outp, info.name), symlinks=True)
- elif os.path.isfile(apex) and apex.endswith(('.apex', '.capex')):
- cmd = [deapexer,
- '--debugfs_path', debugfs_path,
- 'info',
- apex]
- info = json.loads(common.RunAndCheckOutput(cmd))
-
- cmd = [deapexer,
- '--debugfs_path', debugfs_path,
- '--fsckerofs_path', fsckerofs_path,
- 'extract',
- apex,
- os.path.join(outp, info['name'])]
- common.RunAndCheckOutput(cmd)
- else:
- logger.info(' .. skipping %s (is it APEX?)', path)
-
- root_dir_name = 'APEX'
- root_dir = os.path.join(inp, root_dir_name)
- extracted_root = os.path.join(root_dir, 'apex')
+ apex_dir = os.path.join(inp, 'APEX')
+ # checkvintf needs /apex dirmap
+ dirmap['/apex'] = apex_dir
# Always create /apex directory for dirmap
- os.makedirs(extracted_root)
+ os.makedirs(apex_dir)
- create_info_file = False
+ # Invoke apexd_host to activate vendor APEXes for checkvintf
+ apex_host = os.path.join(OPTIONS.search_path, 'bin', 'apexd_host')
+ cmd = [apex_host, '--tool_path', OPTIONS.search_path]
+ cmd += ['--apex_path', dirmap['/apex']]
+ if '/vendor' in dirmap:
+ cmd += ['--vendor_path', dirmap['/vendor']]
+ common.RunAndCheckOutput(cmd)
- # Loop through search path looking for and processing apex/ directories.
- for device_path, target_files_rel_paths in DIR_SEARCH_PATHS.items():
- # checkvintf only needs vendor apexes. skip other partitions for efficiency
- if device_path not in ['/vendor', '/odm']:
- continue
- # First, copy VENDOR/apex/foo.apex to APEX/vendor/apex/foo.apex
- # Then, extract the contents to APEX/apex/foo/
- for target_files_rel_path in target_files_rel_paths:
- inp_partition = os.path.join(inp, target_files_rel_path,"apex")
- if os.path.exists(inp_partition):
- apex_dir = root_dir + os.path.join(device_path + "/apex");
- os.makedirs(root_dir + device_path)
- shutil.copytree(inp_partition, apex_dir, symlinks=True)
- ExtractApexes(apex_dir, extracted_root)
- create_info_file = True
-
- if create_info_file:
- ### Dump apex info files
- dump_cmd = ['dump_apex_info', '--root_dir', root_dir]
- common.RunAndCheckOutput(dump_cmd)
-
- return extracted_root
def CheckVintfFromTargetFiles(inp, info_dict=None):
"""
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 5d102cd..091121f 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1424,9 +1424,10 @@
def ResolveBinaryPath(path):
if os.path.exists(path):
return path
- new_path = os.path.join(OPTIONS.search_path, path)
- if os.path.exists(new_path):
- return new_path
+ if OPTIONS.search_path:
+ new_path = os.path.join(OPTIONS.search_path, path)
+ if os.path.exists(new_path):
+ return new_path
raise ExternalError(
"Failed to find {}".format(new_path))
@@ -2450,12 +2451,22 @@
try:
return int(version)
except ValueError:
- # Not a decimal number. Codename?
- if version in codename_to_api_level_map:
- return codename_to_api_level_map[version]
+ # Not a decimal number.
+ #
+ # It could be either a straight codename, e.g.
+ # UpsideDownCake
+ #
+ # Or a codename with API fingerprint SHA, e.g.
+ # UpsideDownCake.e7d3947f14eb9dc4fec25ff6c5f8563e
+ #
+ # Extract the codename and try and map it to a version number.
+ split = version.split(".")
+ codename = split[0]
+ if codename in codename_to_api_level_map:
+ return codename_to_api_level_map[codename]
raise ExternalError(
- "Unknown minSdkVersion: '{}'. Known codenames: {}".format(
- version, codename_to_api_level_map))
+ "Unknown codename: '{}' from minSdkVersion: '{}'. Known codenames: {}".format(
+ codename, version, codename_to_api_level_map))
def SignFile(input_name, output_name, key, password, min_api_level=None,
diff --git a/tools/releasetools/merge/Android.bp b/tools/releasetools/merge/Android.bp
index 219acf8..96ec73e 100644
--- a/tools/releasetools/merge/Android.bp
+++ b/tools/releasetools/merge/Android.bp
@@ -50,6 +50,7 @@
"releasetools_ota_from_target_files",
],
required: [
+ "apexd_host",
"checkvintf",
"host_init_verifier",
"secilc",
diff --git a/tools/releasetools/merge/merge_dexopt.py b/tools/releasetools/merge/merge_dexopt.py
index 1dd591b..1c0c743 100644
--- a/tools/releasetools/merge/merge_dexopt.py
+++ b/tools/releasetools/merge/merge_dexopt.py
@@ -72,7 +72,6 @@
# <contents of vendor dexpreopt_config.zip>
# system -> output/SYSTEM
# vendor -> output/VENDOR
- # apex -> output/SYSTEM/apex (only for flattened APEX builds)
# apex/ (extracted updatable APEX)
# <apex 1>/
# ...
@@ -114,68 +113,20 @@
os.path.join(output_target_files_dir, 'VENDOR'),
os.path.join(temp_dir, 'vendor'))
- # The directory structure for flatteded APEXes is:
- #
- # SYSTEM
- # apex
- # <APEX name, e.g., com.android.wifi>
- # apex_manifest.pb
- # apex_pubkey
- # etc/
- # javalib/
- # lib/
- # lib64/
- # priv-app/
- #
- # The directory structure for updatable APEXes is:
- #
- # SYSTEM
- # apex
- # com.android.adbd.apex
- # com.android.appsearch.apex
- # com.android.art.apex
- # ...
- apex_root = os.path.join(output_target_files_dir, 'SYSTEM', 'apex')
+ # Extract APEX.
+ logging.info('extracting APEX')
+ apex_extract_root_dir = os.path.join(temp_dir, 'apex')
+ os.makedirs(apex_extract_root_dir)
- # Check for flattended versus updatable APEX.
- if OPTIONS.framework_misc_info.get('target_flatten_apex') == 'false':
- # Extract APEX.
- logging.info('extracting APEX')
-
- apex_extract_root_dir = os.path.join(temp_dir, 'apex')
- os.makedirs(apex_extract_root_dir)
-
- for apex in (glob.glob(os.path.join(apex_root, '*.apex')) +
- glob.glob(os.path.join(apex_root, '*.capex'))):
- logging.info(' apex: %s', apex)
- # deapexer is in the same directory as the merge_target_files binary extracted
- # from otatools.zip.
- apex_json_info = subprocess.check_output(['deapexer', 'info', apex])
- logging.info(' info: %s', apex_json_info)
- apex_info = json.loads(apex_json_info)
- apex_name = apex_info['name']
- logging.info(' name: %s', apex_name)
-
- apex_extract_dir = os.path.join(apex_extract_root_dir, apex_name)
- os.makedirs(apex_extract_dir)
-
- # deapexer uses debugfs_static, which is part of otatools.zip.
- command = [
- 'deapexer',
- '--debugfs_path',
- 'debugfs_static',
- '--fsckerofs_path',
- 'fsck.erofs',
- 'extract',
- apex,
- apex_extract_dir,
- ]
- logging.info(' running %s', command)
- subprocess.check_call(command)
- else:
- # Flattened APEXes don't need to be extracted since they have the necessary
- # directory structure.
- os.symlink(os.path.join(apex_root), os.path.join(temp_dir, 'apex'))
+ command = [
+ 'apexd_host',
+ '--system_path',
+ os.path.join(temp_dir, 'system'),
+ '--apex_path',
+ apex_extract_root_dir,
+ ]
+ logging.info(' running %s', command)
+ subprocess.check_call(command)
# Modify system config to point to the tools that have been extracted.
# Absolute or .. paths are not allowed by the dexpreopt_gen tool in
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 2dfd8c7..86fb480 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -1642,6 +1642,7 @@
'gki_signing_algorithm': 'SHA256_RSA4096',
'gki_signing_signature_args': '--prop foo:bar',
}
+ common.OPTIONS.search_path = None
test_file = tempfile.NamedTemporaryFile()
self.assertRaises(common.ExternalError, common._GenerateGkiCertificate,
test_file.name, 'generic_kernel')