Merge "Kernel modules: add modules.blocklist build support"
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..814cb00
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,8 @@
+third_party {
+ # would be NOTICE save for GPL in:
+ # core/LINUX_KERNEL_COPYING
+ # tools/droiddoc/templates-pdk/assets/jquery-1.6.2.min.js
+ # tools/droiddoc/templates-pdk/assets/jquery-history.js
+ # tools/droiddoc/templates-pdk/assets/jquery-resizable.min.js
+ license_type: RESTRICTED
+}
diff --git a/common/json.mk b/common/json.mk
index ba8ffa7..e376aab 100644
--- a/common/json.mk
+++ b/common/json.mk
@@ -24,7 +24,10 @@
add_json_csv =$= $(call add_json_val,$(1),$(call csv_to_json_list,$(strip $(2))))
add_json_bool =$= $(call add_json_val,$(1),$(if $(strip $(2)),true,false))
add_json_map =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent)"$$(strip $$(1))": {$$(newline))$(json_increase_indent)
+add_json_map_anon =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent){$$(newline))$(json_increase_indent)
end_json_map =$= $(json_decrease_indent)$(eval _json_contents := $$(_json_contents)$$(if $$(filter %$$(comma),$$(lastword $$(_json_contents))),__SV_END)$$(_json_indent)},$$(newline))
+add_json_array =$= $(eval _json_contents := $$(_json_contents)$$(_json_indent)"$$(strip $$(1))": [$$(newline))$(json_increase_indent)
+end_json_array =$= $(json_decrease_indent)$(eval _json_contents := $$(_json_contents)$$(if $$(filter %$$(comma),$$(lastword $$(_json_contents))),__SV_END)$$(_json_indent)],$$(newline))
# Clears _json_contents to start a new json file
json_start =$= $(eval _json_contents := {$$(newline))$(eval _json_indent := $$(4space))
diff --git a/core/Makefile b/core/Makefile
index f64caa9..a7553f0 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -4135,6 +4135,7 @@
mksquashfsimage.sh \
mkuserimg_mke2fs \
ota_from_target_files \
+ repack_bootimg \
sefcontext_compile \
sgdisk \
shflags \
@@ -4155,6 +4156,7 @@
# Additional tools to unpack and repack the apex file.
INTERNAL_OTATOOLS_MODULES += \
apexer \
+ apex_compression_tool \
deapexer \
debugfs_static \
merge_zips \
@@ -5052,7 +5054,7 @@
@# help early validation of the .zip file while uploading it.
$(hide) find $(zip_root)/META | sort >$@.list
$(hide) find $(zip_root) -path $(zip_root)/META -prune -o -print | sort >>$@.list
- $(hide) $(SOONG_ZIP) -d -o $@ -C $(zip_root) -l $@.list
+ $(hide) $(SOONG_ZIP) -d -o $@ -C $(zip_root) -r $@.list
.PHONY: target-files-package
target-files-package: $(BUILT_TARGET_FILES_PACKAGE)
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 883f92d..ff33e0c 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -33,4 +33,22 @@
$(call add_soong_config_namespace,art_module)
SOONG_CONFIG_art_module += source_build
endif
-SOONG_CONFIG_art_module_source_build ?= true
+ifneq (,$(filter true,$(NATIVE_COVERAGE) $(CLANG_COVERAGE)))
+ # Always build ART APEXes from source in coverage builds since the prebuilts
+ # aren't built with instrumentation.
+ # TODO(b/172480617): Find another solution for this.
+ SOONG_CONFIG_art_module_source_build := true
+else ifneq (,$(SANITIZE_TARGET)$(SANITIZE_HOST))
+ # Prebuilts aren't built with sanitizers either.
+ SOONG_CONFIG_art_module_source_build := true
+else
+ # This sets the default for building ART APEXes from source rather than
+ # prebuilts (in packages/modules/ArtPrebuilt and prebuilt/module_sdk/art) in
+ # all other platform builds.
+ SOONG_CONFIG_art_module_source_build ?= true
+endif
+
+# Apex build mode variables
+ifdef APEX_BUILD_FOR_PRE_S_DEVICES
+$(call add_soong_config_var_value,ANDROID,library_linking_strategy,prefer_static)
+endif
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 4fd8baa..68f880f 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -508,6 +508,7 @@
###########################################################
my_init_rc_installed :=
+my_init_rc_path :=
my_init_rc_pairs :=
my_installed_symlinks :=
my_default_test_module :=
@@ -534,7 +535,11 @@
# Rule to install the module's companion init.rc.
my_init_rc := $(LOCAL_INIT_RC_$(my_32_64_bit_suffix)) $(LOCAL_INIT_RC)
ifneq ($(strip $(my_init_rc)),)
-my_init_rc_pairs := $(foreach rc,$(my_init_rc),$(LOCAL_PATH)/$(rc):$(TARGET_OUT$(partition_tag)_ETC)/init/$(notdir $(rc)))
+# Make doesn't support recovery as an output partition, but some Soong modules installed in recovery
+# have init.rc files that need to be installed alongside them. Manually handle the case where the
+# output file is in the recovery partition.
+my_init_rc_path := $(if $(filter $(TARGET_RECOVERY_ROOT_OUT)/%,$(my_module_path)),$(TARGET_RECOVERY_ROOT_OUT)/system/etc,$(TARGET_OUT$(partition_tag)_ETC))
+my_init_rc_pairs := $(foreach rc,$(my_init_rc),$(LOCAL_PATH)/$(rc):$(my_init_rc_path)/init/$(notdir $(rc)))
my_init_rc_installed := $(foreach rc,$(my_init_rc_pairs),$(call word-colon,2,$(rc)))
# Make sure we only set up the copy rules once, even if another arch variant
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 5effac7..019892e 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -277,6 +277,7 @@
LOCAL_SOONG_BUNDLE :=
LOCAL_SOONG_CLASSES_JAR :=
LOCAL_SOONG_DEX_JAR :=
+LOCAL_SOONG_DEXPREOPT_CONFIG :=
LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=
LOCAL_SOONG_HEADER_JAR :=
LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=
diff --git a/target/board/module_arm/device.mk b/core/combo/arch/arm64/armv8-a-branchprot.mk
similarity index 70%
copy from target/board/module_arm/device.mk
copy to core/combo/arch/arm64/armv8-a-branchprot.mk
index cceb987..77f3535 100644
--- a/target/board/module_arm/device.mk
+++ b/core/combo/arch/arm64/armv8-a-branchprot.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,5 +14,6 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+# .mk file required to support build for the new armv8-a-branchprot Arm64 arch
+# variant. The file just needs to be present but does not require to contain
+# anything
diff --git a/core/definitions.mk b/core/definitions.mk
index 4300efe..5f0bf55 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -632,14 +632,6 @@
endef
###########################################################
-## Convert install path to on-device path.
-###########################################################
-# $(1): install path
-define install-path-to-on-device-path
-$(patsubst $(PRODUCT_OUT)%,%,$(1))
-endef
-
-###########################################################
## The intermediates directory. Where object files go for
## a given target. We could technically get away without
## the "_intermediates" suffix on the directory, but it's
@@ -2146,6 +2138,17 @@
$(hide) $(call commit-change-for-toc,$@)
endef
+# Runs jarjar on an input file. Jarjar doesn't exit with a nonzero return code
+# when there is a syntax error in a rules file and doesn't write the output
+# file, so removes the output file before running jarjar and check if it exists
+# after running jarjar.
+define transform-jarjar
+echo $($(PRIVATE_PREFIX)DISPLAY) JarJar: $@
+rm -f $@
+$(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+[ -e $@ ] || (echo "Missing output file"; exit 1)
+endef
+
# Moves $1.tmp to $1 if necessary. This is designed to be used with
# .KATI_RESTAT. For kati, this function doesn't update the timestamp
# of $1 when $1.tmp is identical to $1 so that ninja won't rebuild
diff --git a/core/dex_preopt_config_merger.py b/core/dex_preopt_config_merger.py
new file mode 100755
index 0000000..4efcc17
--- /dev/null
+++ b/core/dex_preopt_config_merger.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+#
+"""
+A tool for merging dexpreopt.config files for <uses-library> dependencies into
+the dexpreopt.config file of the library/app that uses them. This is needed to
+generate class loader context (CLC) for dexpreopt.
+
+In Make there is no topological order when processing different modules, so a
+<uses-library> dependency module may have not been processed yet by the time the
+dependent module is processed. Therefore makefiles communicate the information
+from dependencies via dexpreopt.config files and add file-level dependencies
+from a module dexpreopt.config to its dependency configs. The actual patching
+of configs is done by this script, which is called from the makefiles.
+"""
+
+from __future__ import print_function
+
+import json
+from collections import OrderedDict
+import sys
+
+
+def main():
+ """Program entry point."""
+ if len(sys.argv) < 2:
+ raise SystemExit('usage: %s <main-config> [dep-config ...]' % sys.argv[0])
+
+ # Read all JSON configs.
+ cfgs = []
+ for arg in sys.argv[1:]:
+ with open(arg, 'r') as f:
+ cfgs.append(json.load(f, object_pairs_hook=OrderedDict))
+
+ # The first config is the dexpreopted library/app, the rest are its
+ # <uses-library> dependencies.
+ cfg0 = cfgs[0]
+
+ # Put dependency configs in a map keyed on module name (for easier lookup).
+ uses_libs = {}
+ for cfg in cfgs[1:]:
+ uses_libs[cfg['Name']] = cfg
+
+ # Load the original CLC map.
+ clc_map = cfg0['ClassLoaderContexts']
+
+ # Create a new CLC map that will be a copy of the original one with patched
+ # fields from dependency dexpreopt.config files.
+ clc_map2 = OrderedDict()
+
+ # Patch CLC for each SDK version. Although this should not be necessary for
+ # compatibility libraries (so-called "conditional CLC"), because they all have
+ # known names, known paths in system/framework, and no subcontext. But keep
+ # the loop in case this changes in the future.
+ for sdk_ver in clc_map:
+ clcs = clc_map[sdk_ver]
+ clcs2 = []
+ for clc in clcs:
+ lib = clc['Name']
+ if lib in uses_libs:
+ ulib = uses_libs[lib]
+ # The real <uses-library> name (may be different from the module name).
+ clc['Name'] = ulib['ProvidesUsesLibrary']
+ # On-device (install) path to the dependency DEX jar file.
+ clc['Device'] = ulib['DexLocation']
+ # CLC of the dependency becomes a subcontext. We only need sub-CLC for
+ # 'any' version because all other versions are for compatibility
+ # libraries, which exist only for apps and not for libraries.
+ clc['Subcontexts'] = ulib['ClassLoaderContexts'].get('any')
+ else:
+ # dexpreopt.config for this <uses-library> is not among the script
+ # arguments, which may be the case with compatibility libraries that
+ # don't need patching anyway. Just use the original CLC.
+ pass
+ clcs2.append(clc)
+ clc_map2[sdk_ver] = clcs2
+
+ # Overwrite the original class loader context with the patched one.
+ cfg0['ClassLoaderContexts'] = clc_map2
+
+ # Update dexpreopt.config file.
+ with open(sys.argv[1], 'w') as f:
+ f.write(json.dumps(cfgs[0], indent=4, separators=(',', ': ')))
+
+if __name__ == '__main__':
+ main()
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index b74e047..f9a9ba7 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -189,42 +189,68 @@
my_filtered_optional_uses_libraries := $(filter-out $(INTERNAL_PLATFORM_MISSING_USES_LIBRARIES), \
$(LOCAL_OPTIONAL_USES_LIBRARIES))
- # compatibility libraries are added to class loader context of an app only if
- # targetSdkVersion in the app's manifest is lower than the given SDK version
+ # TODO(b/132357300): This may filter out too much, as PRODUCT_PACKAGES doesn't
+ # include all packages (the full list is unknown until reading all Android.mk
+ # makefiles). As a consequence, a library may be present but not included in
+ # dexpreopt, which will result in class loader context mismatch and a failure
+ # to load dexpreopt code on device. We should fix this, either by deferring
+ # dependency computation until the full list of product packages is known, or
+ # by adding product-specific lists of missing libraries.
+ my_filtered_optional_uses_libraries := $(filter $(PRODUCT_PACKAGES), \
+ $(my_filtered_optional_uses_libraries))
- my_dexpreopt_libs_compat_28 := \
- org.apache.http.legacy
+ ifeq ($(LOCAL_MODULE_CLASS),APPS)
+ # compatibility libraries are added to class loader context of an app only if
+ # targetSdkVersion in the app's manifest is lower than the given SDK version
- my_dexpreopt_libs_compat_29 := \
- android.hidl.base-V1.0-java \
- android.hidl.manager-V1.0-java
+ my_dexpreopt_libs_compat_28 := \
+ org.apache.http.legacy
- my_dexpreopt_libs_compat_30 := \
- android.test.base \
- android.test.mock
+ my_dexpreopt_libs_compat_29 := \
+ android.hidl.base-V1.0-java \
+ android.hidl.manager-V1.0-java
- my_dexpreopt_libs_compat := \
- $(my_dexpreopt_libs_compat_28) \
- $(my_dexpreopt_libs_compat_29) \
- $(my_dexpreopt_libs_compat_30)
+ my_dexpreopt_libs_compat_30 := \
+ android.test.base \
+ android.test.mock
- my_dexpreopt_libs := $(sort \
+ my_dexpreopt_libs_compat := \
+ $(my_dexpreopt_libs_compat_28) \
+ $(my_dexpreopt_libs_compat_29) \
+ $(my_dexpreopt_libs_compat_30)
+ else
+ my_dexpreopt_libs_compat :=
+ endif
+
+ my_dexpreopt_libs := \
$(LOCAL_USES_LIBRARIES) \
- $(my_filtered_optional_uses_libraries) \
- )
+ $(my_filtered_optional_uses_libraries)
# 1: SDK version
# 2: list of libraries
+ #
+ # Make does not process modules in topological order wrt. <uses-library>
+ # dependencies, therefore we cannot rely on variables to get the information
+ # about dependencies (in particular, their on-device path and class loader
+ # context). This information is communicated via dexpreopt.config files: each
+ # config depends on configs for <uses-library> dependencies of this module,
+ # and the dex_preopt_config_merger.py script reads all configs and inserts the
+ # missing bits from dependency configs into the module config.
+ #
+ # By default on-device path is /system/framework/*.jar, and class loader
+ # subcontext is empty. These values are correct for compatibility libraries,
+ # which are special and not handled by dex_preopt_config_merger.py.
+ #
add_json_class_loader_context = \
- $(call add_json_map, $(1)) \
+ $(call add_json_array, $(1)) \
$(foreach lib, $(2),\
- $(call add_json_map, $(lib)) \
- $(eval file := $(filter %/$(lib).jar, $(call module-installed-files,$(lib)))) \
- $(call add_json_str, Host, $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar) \
- $(call add_json_str, Device, $(call install-path-to-on-device-path,$(file))) \
- $(call add_json_map, Subcontexts, ${$}) $(call end_json_map) \
+ $(call add_json_map_anon) \
+ $(call add_json_str, Name, $(lib)) \
+ $(call add_json_str, Host, $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar) \
+ $(call add_json_str, Device, /system/framework/$(lib).jar) \
+ $(call add_json_val, Subcontexts, null) \
$(call end_json_map)) \
- $(call end_json_map)
+ $(call end_json_array)
# Record dex-preopt config.
DEXPREOPT.$(LOCAL_MODULE).DEX_PREOPT := $(LOCAL_DEX_PREOPT)
@@ -275,12 +301,27 @@
my_dexpreopt_config := $(intermediates)/dexpreopt.config
my_dexpreopt_script := $(intermediates)/dexpreopt.sh
my_dexpreopt_zip := $(intermediates)/dexpreopt.zip
+ my_dexpreopt_config_merger := $(BUILD_SYSTEM)/dex_preopt_config_merger.py
+ # Module dexpreopt.config depends on dexpreopt.config files of each
+ # <uses-library> dependency, because these libraries may be processed after
+ # the current module by Make (there's no topological order), so the dependency
+ # information (paths, class loader context) may not be ready yet by the time
+ # this dexpreopt.config is generated. So it's necessary to add file-level
+ # dependencies between dexpreopt.config files.
+ my_dexpreopt_dep_configs := $(foreach lib, \
+ $(filter-out $(my_dexpreopt_libs_compat),$(LOCAL_USES_LIBRARIES) $(my_filtered_optional_uses_libraries)), \
+ $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,)/dexpreopt.config)
+
+ $(my_dexpreopt_config): $(my_dexpreopt_dep_configs) $(my_dexpreopt_config_merger)
$(my_dexpreopt_config): PRIVATE_MODULE := $(LOCAL_MODULE)
$(my_dexpreopt_config): PRIVATE_CONTENTS := $(json_contents)
+ $(my_dexpreopt_config): PRIVATE_DEP_CONFIGS := $(my_dexpreopt_dep_configs)
+ $(my_dexpreopt_config): PRIVATE_CONFIG_MERGER := $(my_dexpreopt_config_merger)
$(my_dexpreopt_config):
@echo "$(PRIVATE_MODULE) dexpreopt.config"
echo -e -n '$(subst $(newline),\n,$(subst ','\'',$(subst \,\\,$(PRIVATE_CONTENTS))))' > $@
+ $(PRIVATE_CONFIG_MERGER) $@ $(PRIVATE_DEP_CONFIGS)
.KATI_RESTAT: $(my_dexpreopt_script)
$(my_dexpreopt_script): PRIVATE_MODULE := $(LOCAL_MODULE)
diff --git a/core/host_dalvik_java_library.mk b/core/host_dalvik_java_library.mk
index da32978..5eeb8ac 100644
--- a/core/host_dalvik_java_library.mk
+++ b/core/host_dalvik_java_library.mk
@@ -125,8 +125,7 @@
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_header_jarjar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_header_jarjar): $(full_classes_turbine_jar) $(LOCAL_JARJAR_RULES) | $(JARJAR)
- @echo Header JarJar: $@
- $(hide) $(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+ $(call transform-jarjar)
else
full_classes_header_jarjar := $(full_classes_turbine_jar)
endif
@@ -149,8 +148,7 @@
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_jarjar_jar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_jarjar_jar): $(full_classes_combined_jar) $(LOCAL_JARJAR_RULES) | $(JARJAR)
- @echo JarJar: $@
- $(hide) $(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+ $(call transform-jarjar)
else
full_classes_jarjar_jar := $(full_classes_combined_jar)
endif
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index f9abe9b..0f95202 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -113,8 +113,7 @@
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_jarjar_jar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_jarjar_jar): $(full_classes_combined_jar) $(LOCAL_JARJAR_RULES) | $(JARJAR)
- @echo JarJar: $@
- $(hide) $(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+ $(call transform-jarjar)
else
full_classes_jarjar_jar := $(full_classes_combined_jar)
endif
diff --git a/core/java.mk b/core/java.mk
index 5fe8da5..d28c0c4 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -253,8 +253,7 @@
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_header_jarjar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_header_jarjar): $(full_classes_turbine_jar) $(LOCAL_JARJAR_RULES) | $(JARJAR)
- @echo Header JarJar: $@
- $(hide) $(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+ $(call transform-jarjar)
else
full_classes_header_jarjar := $(full_classes_turbine_jar)
endif
@@ -334,8 +333,7 @@
ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
$(full_classes_jarjar_jar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
$(full_classes_jarjar_jar): $(full_classes_processed_jar) $(LOCAL_JARJAR_RULES) | $(JARJAR)
- @echo JarJar: $@
- $(hide) $(JAVA) -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+ $(call transform-jarjar)
else
full_classes_jarjar_jar := $(full_classes_processed_jar)
endif
diff --git a/core/main.mk b/core/main.mk
index 5ea95c8..2c78815 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -83,6 +83,8 @@
-include test/vts/tools/vts-core-tradefed/build/config.mk
# CSUITE-specific config.
-include test/app_compat/csuite/tools/build/config.mk
+# CTS-Root-specific config.
+-include test/cts-root/tools/build/config.mk
# Clean rules
.PHONY: clean-dex-files
diff --git a/core/soong_config.mk b/core/soong_config.mk
index fde5832..bdc8ce9 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -153,13 +153,18 @@
$(call add_json_bool,$(module),true))
$(call end_json_map)
+$(call add_json_bool, DirectedRecoverySnapshot, $(DIRECTED_RECOVERY_SNAPSHOT))
+$(call add_json_map, RecoverySnapshotModules)
+$(foreach module,$(RECOVERY_SNAPSHOT_MODULES),\
+ $(call add_json_bool,$(module),true))
+$(call end_json_map)
+
$(call add_json_bool, Treble_linker_namespaces, $(filter true,$(PRODUCT_TREBLE_LINKER_NAMESPACES)))
$(call add_json_bool, Enforce_vintf_manifest, $(filter true,$(PRODUCT_ENFORCE_VINTF_MANIFEST)))
$(call add_json_bool, Check_elf_files, $(filter true,$(PRODUCT_CHECK_ELF_FILES)))
$(call add_json_bool, Uml, $(filter true,$(TARGET_USER_MODE_LINUX)))
-$(call add_json_bool, Use_lmkd_stats_log, $(filter true,$(TARGET_LMKD_STATS_LOG)))
$(call add_json_str, VendorPath, $(TARGET_COPY_OUT_VENDOR))
$(call add_json_str, OdmPath, $(TARGET_COPY_OUT_ODM))
$(call add_json_str, VendorDlkmPath, $(TARGET_COPY_OUT_VENDOR_DLKM))
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 5444d96..c600178 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -5,6 +5,7 @@
# LOCAL_SOONG_HEADER_JAR
# LOCAL_SOONG_DEX_JAR
# LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR
+# LOCAL_SOONG_DEXPREOPT_CONFIG
ifneq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
$(call pretty-error,soong_java_prebuilt.mk may only be used from Soong)
@@ -146,6 +147,12 @@
ALL_MODULES.$(my_register_name).AAR := $(LOCAL_SOONG_AAR)
endif
+# Copy dexpreopt.config files from Soong libraries to the location where Make
+# modules can find them.
+ifdef LOCAL_SOONG_DEXPREOPT_CONFIG
+ $(eval $(call copy-one-file,$(LOCAL_SOONG_DEXPREOPT_CONFIG), $(call local-intermediates-dir,)/dexpreopt.config))
+endif
+
javac-check : $(full_classes_jar)
javac-check-$(LOCAL_MODULE) : $(full_classes_jar)
.PHONY: javac-check-$(LOCAL_MODULE)
diff --git a/core/tasks/cts_root.mk b/core/tasks/cts_root.mk
new file mode 100644
index 0000000..b618121
--- /dev/null
+++ b/core/tasks/cts_root.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2021 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.
+
+ifneq ($(wildcard test/cts-root/README.md),)
+test_suite_name := cts_root
+test_suite_tradefed := cts-root-tradefed
+test_suite_readme := test/cts-root/README.md
+
+include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
+
+.PHONY: cts_root
+cts_root: $(compatibility_zip)
+$(call dist-for-goals, cts_root, $(compatibility_zip))
+endif
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index fe90165..0c91a14 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -240,7 +240,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 := 2021-01-05
+ PLATFORM_SECURITY_PATCH := 2021-02-05
endif
.KATI_READONLY := PLATFORM_SECURITY_PATCH
diff --git a/envsetup.sh b/envsetup.sh
index 8fa608b..c03e2cb 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -33,7 +33,9 @@
- allmod: List all modules.
- gomod: Go to the directory containing a module.
- pathmod: Get the directory containing a module.
-- refreshmod: Refresh list of modules for allmod/gomod/pathmod.
+- outmod: Gets the location of a module's installed outputs with a certain extension.
+- installmod: Adb installs a module's built APK.
+- refreshmod: Refresh list of modules for allmod/gomod/pathmod/outmod/installmod.
- syswrite: Remount partitions (e.g. system.img) as writable, rebooting if necessary.
Environment options:
@@ -411,7 +413,10 @@
fi
complete -F _lunch lunch
+ complete -F _complete_android_module_names pathmod
complete -F _complete_android_module_names gomod
+ complete -F _complete_android_module_names outmod
+ complete -F _complete_android_module_names installmod
complete -F _complete_android_module_names m
}
@@ -1378,9 +1383,8 @@
> $ANDROID_PRODUCT_OUT/module-info.json.build.log 2>&1
}
-# List all modules for the current device, as cached in module-info.json. If any build change is
-# made and it should be reflected in the output, you should run 'refreshmod' first.
-function allmod() {
+# Verifies that module-info.txt exists, creating it if it doesn't.
+function verifymodinfo() {
if [ ! "$ANDROID_PRODUCT_OUT" ]; then
echo "No ANDROID_PRODUCT_OUT. Try running 'lunch' first." >&2
return 1
@@ -1390,6 +1394,12 @@
echo "Could not find module-info.json. It will only be built once, and it can be updated with 'refreshmod'" >&2
refreshmod || return 1
fi
+}
+
+# List all modules for the current device, as cached in module-info.json. If any build change is
+# made and it should be reflected in the output, you should run 'refreshmod' first.
+function allmod() {
+ verifymodinfo || return 1
python -c "import json; print('\n'.join(sorted(json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')).keys())))"
}
@@ -1397,20 +1407,12 @@
# Get the path of a specific module in the android tree, as cached in module-info.json. If any build change
# is made, and it should be reflected in the output, you should run 'refreshmod' first.
function pathmod() {
- if [ ! "$ANDROID_PRODUCT_OUT" ]; then
- echo "No ANDROID_PRODUCT_OUT. Try running 'lunch' first." >&2
- return 1
- fi
-
if [[ $# -ne 1 ]]; then
echo "usage: pathmod <module>" >&2
return 1
fi
- if [ ! -f "$ANDROID_PRODUCT_OUT/module-info.json" ]; then
- echo "Could not find module-info.json. It will only be built once, and it can be updated with 'refreshmod'" >&2
- refreshmod || return 1
- fi
+ verifymodinfo || return 1
local relpath=$(python -c "import json, os
module = '$1'
@@ -1442,6 +1444,59 @@
cd $path
}
+# Gets the list of a module's installed outputs, as cached in module-info.json.
+# If any build change is made, and it should be reflected in the output, you should run 'refreshmod' first.
+function outmod() {
+ if [[ $# -ne 1 ]]; then
+ echo "usage: outmod <module>" >&2
+ return 1
+ fi
+
+ verifymodinfo || return 1
+
+ local relpath
+ relpath=$(python -c "import json, os
+module = '$1'
+module_info = json.load(open('$ANDROID_PRODUCT_OUT/module-info.json'))
+if module not in module_info:
+ exit(1)
+for output in module_info[module]['installed']:
+ print(os.path.join('$ANDROID_BUILD_TOP', output))" 2>/dev/null)
+
+ if [ $? -ne 0 ]; then
+ echo "Could not find module '$1' (try 'refreshmod' if there have been build changes?)" >&2
+ return 1
+ elif [ ! -z "$relpath" ]; then
+ echo "$relpath"
+ fi
+}
+
+# adb install a module's apk, as cached in module-info.json. If any build change
+# is made, and it should be reflected in the output, you should run 'refreshmod' first.
+# Usage: installmod [adb install arguments] <module>
+# For example: installmod -r Dialer -> adb install -r /path/to/Dialer.apk
+function installmod() {
+ if [[ $# -eq 0 ]]; then
+ echo "usage: installmod [adb install arguments] <module>" >&2
+ return 1
+ fi
+
+ local _path
+ _path=$(outmod ${@:$#:1})
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ _path=$(echo "$_path" | grep -E \\.apk$ | head -n 1)
+ if [ -z "$_path" ]; then
+ echo "Module '$1' does not produce a file ending with .apk (try 'refreshmod' if there have been build changes?)" >&2
+ return 1
+ fi
+ local length=$(( $# - 1 ))
+ echo adb install ${@:1:$length} $_path
+ adb install ${@:1:$length} $_path
+}
+
function _complete_android_module_names() {
local word=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $(allmod | grep -E "^$word") )
diff --git a/target/board/module_x86/device.mk b/target/board/module_x86/device.mk
deleted file mode 100644
index cceb987..0000000
--- a/target/board/module_x86/device.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright (C) 2020 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, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
diff --git a/target/board/module_x86_64/device.mk b/target/board/module_x86_64/device.mk
deleted file mode 100644
index 0d4c543..0000000
--- a/target/board/module_x86_64/device.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Copyright (C) 2020 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, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/core_64_bit.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index c27badc..7d9d90e 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -72,7 +72,12 @@
endif
-PRODUCT_MAKEFILES += $(LOCAL_DIR)/mainline_sdk.mk
+PRODUCT_MAKEFILES += \
+ $(LOCAL_DIR)/mainline_sdk.mk \
+ $(LOCAL_DIR)/module_arm.mk \
+ $(LOCAL_DIR)/module_arm64.mk \
+ $(LOCAL_DIR)/module_x86.mk \
+ $(LOCAL_DIR)/module_x86_64.mk \
COMMON_LUNCH_CHOICES := \
aosp_arm64-eng \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index c7ae1f0..5238d40 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -400,4 +400,8 @@
PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,\
frameworks/base/config/dirty-image-objects:system/etc/dirty-image-objects)
+# This property allows enabling Keystore 2.0 selectively for testing.
+# TODO Remove when Keystore 2.0 migration is complete. b/171563717
+PRODUCT_SYSTEM_PROPERTIES += persist.android.security.keystore2.enable=false
+
$(call inherit-product, $(SRC_TARGET_DIR)/product/runtime_libart.mk)
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 131ba31..1545780 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -36,7 +36,8 @@
com.android.permission:framework-permission \
com.android.sdkext:framework-sdkextensions \
com.android.wifi:framework-wifi \
- com.android.tethering:framework-tethering
+ com.android.tethering:framework-tethering \
+ com.android.ipsec:android.net.ipsec.ike
# Add the compatibility library that is needed when android.test.base
# is removed from the bootclasspath.
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index 2ca6687..717d990 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -96,6 +96,9 @@
VNDK-core: android.hardware.oemlock-unstable-ndk_platform.so
VNDK-core: android.hardware.power-V1-ndk_platform.so
VNDK-core: android.hardware.power-ndk_platform.so
+VNDK-core: android.hardware.power.stats-V1-ndk_platform.so
+VNDK-core: android.hardware.power.stats-ndk_platform.so
+VNDK-core: android.hardware.power.stats-unstable-ndk_platform.so
VNDK-core: android.hardware.rebootescrow-V1-ndk_platform.so
VNDK-core: android.hardware.rebootescrow-ndk_platform.so
VNDK-core: android.hardware.security.keymint-V1-ndk_platform.so
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 2c74ce0..25716ce 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -34,6 +34,9 @@
# Split selinux policy
PRODUCT_FULL_TREBLE_OVERRIDE := true
+# Enable dynamic partitions to facilitate mixing onto Cuttlefish
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
# Enable dynamic partition size
PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
diff --git a/target/product/media_system.mk b/target/product/media_system.mk
index 4ebec51..143131e 100644
--- a/target/product/media_system.mk
+++ b/target/product/media_system.mk
@@ -58,7 +58,6 @@
# The values should be of the format <apex name>:<jar name>
PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS := \
com.android.permission:service-permission \
- com.android.ipsec:android.net.ipsec.ike \
PRODUCT_COPY_FILES += \
system/core/rootdir/etc/public.libraries.android.txt:system/etc/public.libraries.txt
diff --git a/target/board/module_arm/device.mk b/target/product/module_arm.mk
similarity index 72%
copy from target/board/module_arm/device.mk
copy to target/product/module_arm.mk
index cceb987..d99dce8 100644
--- a/target/board/module_arm/device.mk
+++ b/target/product/module_arm.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,5 +14,8 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/module_common.mk)
+
+PRODUCT_NAME := module_arm
+PRODUCT_BRAND := Android
+PRODUCT_DEVICE := module_arm
diff --git a/target/board/module_arm64/device.mk b/target/product/module_arm64.mk
similarity index 66%
rename from target/board/module_arm64/device.mk
rename to target/product/module_arm64.mk
index 0d4c543..fc9529c 100644
--- a/target/board/module_arm64/device.mk
+++ b/target/product/module_arm64.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,6 +14,9 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/core_64_bit.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/module_common.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
+
+PRODUCT_NAME := module_arm64
+PRODUCT_BRAND := Android
+PRODUCT_DEVICE := module_arm64
diff --git a/target/board/module_arm/device.mk b/target/product/module_common.mk
similarity index 75%
rename from target/board/module_arm/device.mk
rename to target/product/module_common.mk
index cceb987..eedd479 100644
--- a/target/board/module_arm/device.mk
+++ b/target/product/module_common.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,5 +14,5 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/default_art_config.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/languages_default.mk)
diff --git a/target/board/module_arm/device.mk b/target/product/module_x86.mk
similarity index 72%
copy from target/board/module_arm/device.mk
copy to target/product/module_x86.mk
index cceb987..b852e7a 100644
--- a/target/board/module_arm/device.mk
+++ b/target/product/module_x86.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,5 +14,8 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/module_common.mk)
+
+PRODUCT_NAME := module_x86
+PRODUCT_BRAND := Android
+PRODUCT_DEVICE := module_x86
diff --git a/target/board/module_arm64/device.mk b/target/product/module_x86_64.mk
similarity index 66%
copy from target/board/module_arm64/device.mk
copy to target/product/module_x86_64.mk
index 0d4c543..f6bc1fc 100644
--- a/target/board/module_arm64/device.mk
+++ b/target/product/module_x86_64.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 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.
@@ -14,6 +14,9 @@
# limitations under the License.
#
-$(call inherit-product, build/make/target/product/default_art_config.mk)
-$(call inherit-product, build/make/target/product/core_64_bit.mk)
-$(call inherit-product, build/make/target/product/languages_default.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/module_common.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
+
+PRODUCT_NAME := module_x86_64
+PRODUCT_BRAND := Android
+PRODUCT_DEVICE := module_x86_64
diff --git a/target/product/runtime_libart.mk b/target/product/runtime_libart.mk
index e655d51..d3da8fe 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -56,17 +56,18 @@
ifeq (eng,$(TARGET_BUILD_VARIANT))
PRODUCT_SYSTEM_PROPERTIES += \
pm.dexopt.first-boot?=extract \
- pm.dexopt.boot?=extract
+ pm.dexopt.boot-after-ota?=extract
else
PRODUCT_SYSTEM_PROPERTIES += \
- pm.dexopt.first-boot?=quicken \
- pm.dexopt.boot?=verify
+ pm.dexopt.first-boot?=verify \
+ pm.dexopt.boot-after-ota?=verify
endif
# The install filter is speed-profile in order to enable the use of
# profiles from the dex metadata files. Note that if a profile is not provided
# or if it is empty speed-profile is equivalent to (quicken + empty app image).
PRODUCT_SYSTEM_PROPERTIES += \
+ pm.dexopt.post-boot?=extract \
pm.dexopt.install?=speed-profile \
pm.dexopt.install-fast?=skip \
pm.dexopt.install-bulk?=speed-profile \
diff --git a/tools/Android.bp b/tools/Android.bp
index e0f3739..357ee2a 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -62,10 +62,10 @@
srcs: ["extract_kernel.py"],
version: {
py2: {
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
}
diff --git a/tools/extract_kernel.py b/tools/extract_kernel.py
index 0046b38..44fbcdf 100755
--- a/tools/extract_kernel.py
+++ b/tools/extract_kernel.py
@@ -39,12 +39,12 @@
# "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
# LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
LINUX_BANNER_PREFIX = b'Linux version '
-LINUX_BANNER_REGEX = LINUX_BANNER_PREFIX + \
+LINUX_BANNER_REGEX = LINUX_BANNER_PREFIX.decode() + \
r'(?P<release>(?P<version>[0-9]+[.][0-9]+[.][0-9]+).*) \(.*@.*\) \((?P<compiler>.*)\) .*\n'
def get_from_release(input_bytes, start_idx, key):
- null_idx = input_bytes.find('\x00', start_idx)
+ null_idx = input_bytes.find(b'\x00', start_idx)
if null_idx < 0:
return None
try:
@@ -69,7 +69,7 @@
value = get_from_release(input_bytes, idx, key)
if value:
- return value
+ return value.encode()
idx += len(LINUX_BANNER_PREFIX)
@@ -140,7 +140,7 @@
while True:
idx = input_bytes.find(search_bytes, idx)
if idx < 0:
- raise StopIteration()
+ return
yield try_decompress_bytes(cmd, input_bytes[idx:])
idx += 1
@@ -183,6 +183,11 @@
return False
return True
+def to_bytes_io(b):
+ """
+ Make b, which is either sys.stdout or sys.stdin, receive bytes as arguments.
+ """
+ return b.buffer if sys.version_info.major == 3 else b
def main():
parser = argparse.ArgumentParser(
@@ -194,35 +199,35 @@
help='Input kernel image. If not specified, use stdin',
metavar='FILE',
type=argparse.FileType('rb'),
- default=sys.stdin)
+ default=to_bytes_io(sys.stdin))
parser.add_argument('--output-configs',
help='If specified, write configs. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
- const=sys.stdout)
+ const=to_bytes_io(sys.stdout))
parser.add_argument('--output-version',
help='If specified, write version. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
- const=sys.stdout)
+ const=to_bytes_io(sys.stdout))
parser.add_argument('--output-release',
help='If specified, write kernel release. Use stdout if '
'no file is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
- const=sys.stdout)
+ const=to_bytes_io(sys.stdout))
parser.add_argument('--output-compiler',
help='If specified, write the compiler information. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
- const=sys.stdout)
+ const=to_bytes_io(sys.stdout))
parser.add_argument('--tools',
help='Decompression tools to use. If not specified, PATH '
'is searched.',
diff --git a/tools/product_config/Android.bp b/tools/product_config/Android.bp
index 287ed5a..9523b4d 100644
--- a/tools/product_config/Android.bp
+++ b/tools/product_config/Android.bp
@@ -18,6 +18,7 @@
static_libs: [
"junit"
],
+ manifest: "TEST_MANIFEST.MF",
test_suites: ["general-tests"]
}
diff --git a/tools/product_config/TEST_MANIFEST.MF b/tools/product_config/TEST_MANIFEST.MF
new file mode 100644
index 0000000..287a77f
--- /dev/null
+++ b/tools/product_config/TEST_MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.build.config.TestRunner
diff --git a/tools/product_config/src/com/android/build/config/CommandException.java b/tools/product_config/src/com/android/build/config/CommandException.java
new file mode 100644
index 0000000..f1a2c39
--- /dev/null
+++ b/tools/product_config/src/com/android/build/config/CommandException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.build.config;
+
+/**
+ * Exception to indicate that a fatal error has occurred. Throwing this
+ * will cause errors to be printed, cleanup to occur, and the command to
+ * exit with a failure code.
+ *
+ * These are user errors. Throwing other exceptions will result in
+ * the stack trace being shown.
+ */
+public class CommandException extends RuntimeException {
+ public CommandException() {
+ super();
+ }
+
+ public CommandException(String message) {
+ super(message);
+ }
+
+ public CommandException(String message, Throwable chain) {
+ super(message, chain);
+ }
+}
diff --git a/tools/product_config/src/com/android/build/config/ErrorReporter.java b/tools/product_config/src/com/android/build/config/ErrorReporter.java
index f382b4e..5d87636 100644
--- a/tools/product_config/src/com/android/build/config/ErrorReporter.java
+++ b/tools/product_config/src/com/android/build/config/ErrorReporter.java
@@ -49,6 +49,16 @@
*/
private boolean mHadError;
+ public static class FatalException extends RuntimeException {
+ FatalException(String message) {
+ super(message);
+ }
+
+ FatalException(String message, Throwable chain) {
+ super(message, chain);
+ }
+ }
+
/**
* Whether errors are errors, warnings or hidden.
*/
@@ -127,6 +137,35 @@
public String getHelp() {
return mHelp;
}
+
+ /**
+ * Add an error with no source position.
+ */
+ public void add(String message) {
+ ErrorReporter.this.add(this, false, new Position(), message);
+ }
+
+ /**
+ * Add an error.
+ */
+ public void add(Position pos, String message) {
+ ErrorReporter.this.add(this, false, pos, message);
+ }
+
+ /**
+ * Add an error with no source position, and throw a FatalException, stopping processing
+ * immediately.
+ */
+ public void fatal(String message) {
+ ErrorReporter.this.add(this, true, new Position(), message);
+ }
+
+ /**
+ * Add an error, and throw a FatalException, stopping processing immediately.
+ */
+ public void fatal(Position pos, String message) {
+ ErrorReporter.this.add(this, true, pos, message);
+ }
}
/**
@@ -154,6 +193,13 @@
public String getMessage() {
return mMessage;
}
+
+ @Override
+ public String toString() {
+ return mPosition
+ + "[" + mCategory.getLevel().getLabel() + " " + mCategory.getCode() + "] "
+ + mMessage;
+ }
}
private void initLocked() {
@@ -191,22 +237,16 @@
}
/**
- * Add an error with no source position.
- */
- public void add(Category category, String message) {
- add(category, new Position(), message);
- }
-
- /**
* Add an error.
*/
- public void add(Category category, Position pos, String message) {
+ private void add(Category category, boolean fatal, Position pos, String message) {
synchronized (mEntries) {
initLocked();
if (mCategories.get(category.getCode()) != category) {
throw new RuntimeException("Errors.Category used from the wrong Errors object.");
}
- mEntries.add(new Entry(category, pos, message));
+ final Entry entry = new Entry(category, pos, message);
+ mEntries.add(entry);
final Level level = category.getLevel();
if (level == Level.WARNING || level == Level.ERROR) {
mHadWarningOrError = true;
@@ -214,6 +254,9 @@
if (level == Level.ERROR) {
mHadError = true;
}
+ if (fatal) {
+ throw new FatalException(entry.toString());
+ }
}
}
@@ -250,13 +293,10 @@
public void printErrors(PrintStream out) {
synchronized (mEntries) {
for (Entry entry: mEntries) {
- final Category category = entry.getCategory();
- final Level level = category.getLevel();
- if (level == Level.HIDDEN) {
+ if (entry.getCategory().getLevel() == Level.HIDDEN) {
continue;
}
- out.println(entry.getPosition() + "[" + level.getLabel() + " "
- + category.getCode() + "] " + entry.getMessage());
+ out.println(entry.toString());
}
}
}
diff --git a/tools/product_config/src/com/android/build/config/Main.java b/tools/product_config/src/com/android/build/config/Main.java
index 7669742..b792193 100644
--- a/tools/product_config/src/com/android/build/config/Main.java
+++ b/tools/product_config/src/com/android/build/config/Main.java
@@ -38,27 +38,45 @@
// TODO: Get the variables that were defined in starlark and use that to write
// out the make, soong and bazel input files.
+ mErrors.ERROR_COMMAND_LINE.add("asdf");
+ throw new RuntimeException("poop");
}
public static void main(String[] args) {
Errors errors = new Errors();
+ int exitCode = 0;
- Options options = Options.parse(errors, args);
- if (errors.hadError()) {
- Options.printHelp(System.err);
+ try {
+ Options options = Options.parse(errors, args);
+ if (errors.hadError()) {
+ Options.printHelp(System.err);
+ System.err.println();
+ throw new CommandException();
+ }
+
+ switch (options.getAction()) {
+ case DEFAULT:
+ (new Main(errors, options)).run();
+ return;
+ case HELP:
+ Options.printHelp(System.out);
+ return;
+ }
+ } catch (CommandException ex) {
+ // These are user errors, so don't show a stack trace
+ exitCode = 1;
+ } catch (Throwable ex) {
+ // These are programming errors in the code of this tool, so print the exception.
+ // We'll try to print this. If it's something unrecoverable, then we'll hope
+ // for the best. We will still print the errors below, because they can be useful
+ // for debugging.
+ ex.printStackTrace(System.err);
System.err.println();
+ exitCode = 1;
+ } finally {
+ // Print errors and warnings
errors.printErrors(System.err);
- System.exit(1);
}
-
- switch (options.getAction()) {
- case DEFAULT:
- (new Main(errors, options)).run();
- errors.printErrors(System.err);
- return;
- case HELP:
- Options.printHelp(System.out);
- return;
- }
+ System.exit(exitCode);
}
}
diff --git a/tools/product_config/src/com/android/build/config/Options.java b/tools/product_config/src/com/android/build/config/Options.java
index 494b947..48146cb 100644
--- a/tools/product_config/src/com/android/build/config/Options.java
+++ b/tools/product_config/src/com/android/build/config/Options.java
@@ -96,14 +96,14 @@
mIndex++;
}
} catch (ParseException ex) {
- mErrors.add(mErrors.ERROR_COMMAND_LINE, ex.getMessage());
+ mErrors.ERROR_COMMAND_LINE.add(ex.getMessage());
}
return mResult;
}
private void addWarning(Errors.Category category, String message) {
- mErrors.add(category, message);
+ category.add(message);
}
private String getNextNonFlagArg() {
@@ -133,12 +133,11 @@
final int code = requireNextNumberArg(arg);
final Errors.Category category = mErrors.getCategories().get(code);
if (category == null) {
- mErrors.add(mErrors.WARNING_UNKNOWN_COMMAND_LINE_ERROR,
- "Unknown error code: " + code);
+ mErrors.WARNING_UNKNOWN_COMMAND_LINE_ERROR.add("Unknown error code: " + code);
return;
}
if (!category.isLevelSettable()) {
- mErrors.add(mErrors.ERROR_COMMAND_LINE, "Can't set level for error " + code);
+ mErrors.ERROR_COMMAND_LINE.add("Can't set level for error " + code);
return;
}
category.setLevel(level);
diff --git a/tools/product_config/test/com/android/build/config/ErrorReporterTest.java b/tools/product_config/test/com/android/build/config/ErrorReporterTest.java
index 2cde476..b9b25b4 100644
--- a/tools/product_config/test/com/android/build/config/ErrorReporterTest.java
+++ b/tools/product_config/test/com/android/build/config/ErrorReporterTest.java
@@ -30,7 +30,7 @@
public void testAdding() {
TestErrors errors = new TestErrors();
- errors.add(errors.ERROR, new Position("a", 12), "Errrororrrr");
+ errors.ERROR.add(new Position("a", 12), "Errrororrrr");
Assert.assertTrue(errors.hadWarningOrError());
Assert.assertTrue(errors.hadError());
@@ -66,7 +66,7 @@
public void testWarning() {
TestErrors errors = new TestErrors();
- errors.add(errors.WARNING, "Waaaaarninggggg");
+ errors.WARNING.add("Waaaaarninggggg");
Assert.assertTrue(errors.hadWarningOrError());
Assert.assertFalse(errors.hadError());
@@ -80,7 +80,7 @@
public void testHidden() {
TestErrors errors = new TestErrors();
- errors.add(errors.HIDDEN, "Hidddeennn");
+ errors.HIDDEN.add("Hidddeennn");
Assert.assertFalse(errors.hadWarningOrError());
Assert.assertFalse(errors.hadError());
diff --git a/tools/product_config/test/com/android/build/config/TestRunner.java b/tools/product_config/test/com/android/build/config/TestRunner.java
new file mode 100644
index 0000000..9a5ee69
--- /dev/null
+++ b/tools/product_config/test/com/android/build/config/TestRunner.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.build.config;
+
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+public class TestRunner {
+ public static void main(String[] args) {
+ JUnitCore junit = new JUnitCore();
+
+ junit.addListener(new RunListener() {
+ @Override
+ public void testStarted(Description description) {
+ System.out.println("\nSTARTING: " + description.getDisplayName());
+ }
+
+ @Override
+ public void testFailure(Failure failure) {
+ System.out.println("FAILED: "
+ + failure.getDescription().getDisplayName());
+ System.out.println(failure.getTrace());
+ }
+ });
+ Result result = junit.run(ErrorReporterTest.class,
+ OptionsTest.class);
+ if (!result.wasSuccessful()) {
+ System.out.println("\n*** FAILED ***");
+ }
+ }
+}
+
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index c28c4dc..2429f17 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -28,6 +28,8 @@
"add_img_to_target_files.py",
],
libs: [
+ "ota_metadata_proto",
+ "releasetools_apex_utils",
"releasetools_build_image",
"releasetools_build_super_image",
"releasetools_common",
@@ -280,6 +282,7 @@
"boot_signer",
"brotli",
"bsdiff",
+ "deapexer",
"imgdiff",
"minigzip",
"lz4",
@@ -588,6 +591,7 @@
name: "releasetools_py3_test",
defaults: ["releasetools_test_defaults"],
main: "test_utils.py",
+ test_suites: ["general-tests"],
version: {
py2: {
enabled: false,
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 5f35d78..7839b47 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -62,6 +62,9 @@
import rangelib
import sparse_img
import verity_utils
+import ota_metadata_pb2
+
+from apex_utils import GetApexInfoFromTargetFiles
if sys.hexversion < 0x02070000:
print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -94,13 +97,13 @@
name: The name of the output file, regardless of the final destination.
"""
- def __init__(self, output_zip, input_dir, prefix, name):
+ def __init__(self, output_zip, input_dir, *args):
# We write the intermediate output file under the given input_dir, even if
# the final destination is a zip archive.
- self.name = os.path.join(input_dir, prefix, name)
+ self.name = os.path.join(input_dir, *args)
self._output_zip = output_zip
if self._output_zip:
- self._zip_name = os.path.join(prefix, name)
+ self._zip_name = os.path.join(*args)
def Write(self):
if self._output_zip:
@@ -179,7 +182,6 @@
block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system.map")
CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system", img,
block_list=block_list)
-
return img.name
@@ -754,6 +756,22 @@
os.path.join(OPTIONS.input_tmp, "IMAGES",
"{}.img".format(partition_name))))
+def AddApexInfo(output_zip):
+ apex_infos = GetApexInfoFromTargetFiles(OPTIONS.input_tmp)
+ apex_metadata_proto = ota_metadata_pb2.ApexMetadata()
+ apex_metadata_proto.apex_info.extend(apex_infos)
+ apex_info_bytes = apex_metadata_proto.SerializeToString()
+
+ output_file = os.path.join(OPTIONS.input_tmp, "META", "apex_info.pb")
+ with open(output_file, "wb") as ofile:
+ ofile.write(apex_info_bytes)
+ if output_zip:
+ arc_name = "META/apex_info.pb"
+ if arc_name in output_zip.namelist():
+ OPTIONS.replace_updated_files_list.append(arc_name)
+ else:
+ common.ZipWrite(output_zip, output_file, arc_name)
+
def AddImagesToTargetFiles(filename):
"""Creates and adds images (boot/recovery/system/...) to a target_files.zip.
@@ -914,6 +932,8 @@
banner("system_other")
AddSystemOther(output_zip)
+ AddApexInfo(output_zip)
+
if not OPTIONS.is_signing:
banner("userdata")
AddUserdata(output_zip)
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index 7ccc95c..644b92a 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -34,6 +34,8 @@
APEX_PAYLOAD_IMAGE = 'apex_payload.img'
+APEX_PUBKEY = 'apex_pubkey'
+
class ApexInfoError(Exception):
"""An Exception raised during Apex Information command."""
@@ -306,13 +308,13 @@
return payload_info
-def SignUncompressedApex(avbtool, apex_data, payload_key, container_key,
+def SignUncompressedApex(avbtool, apex_file, payload_key, container_key,
container_pw, apk_keys, codename_to_api_level_map,
no_hashtree, signing_args=None):
"""Signs the current uncompressed APEX with the given payload/container keys.
Args:
- apex_data: Raw uncompressed APEX data.
+ apex_file: Uncompressed APEX file.
payload_key: The path to payload signing key (w/ extension).
container_key: The path to container signing key (w/o extension).
container_pw: The matching password of the container_key, or None.
@@ -324,12 +326,6 @@
Returns:
The path to the signed APEX file.
"""
- apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
- with open(apex_file, 'wb') as apex_fp:
- apex_fp.write(apex_data)
-
- APEX_PUBKEY = 'apex_pubkey'
-
# 1. Extract the apex payload image and sign the containing apk files. Repack
# the apex file after signing.
apk_signer = ApexApkSigner(apex_file, container_pw,
@@ -388,6 +384,80 @@
return signed_apex
+def SignCompressedApex(avbtool, apex_file, payload_key, container_key,
+ container_pw, apk_keys, codename_to_api_level_map,
+ no_hashtree, signing_args=None):
+ """Signs the current compressed APEX with the given payload/container keys.
+
+ Args:
+ apex_file: Raw uncompressed APEX data.
+ payload_key: The path to payload signing key (w/ extension).
+ container_key: The path to container signing key (w/o extension).
+ container_pw: The matching password of the container_key, or None.
+ apk_keys: A dict that holds the signing keys for apk files.
+ codename_to_api_level_map: A dict that maps from codename to API level.
+ no_hashtree: Don't include hashtree in the signed APEX.
+ signing_args: Additional args to be passed to the payload signer.
+
+ Returns:
+ The path to the signed APEX file.
+ """
+ debugfs_path = os.path.join(OPTIONS.search_path, 'bin', 'debugfs_static')
+
+ # 1. Decompress original_apex inside compressed apex.
+ original_apex_file = common.MakeTempFile(prefix='original-apex-',
+ suffix='.apex')
+ # Decompression target path should not exist
+ os.remove(original_apex_file)
+ common.RunAndCheckOutput(['deapexer', '--debugfs_path', debugfs_path,
+ 'decompress', '--input', apex_file,
+ '--output', original_apex_file])
+
+ # 2. Sign original_apex
+ signed_original_apex_file = SignUncompressedApex(
+ avbtool,
+ original_apex_file,
+ payload_key,
+ container_key,
+ container_pw,
+ apk_keys,
+ codename_to_api_level_map,
+ no_hashtree,
+ signing_args)
+
+ # 3. Compress signed original apex.
+ compressed_apex_file = common.MakeTempFile(prefix='apex-container-',
+ suffix='.capex')
+ common.RunAndCheckOutput(['apex_compression_tool',
+ 'compress',
+ '--apex_compression_tool_path', os.getenv('PATH'),
+ '--input', signed_original_apex_file,
+ '--output', compressed_apex_file])
+
+ # 4. Align apex
+ aligned_apex = common.MakeTempFile(prefix='apex-container-', suffix='.capex')
+ common.RunAndCheckOutput(['zipalign', '-f', '4096', compressed_apex_file,
+ aligned_apex])
+
+ # 5. Sign the APEX container with container_key.
+ signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.capex')
+
+ # Specify the 4K alignment when calling SignApk.
+ extra_signapk_args = OPTIONS.extra_signapk_args[:]
+ extra_signapk_args.extend(['-a', '4096'])
+
+ password = container_pw.get(container_key) if container_pw else None
+ common.SignFile(
+ aligned_apex,
+ signed_apex,
+ container_key,
+ password,
+ codename_to_api_level_map=codename_to_api_level_map,
+ extra_signapk_args=extra_signapk_args)
+
+ return signed_apex
+
+
def SignApex(avbtool, apex_data, payload_key, container_key, container_pw,
apk_keys, codename_to_api_level_map,
no_hashtree, signing_args=None):
@@ -410,7 +480,7 @@
with open(apex_file, 'wb') as output_fp:
output_fp.write(apex_data)
- debugfs_path = os.path.join(OPTIONS.search_path, "bin", "debugfs_static")
+ debugfs_path = os.path.join(OPTIONS.search_path, 'bin', 'debugfs_static')
cmd = ['deapexer', '--debugfs_path', debugfs_path,
'info', '--print-type', apex_file]
@@ -419,7 +489,18 @@
if apex_type == 'UNCOMPRESSED':
return SignUncompressedApex(
avbtool,
- apex_data,
+ apex_file,
+ payload_key=payload_key,
+ container_key=container_key,
+ container_pw=None,
+ codename_to_api_level_map=codename_to_api_level_map,
+ no_hashtree=no_hashtree,
+ apk_keys=apk_keys,
+ signing_args=signing_args)
+ elif apex_type == 'COMPRESSED':
+ return SignCompressedApex(
+ avbtool,
+ apex_file,
payload_key=payload_key,
container_key=container_key,
container_pw=None,
@@ -458,6 +539,15 @@
target_dir = os.path.join(tmp_dir, "SYSTEM/apex/")
apex_infos = []
+
+ debugfs_path = "debugfs"
+ if OPTIONS.search_path:
+ debugfs_path = os.path.join(OPTIONS.search_path, "bin", "debugfs_static")
+ deapexer = 'deapexer'
+ if OPTIONS.search_path:
+ deapexer_path = os.path.join(OPTIONS.search_path, "bin", "deapexer")
+ if os.path.isfile(deapexer_path):
+ deapexer = deapexer_path
for apex_filename in os.listdir(target_dir):
apex_filepath = os.path.join(target_dir, apex_filename)
if not os.path.isfile(apex_filepath) or \
@@ -470,14 +560,6 @@
apex_info.package_name = manifest.name
apex_info.version = manifest.version
# Check if the file is compressed or not
- debugfs_path = "debugfs"
- if OPTIONS.search_path:
- debugfs_path = os.path.join(OPTIONS.search_path, "bin", "debugfs_static")
- deapexer = 'deapexer'
- if OPTIONS.search_path:
- deapexer_path = os.path.join(OPTIONS.search_path, "deapexer")
- if os.path.isfile(deapexer_path):
- deapexer = deapexer_path
apex_type = RunAndCheckOutput([
deapexer, "--debugfs_path", debugfs_path,
'info', '--print-type', apex_filepath]).rstrip()
@@ -498,6 +580,6 @@
'--output', decompressed_file_path])
apex_info.decompressed_size = os.path.getsize(decompressed_file_path)
- apex_infos.append(apex_info)
+ apex_infos.append(apex_info)
return apex_infos
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 26c4ae8..da189f3 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -276,29 +276,6 @@
return subprocess.Popen(args, **kwargs)
-def RunAndWait(args, verbose=None, **kwargs):
- """Runs the given command waiting for it to complete.
-
- Args:
- args: The command represented as a list of strings.
- verbose: Whether the commands should be shown. Default to the global
- verbosity if unspecified.
- kwargs: Any additional args to be passed to subprocess.Popen(), such as env,
- stdin, etc. stdout and stderr will default to subprocess.PIPE and
- subprocess.STDOUT respectively unless caller specifies any of them.
-
- Raises:
- ExternalError: On non-zero exit from the command.
- """
- proc = Run(args, verbose=verbose, **kwargs)
- proc.wait()
-
- if proc.returncode != 0:
- raise ExternalError(
- "Failed to run command '{}' (exit code {})".format(
- args, proc.returncode))
-
-
def RunAndCheckOutput(args, verbose=None, **kwargs):
"""Runs the given command and returns the output.
@@ -663,7 +640,7 @@
"""Extracts the contents of fn from input zipfile or directory into a file."""
if isinstance(input_file, zipfile.ZipFile):
tmp_file = MakeTempFile(os.path.basename(fn))
- with open(tmp_file, 'w') as f:
+ with open(tmp_file, 'wb') as f:
f.write(input_file.read(fn))
return tmp_file
else:
@@ -887,8 +864,8 @@
prop_file = GetBootImageBuildProp(boot_img)
if prop_file is None:
return ''
- with open(prop_file) as f:
- return f.read().decode()
+ with open(prop_file, "r") as f:
+ return f.read()
@staticmethod
def _ReadPartitionPropFile(input_file, name):
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 9360d7b..3d9c717 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -887,12 +887,12 @@
output_zip,
'-C',
source_dir,
- '-l',
+ '-r',
output_target_files_list,
]
logger.info('creating %s', output_file)
- common.RunAndWait(command, verbose=True)
+ common.RunAndCheckOutput(command, verbose=True)
logger.info('finished creating %s', output_file)
return output_zip
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 6b82d32..2cbaf37 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -229,11 +229,11 @@
import common
import ota_utils
+from ota_utils import (UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata,
+ PropertyFiles)
import target_files_diff
from check_target_files_vintf import CheckVintfIfTrebleEnabled
from non_ab_ota import GenerateNonAbOtaPackage
-from ota_utils import (UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata,
- PropertyFiles)
if sys.hexversion < 0x02070000:
print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -272,6 +272,8 @@
OPTIONS.disable_verity_computation = False
OPTIONS.partial = None
OPTIONS.custom_images = {}
+OPTIONS.disable_vabc = False
+OPTIONS.spl_downgrade = False
POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
@@ -290,6 +292,8 @@
'system_ext', 'vbmeta', 'vbmeta_system', 'vbmeta_vendor', 'vendor',
'vendor_boot']
+SECURITY_PATCH_LEVEL_PROP_NAME = "ro.build.version.security_patch"
+
class PayloadSigner(object):
"""A class that wraps the payload signing works.
@@ -961,7 +965,8 @@
for part in partition_state]
return ["--partition_timestamps", ",".join(partition_timestamps)]
-def GeneratePartitionTimestampFlagsDowngrade(pre_partition_state, post_partition_state):
+def GeneratePartitionTimestampFlagsDowngrade(
+ pre_partition_state, post_partition_state):
assert pre_partition_state is not None
partition_timestamps = {}
for part in pre_partition_state:
@@ -970,9 +975,9 @@
partition_timestamps[part.partition_name] = \
max(part.version, partition_timestamps[part.partition_name])
return [
- "--partition_timestamps",
- ",".join([key + ":" + val for (key, val) in partition_timestamps.items()])
- ]
+ "--partition_timestamps",
+ ",".join([key + ":" + val for (key, val) in partition_timestamps.items()])
+ ]
def IsSparseImage(filepath):
with open(filepath, 'rb') as fp:
@@ -1026,7 +1031,8 @@
else:
staging_file = output_file
output_zip = zipfile.ZipFile(staging_file, "w",
- compression=zipfile.ZIP_DEFLATED, allowZip64=True)
+ compression=zipfile.ZIP_DEFLATED,
+ allowZip64=True)
if source_file is not None:
assert "ab_partitions" in OPTIONS.source_info_dict, \
@@ -1080,25 +1086,27 @@
if OPTIONS.downgrade:
max_timestamp = source_info.GetBuildProp("ro.build.date.utc")
partition_timestamps_flags = GeneratePartitionTimestampFlagsDowngrade(
- metadata.precondition.partition_state,
- metadata.postcondition.partition_state
- )
+ metadata.precondition.partition_state,
+ metadata.postcondition.partition_state
+ )
else:
max_timestamp = str(metadata.postcondition.timestamp)
partition_timestamps_flags = GeneratePartitionTimestampFlags(
metadata.postcondition.partition_state)
+ if OPTIONS.disable_vabc:
+ additional_args += ["--disable_vabc", "true"]
additional_args += ["--max_timestamp", max_timestamp]
if SupportsMainlineGkiUpdates(source_file):
- logger.warn("Detected build with mainline GKI, include full boot image.")
+ logger.warning("Detected build with mainline GKI, include full boot image.")
additional_args.extend(["--full_boot", "true"])
payload.Generate(
target_file,
source_file,
additional_args + partition_timestamps_flags
- )
+ )
# Sign the payload.
payload_signer = PayloadSigner()
@@ -1117,7 +1125,7 @@
secondary_payload = Payload(secondary=True)
secondary_payload.Generate(secondary_target_file,
additional_args=["--max_timestamp",
- max_timestamp])
+ max_timestamp])
secondary_payload.Sign(payload_signer)
secondary_payload.WriteToZip(output_zip)
@@ -1125,7 +1133,7 @@
# into A/B OTA package.
target_zip = zipfile.ZipFile(target_file, "r", allowZip64=True)
if (target_info.get("verity") == "true" or
- target_info.get("avb_enable") == "true"):
+ target_info.get("avb_enable") == "true"):
care_map_list = [x for x in ["care_map.pb", "care_map.txt"] if
"META/" + x in target_zip.namelist()]
@@ -1140,6 +1148,15 @@
else:
logger.warning("Cannot find care map file in target_file package")
+ # Copy apex_info.pb over to generated OTA package.
+ try:
+ apex_info_entry = target_zip.getinfo("META/apex_info.pb")
+ with target_zip.open(apex_info_entry, "r") as zfp:
+ common.ZipWriteStr(output_zip, "apex_info.pb", zfp.read(),
+ compress_type=zipfile.ZIP_STORED)
+ except KeyError:
+ logger.warning("target_file doesn't contain apex_info.pb %s", target_file)
+
common.ZipClose(target_zip)
CheckVintfIfTrebleEnabled(target_file, target_info)
@@ -1246,6 +1263,10 @@
elif o == "--custom_image":
custom_partition, custom_image = a.split("=")
OPTIONS.custom_images[custom_partition] = custom_image
+ elif o == "--disable_vabc":
+ OPTIONS.disable_vabc = True
+ elif o == "--spl_downgrade":
+ OPTIONS.spl_downgrade = True
else:
return False
return True
@@ -1287,6 +1308,8 @@
"boot_variable_file=",
"partial=",
"custom_image=",
+ "disable_vabc",
+ "spl_downgrade"
], extra_option_handler=option_handler)
if len(args) != 2:
@@ -1334,13 +1357,14 @@
if OPTIONS.partial:
OPTIONS.info_dict['ab_partitions'] = \
list(
- set(OPTIONS.info_dict['ab_partitions']) & set(OPTIONS.partial)
- )
+ set(OPTIONS.info_dict['ab_partitions']) & set(OPTIONS.partial)
+ )
if OPTIONS.source_info_dict:
OPTIONS.source_info_dict['ab_partitions'] = \
list(
- set(OPTIONS.source_info_dict['ab_partitions']) & set(OPTIONS.partial)
- )
+ set(OPTIONS.source_info_dict['ab_partitions']) &
+ set(OPTIONS.partial)
+ )
# Load OEM dicts if provided.
OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)
@@ -1349,7 +1373,7 @@
# use_dynamic_partitions but target build does.
if (OPTIONS.source_info_dict and
OPTIONS.source_info_dict.get("use_dynamic_partitions") != "true" and
- OPTIONS.target_info_dict.get("use_dynamic_partitions") == "true"):
+ OPTIONS.target_info_dict.get("use_dynamic_partitions") == "true"):
if OPTIONS.target_info_dict.get("dynamic_partition_retrofit") != "true":
raise common.ExternalError(
"Expect to generate incremental OTA for retrofitting dynamic "
@@ -1365,7 +1389,8 @@
ab_update = OPTIONS.info_dict.get("ab_update") == "true"
allow_non_ab = OPTIONS.info_dict.get("allow_non_ab") == "true"
if OPTIONS.force_non_ab:
- assert allow_non_ab, "--force_non_ab only allowed on devices that supports non-A/B"
+ assert allow_non_ab,\
+ "--force_non_ab only allowed on devices that supports non-A/B"
assert ab_update, "--force_non_ab only allowed on A/B devices"
generate_ab = not OPTIONS.force_non_ab and ab_update
@@ -1380,7 +1405,27 @@
"build/make/target/product/security/testkey")
# Get signing keys
OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
+ private_key_path = OPTIONS.package_key + OPTIONS.private_key_suffix
+ if not os.path.exists(private_key_path):
+ raise common.ExternalError(
+ "Private key {} doesn't exist. Make sure you passed the"
+ " correct key path through -k option".format(
+ private_key_path)
+ )
+ if OPTIONS.source_info_dict:
+ source_build_prop = OPTIONS.source_info_dict["build.prop"]
+ target_build_prop = OPTIONS.target_info_dict["build.prop"]
+ source_spl = source_build_prop.GetProp(SECURITY_PATCH_LEVEL_PROP_NAME)
+ target_spl = target_build_prop.GetProp(SECURITY_PATCH_LEVEL_PROP_NAME)
+ if target_spl < source_spl and not OPTIONS.spl_downgrade:
+ raise common.ExternalError(
+ "Target security patch level {} is older than source SPL {} applying "
+ "such OTA will likely cause device fail to boot. Pass --spl-downgrade "
+ "to override this check. This script expects security patch level to "
+ "be in format yyyy-mm-dd (e.x. 2021-02-05). It's possible to use "
+ "separators other than -, so as long as it's used consistenly across "
+ "all SPL dates".format(target_spl, source_spl))
if generate_ab:
GenerateAbOtaPackage(
target_file=args[0],
diff --git a/tools/releasetools/ota_metadata.proto b/tools/releasetools/ota_metadata.proto
index 1277685..5da8b84 100644
--- a/tools/releasetools/ota_metadata.proto
+++ b/tools/releasetools/ota_metadata.proto
@@ -16,8 +16,8 @@
// If you change this file,
// Please update ota_metadata_pb2.py by executing
-// protoc ota_metadata.proto --python_out $ANDROID_BUILD_TOP/build/tools/releasetools
-
+// protoc ota_metadata.proto --python_out
+// $ANDROID_BUILD_TOP/build/tools/releasetools
syntax = "proto3";
@@ -72,6 +72,12 @@
int64 decompressed_size = 4;
}
+// Just a container to hold repeated apex_info, so that we can easily serialize
+// a list of apex_info to string.
+message ApexMetadata {
+ repeated ApexInfo apex_info = 1;
+}
+
// The metadata of an OTA package. It contains the information of the package
// and prerequisite to install the update correctly.
message OtaMetadata {
diff --git a/tools/releasetools/ota_metadata_pb2.py b/tools/releasetools/ota_metadata_pb2.py
index ff2b2c5..27cc930 100644
--- a/tools/releasetools/ota_metadata_pb2.py
+++ b/tools/releasetools/ota_metadata_pb2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: ota_metadata.proto
-
+"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
@@ -18,7 +18,8 @@
package='build.tools.releasetools',
syntax='proto3',
serialized_options=b'H\003',
- serialized_pb=b'\n\x12ota_metadata.proto\x12\x18\x62uild.tools.releasetools\"X\n\x0ePartitionState\x12\x16\n\x0epartition_name\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65vice\x18\x02 \x03(\t\x12\r\n\x05\x62uild\x18\x03 \x03(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\"\xce\x01\n\x0b\x44\x65viceState\x12\x0e\n\x06\x64\x65vice\x18\x01 \x03(\t\x12\r\n\x05\x62uild\x18\x02 \x03(\t\x12\x19\n\x11\x62uild_incremental\x18\x03 \x01(\t\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\x12\x11\n\tsdk_level\x18\x05 \x01(\t\x12\x1c\n\x14security_patch_level\x18\x06 \x01(\t\x12\x41\n\x0fpartition_state\x18\x07 \x03(\x0b\x32(.build.tools.releasetools.PartitionState\"\xe1\x03\n\x0bOtaMetadata\x12;\n\x04type\x18\x01 \x01(\x0e\x32-.build.tools.releasetools.OtaMetadata.OtaType\x12\x0c\n\x04wipe\x18\x02 \x01(\x08\x12\x11\n\tdowngrade\x18\x03 \x01(\x08\x12P\n\x0eproperty_files\x18\x04 \x03(\x0b\x32\x38.build.tools.releasetools.OtaMetadata.PropertyFilesEntry\x12;\n\x0cprecondition\x18\x05 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12<\n\rpostcondition\x18\x06 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12#\n\x1bretrofit_dynamic_partitions\x18\x07 \x01(\x08\x12\x16\n\x0erequired_cache\x18\x08 \x01(\x03\x1a\x34\n\x12PropertyFilesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"4\n\x07OtaType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02\x41\x42\x10\x01\x12\t\n\x05\x42LOCK\x10\x02\x12\t\n\x05\x42RICK\x10\x03\x42\x02H\x03\x62\x06proto3'
+ create_key=_descriptor._internal_create_key,
+ serialized_pb=b'\n\x12ota_metadata.proto\x12\x18\x62uild.tools.releasetools\"X\n\x0ePartitionState\x12\x16\n\x0epartition_name\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65vice\x18\x02 \x03(\t\x12\r\n\x05\x62uild\x18\x03 \x03(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\"\xce\x01\n\x0b\x44\x65viceState\x12\x0e\n\x06\x64\x65vice\x18\x01 \x03(\t\x12\r\n\x05\x62uild\x18\x02 \x03(\t\x12\x19\n\x11\x62uild_incremental\x18\x03 \x01(\t\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\x12\x11\n\tsdk_level\x18\x05 \x01(\t\x12\x1c\n\x14security_patch_level\x18\x06 \x01(\t\x12\x41\n\x0fpartition_state\x18\x07 \x03(\x0b\x32(.build.tools.releasetools.PartitionState\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"E\n\x0c\x41pexMetadata\x12\x35\n\tapex_info\x18\x01 \x03(\x0b\x32\".build.tools.releasetools.ApexInfo\"\x98\x04\n\x0bOtaMetadata\x12;\n\x04type\x18\x01 \x01(\x0e\x32-.build.tools.releasetools.OtaMetadata.OtaType\x12\x0c\n\x04wipe\x18\x02 \x01(\x08\x12\x11\n\tdowngrade\x18\x03 \x01(\x08\x12P\n\x0eproperty_files\x18\x04 \x03(\x0b\x32\x38.build.tools.releasetools.OtaMetadata.PropertyFilesEntry\x12;\n\x0cprecondition\x18\x05 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12<\n\rpostcondition\x18\x06 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12#\n\x1bretrofit_dynamic_partitions\x18\x07 \x01(\x08\x12\x16\n\x0erequired_cache\x18\x08 \x01(\x03\x12\x35\n\tapex_info\x18\t \x03(\x0b\x32\".build.tools.releasetools.ApexInfo\x1a\x34\n\x12PropertyFilesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"4\n\x07OtaType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02\x41\x42\x10\x01\x12\t\n\x05\x42LOCK\x10\x02\x12\t\n\x05\x42RICK\x10\x03\x42\x02H\x03\x62\x06proto3'
)
@@ -28,28 +29,33 @@
full_name='build.tools.releasetools.OtaMetadata.OtaType',
filename=None,
file=DESCRIPTOR,
+ create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='UNKNOWN', index=0, number=0,
serialized_options=None,
- type=None),
+ type=None,
+ create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='AB', index=1, number=1,
serialized_options=None,
- type=None),
+ type=None,
+ create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='BLOCK', index=2, number=2,
serialized_options=None,
- type=None),
+ type=None,
+ create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='BRICK', index=3, number=3,
serialized_options=None,
- type=None),
+ type=None,
+ create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
- serialized_start=777,
- serialized_end=829,
+ serialized_start=1004,
+ serialized_end=1056,
)
_sym_db.RegisterEnumDescriptor(_OTAMETADATA_OTATYPE)
@@ -60,6 +66,7 @@
filename=None,
file=DESCRIPTOR,
containing_type=None,
+ create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='partition_name', full_name='build.tools.releasetools.PartitionState.partition_name', index=0,
@@ -67,28 +74,28 @@
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='device', full_name='build.tools.releasetools.PartitionState.device', index=1,
number=2, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='build', full_name='build.tools.releasetools.PartitionState.build', index=2,
number=3, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='version', full_name='build.tools.releasetools.PartitionState.version', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
@@ -112,6 +119,7 @@
filename=None,
file=DESCRIPTOR,
containing_type=None,
+ create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='device', full_name='build.tools.releasetools.DeviceState.device', index=0,
@@ -119,49 +127,49 @@
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='build', full_name='build.tools.releasetools.DeviceState.build', index=1,
number=2, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='build_incremental', full_name='build.tools.releasetools.DeviceState.build_incremental', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='timestamp', full_name='build.tools.releasetools.DeviceState.timestamp', index=3,
number=4, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='sdk_level', full_name='build.tools.releasetools.DeviceState.sdk_level', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='security_patch_level', full_name='build.tools.releasetools.DeviceState.security_patch_level', index=5,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='partition_state', full_name='build.tools.releasetools.DeviceState.partition_state', index=6,
number=7, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
@@ -179,12 +187,98 @@
)
+_APEXINFO = _descriptor.Descriptor(
+ name='ApexInfo',
+ full_name='build.tools.releasetools.ApexInfo',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ create_key=_descriptor._internal_create_key,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='package_name', full_name='build.tools.releasetools.ApexInfo.package_name', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=b"".decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='version', full_name='build.tools.releasetools.ApexInfo.version', index=1,
+ number=2, type=3, cpp_type=2, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='is_compressed', full_name='build.tools.releasetools.ApexInfo.is_compressed', index=2,
+ number=3, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='decompressed_size', full_name='build.tools.releasetools.ApexInfo.decompressed_size', index=3,
+ number=4, type=3, cpp_type=2, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ serialized_options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=347,
+ serialized_end=446,
+)
+
+
+_APEXMETADATA = _descriptor.Descriptor(
+ name='ApexMetadata',
+ full_name='build.tools.releasetools.ApexMetadata',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ create_key=_descriptor._internal_create_key,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='apex_info', full_name='build.tools.releasetools.ApexMetadata.apex_info', index=0,
+ number=1, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ serialized_options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=448,
+ serialized_end=517,
+)
+
+
_OTAMETADATA_PROPERTYFILESENTRY = _descriptor.Descriptor(
name='PropertyFilesEntry',
full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry',
filename=None,
file=DESCRIPTOR,
containing_type=None,
+ create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='key', full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry.key', index=0,
@@ -192,14 +286,14 @@
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='value', full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry.value', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
@@ -212,8 +306,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=723,
- serialized_end=775,
+ serialized_start=950,
+ serialized_end=1002,
)
_OTAMETADATA = _descriptor.Descriptor(
@@ -222,6 +316,7 @@
filename=None,
file=DESCRIPTOR,
containing_type=None,
+ create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='type', full_name='build.tools.releasetools.OtaMetadata.type', index=0,
@@ -229,56 +324,63 @@
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='wipe', full_name='build.tools.releasetools.OtaMetadata.wipe', index=1,
number=2, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='downgrade', full_name='build.tools.releasetools.OtaMetadata.downgrade', index=2,
number=3, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='property_files', full_name='build.tools.releasetools.OtaMetadata.property_files', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='precondition', full_name='build.tools.releasetools.OtaMetadata.precondition', index=4,
number=5, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='postcondition', full_name='build.tools.releasetools.OtaMetadata.postcondition', index=5,
number=6, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='retrofit_dynamic_partitions', full_name='build.tools.releasetools.OtaMetadata.retrofit_dynamic_partitions', index=6,
number=7, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='required_cache', full_name='build.tools.releasetools.OtaMetadata.required_cache', index=7,
number=8, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='apex_info', full_name='build.tools.releasetools.OtaMetadata.apex_info', index=8,
+ number=9, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
@@ -292,19 +394,23 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=348,
- serialized_end=829,
+ serialized_start=520,
+ serialized_end=1056,
)
_DEVICESTATE.fields_by_name['partition_state'].message_type = _PARTITIONSTATE
+_APEXMETADATA.fields_by_name['apex_info'].message_type = _APEXINFO
_OTAMETADATA_PROPERTYFILESENTRY.containing_type = _OTAMETADATA
_OTAMETADATA.fields_by_name['type'].enum_type = _OTAMETADATA_OTATYPE
_OTAMETADATA.fields_by_name['property_files'].message_type = _OTAMETADATA_PROPERTYFILESENTRY
_OTAMETADATA.fields_by_name['precondition'].message_type = _DEVICESTATE
_OTAMETADATA.fields_by_name['postcondition'].message_type = _DEVICESTATE
+_OTAMETADATA.fields_by_name['apex_info'].message_type = _APEXINFO
_OTAMETADATA_OTATYPE.containing_type = _OTAMETADATA
DESCRIPTOR.message_types_by_name['PartitionState'] = _PARTITIONSTATE
DESCRIPTOR.message_types_by_name['DeviceState'] = _DEVICESTATE
+DESCRIPTOR.message_types_by_name['ApexInfo'] = _APEXINFO
+DESCRIPTOR.message_types_by_name['ApexMetadata'] = _APEXMETADATA
DESCRIPTOR.message_types_by_name['OtaMetadata'] = _OTAMETADATA
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@@ -322,6 +428,20 @@
})
_sym_db.RegisterMessage(DeviceState)
+ApexInfo = _reflection.GeneratedProtocolMessageType('ApexInfo', (_message.Message,), {
+ 'DESCRIPTOR' : _APEXINFO,
+ '__module__' : 'ota_metadata_pb2'
+ # @@protoc_insertion_point(class_scope:build.tools.releasetools.ApexInfo)
+ })
+_sym_db.RegisterMessage(ApexInfo)
+
+ApexMetadata = _reflection.GeneratedProtocolMessageType('ApexMetadata', (_message.Message,), {
+ 'DESCRIPTOR' : _APEXMETADATA,
+ '__module__' : 'ota_metadata_pb2'
+ # @@protoc_insertion_point(class_scope:build.tools.releasetools.ApexMetadata)
+ })
+_sym_db.RegisterMessage(ApexMetadata)
+
OtaMetadata = _reflection.GeneratedProtocolMessageType('OtaMetadata', (_message.Message,), {
'PropertyFilesEntry' : _reflection.GeneratedProtocolMessageType('PropertyFilesEntry', (_message.Message,), {
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index e8674b6..890cb51 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -444,6 +444,23 @@
return data
+def IsBuildPropFile(filename):
+ return filename in (
+ "SYSTEM/etc/prop.default",
+ "BOOT/RAMDISK/prop.default",
+ "RECOVERY/RAMDISK/prop.default",
+
+ "VENDOR_BOOT/RAMDISK/default.prop",
+ "VENDOR_BOOT/RAMDISK/prop.default",
+
+ # ROOT/default.prop is a legacy path, but may still exist for upgrading
+ # devices that don't support `property_overrides_split_enabled`.
+ "ROOT/default.prop",
+
+ # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
+ # as a symlink in the current code. So it's a no-op here. Keeping the
+ # path here for clarity.
+ "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
apk_keys, apex_keys, key_passwords,
@@ -534,33 +551,7 @@
continue
# System properties.
- elif filename in (
- "SYSTEM/build.prop",
-
- "VENDOR/build.prop",
- "SYSTEM/vendor/build.prop",
-
- "ODM/etc/build.prop",
- "VENDOR/odm/etc/build.prop",
-
- "PRODUCT/build.prop",
- "SYSTEM/product/build.prop",
-
- "SYSTEM_EXT/build.prop",
- "SYSTEM/system_ext/build.prop",
-
- "SYSTEM/etc/prop.default",
- "BOOT/RAMDISK/prop.default",
- "RECOVERY/RAMDISK/prop.default",
-
- # ROOT/default.prop is a legacy path, but may still exist for upgrading
- # devices that don't support `property_overrides_split_enabled`.
- "ROOT/default.prop",
-
- # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
- # as a symlink in the current code. So it's a no-op here. Keeping the
- # path here for clarity.
- "RECOVERY/RAMDISK/default.prop"):
+ elif IsBuildPropFile(filename):
print("Rewriting %s:" % (filename,))
if stat.S_ISLNK(info.external_attr >> 16):
new_data = data
@@ -588,12 +579,7 @@
# Don't copy OTA certs if we're replacing them.
# Replacement of update-payload-key.pub.pem was removed in b/116660991.
- elif (
- OPTIONS.replace_ota_keys and
- filename in (
- "BOOT/RAMDISK/system/etc/security/otacerts.zip",
- "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
- "SYSTEM/etc/security/otacerts.zip")):
+ elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
pass
# Skip META/misc_info.txt since we will write back the new values later.
@@ -626,6 +612,10 @@
elif filename in ["META/care_map.pb", "META/care_map.txt"]:
pass
+ # Skip apex_info.pb because we sign/modify apexes
+ elif filename == "META/apex_info.pb":
+ pass
+
# Updates system_other.avbpubkey in /product/etc/.
elif filename in (
"PRODUCT/etc/security/avb/system_other.avbpubkey",
@@ -857,21 +847,12 @@
print("META/otakeys.txt has no keys; using %s for OTA package"
" verification." % (mapped_keys[0],))
- # recovery now uses the same x509.pem version of the keys.
- # extra_recovery_keys are used only in recovery.
- if misc_info.get("recovery_as_boot") == "true":
- recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
- else:
- recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
-
- WriteOtacerts(output_tf_zip, recovery_keys_location,
- mapped_keys + extra_recovery_keys)
-
- # SystemUpdateActivity uses the x509.pem version of the keys, but
- # put into a zipfile system/etc/security/otacerts.zip.
- # We DO NOT include the extra_recovery_keys (if any) here.
- WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
-
+ otacerts = [info
+ for info in input_tf_zip.infolist()
+ if info.filename.endswith("/otacerts.zip")]
+ for info in otacerts:
+ print("Rewriting OTA key:", info.filename, mapped_keys)
+ WriteOtacerts(output_tf_zip, info.filename, mapped_keys)
def ReplaceVerityPublicKey(output_zip, filename, key_path):
diff --git a/tools/releasetools/test_sign_apex.py b/tools/releasetools/test_sign_apex.py
index 82f5938..646b04d 100644
--- a/tools/releasetools/test_sign_apex.py
+++ b/tools/releasetools/test_sign_apex.py
@@ -57,3 +57,17 @@
False,
apk_keys)
self.assertTrue(os.path.exists(signed_test_apex))
+
+ @test_utils.SkipIfExternalToolsUnavailable()
+ def test_SignCompressedApexFile(self):
+ apex = os.path.join(test_utils.get_current_dir(), 'com.android.apex.compressed.v1.capex')
+ payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+ container_key = os.path.join(self.testdata_dir, 'testkey')
+ signed_apex = sign_apex.SignApexFile(
+ 'avbtool',
+ apex,
+ payload_key,
+ container_key,
+ False,
+ codename_to_api_level_map={'S': 31})
+ self.assertTrue(os.path.exists(signed_apex))
diff --git a/tools/test_extract_kernel.py b/tools/test_extract_kernel.py
index 1a1cfcb..002e387 100644
--- a/tools/test_extract_kernel.py
+++ b/tools/test_extract_kernel.py
@@ -15,16 +15,16 @@
# limitations under the License.
import unittest
-from extract_kernel import get_version, dump_version
+from extract_kernel import dump_version
class ExtractKernelTest(unittest.TestCase):
def test_extract_version(self):
- self.assertEqual("4.9.100", get_version(
- b'Linux version 4.9.100-a123 (a@a) (a) a\n\x00', 0))
- self.assertEqual("4.9.123", get_version(
- b'Linux version 4.9.123 (@) () \n\x00', 0))
+ self.assertEqual("4.9.100", dump_version(
+ b'Linux version 4.9.100-a123 (a@a) (a) a\n\x00'))
+ self.assertEqual("4.9.123", dump_version(
+ b'Linux version 4.9.123 (@) () \n\x00'))
def test_dump_self(self):
self.assertEqual("4.9.1", dump_version(
b"trash\x00Linux version 4.8.8\x00trash\x00"
- "other trash Linux version 4.9.1-g3 (2@s) (2) a\n\x00"))
+ b"other trash Linux version 4.9.1-g3 (2@s) (2) a\n\x00"))