Merge "Add sepolicy compat versions to soong config"
diff --git a/core/Makefile b/core/Makefile
index 26ed864..ea5fc49 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -527,16 +527,6 @@
$(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,GENERIC_RAMDISK,$(TARGET_RAMDISK_OUT),,modules.load,,$(kmd)))))
# -----------------------------------------------------------------
-# FSVerity metadata generation
-ifeq ($(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA),true)
-
-FSVERITY_APK_KEY_PATH := $(DEFAULT_SYSTEM_DEV_CERTIFICATE)
-FSVERITY_APK_OUT := system/etc/security/fsverity/BuildManifest.apk
-FSVERITY_APK_MANIFEST_PATH := system/security/fsverity/AndroidManifest.xml
-
-endif # PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA
-
-# -----------------------------------------------------------------
# Cert-to-package mapping. Used by the post-build signing tools.
# Use a macro to add newline to each echo command
# $1 stem name of the package
@@ -1744,11 +1734,6 @@
$(if $(filter $(2),system),\
$(if $(INTERNAL_SYSTEM_OTHER_PARTITION_SIZE),$(hide) echo "system_other_size=$(INTERNAL_SYSTEM_OTHER_PARTITION_SIZE)" >> $(1))
$(if $(PRODUCT_SYSTEM_HEADROOM),$(hide) echo "system_headroom=$(PRODUCT_SYSTEM_HEADROOM)" >> $(1))
- $(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity=$(HOST_OUT_EXECUTABLES)/fsverity" >> $(1))
- $(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_generate_metadata=true" >> $(1))
- $(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_key=$(FSVERITY_APK_KEY_PATH)" >> $(1))
- $(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_manifest=$(FSVERITY_APK_MANIFEST_PATH)" >> $(1))
- $(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_out=$(FSVERITY_APK_OUT)" >> $(1))
$(call add-common-ro-flags-to-image-props,system,$(1))
)
$(if $(filter $(2),system_other),\
@@ -2765,6 +2750,56 @@
# -----------------------------------------------------------------
# system image
+# FSVerity metadata generation
+# Generate fsverity metadata files (.fsv_meta) and build manifest
+# (system/etc/security/fsverity/BuildManifest.apk) BEFORE filtering systemimage files below
+ifeq ($(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA),true)
+
+# Generate fsv_meta
+fsverity-metadata-targets := $(sort $(filter \
+ $(TARGET_OUT)/framework/%.jar \
+ $(foreach arch,$(TARGET_ARCH) $(TARGET_2ND_ARCH),$(foreach ext,oat vdex art, \
+ $(TARGET_OUT)/framework/oat/$(arch)/%.$(ext))) \
+ $(TARGET_OUT)/etc/boot-image.prof \
+ $(TARGET_OUT)/etc/dirty-image-objects \
+ $(TARGET_OUT)/etc/updatable-bcp-packages.txt, \
+ $(ALL_GENERATED_SOURCES) $(ALL_DEFAULT_INSTALLED_MODULES)))
+
+define fsverity-generate-metadata
+$(1).fsv_meta: PRIVATE_SRC := $(1)
+$(1).fsv_meta: PRIVATE_FSVERITY := $(HOST_OUT_EXECUTABLES)/fsverity
+$(1).fsv_meta: $(HOST_OUT_EXECUTABLES)/fsverity_metadata_generator $(HOST_OUT_EXECUTABLES)/fsverity $(1)
+ $$< --fsverity-path $$(PRIVATE_FSVERITY) --signature none \
+ --hash-alg sha256 --output $$@ $$(PRIVATE_SRC)
+endef
+
+$(foreach f,$(fsverity-metadata-targets),$(eval $(call fsverity-generate-metadata,$(f))))
+ALL_DEFAULT_INSTALLED_MODULES += $(addsuffix .fsv_meta,$(fsverity-metadata-targets))
+
+# Generate BuildManifest.apk
+FSVERITY_APK_KEY_PATH := $(DEFAULT_SYSTEM_DEV_CERTIFICATE)
+FSVERITY_APK_OUT := $(TARGET_OUT)/etc/security/fsverity/BuildManifest.apk
+FSVERITY_APK_MANIFEST_PATH := system/security/fsverity/AndroidManifest.xml
+$(FSVERITY_APK_OUT): PRIVATE_FSVERITY := $(HOST_OUT_EXECUTABLES)/fsverity
+$(FSVERITY_APK_OUT): PRIVATE_AAPT2 := $(HOST_OUT_EXECUTABLES)/aapt2
+$(FSVERITY_APK_OUT): PRIVATE_APKSIGNER := $(HOST_OUT_EXECUTABLES)/apksigner
+$(FSVERITY_APK_OUT): PRIVATE_MANIFEST := $(FSVERITY_APK_MANIFEST_PATH)
+$(FSVERITY_APK_OUT): PRIVATE_KEY := $(FSVERITY_APK_KEY_PATH)
+$(FSVERITY_APK_OUT): PRIVATE_INPUTS := $(fsverity-metadata-targets)
+$(FSVERITY_APK_OUT): $(HOST_OUT_EXECUTABLES)/fsverity_manifest_generator \
+ $(HOST_OUT_EXECUTABLES)/fsverity $(HOST_OUT_EXECUTABLES)/aapt2 \
+ $(HOST_OUT_EXECUTABLES)/apksigner $(FSVERITY_APK_MANIFEST_PATH) \
+ $(FSVERITY_APK_KEY_PATH).x509.pem $(FSVERITY_APK_KEY_PATH).pk8 \
+ $(fsverity-metadata-targets)
+ $< --fsverity-path $(PRIVATE_FSVERITY) --aapt2-path $(PRIVATE_AAPT2) \
+ --apksigner-path $(PRIVATE_APKSIGNER) --apk-key-path $(PRIVATE_KEY) \
+ --apk-manifest-path $(PRIVATE_MANIFEST) --output $@ \
+ --base-dir $(PRODUCT_OUT) $(PRIVATE_INPUTS)
+
+ALL_DEFAULT_INSTALLED_MODULES += $(FSVERITY_APK_OUT)
+
+endif # PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA
+
INTERNAL_SYSTEMIMAGE_FILES := $(sort $(filter $(TARGET_OUT)/%, \
$(ALL_GENERATED_SOURCES) \
$(ALL_DEFAULT_INSTALLED_MODULES)))
@@ -2864,10 +2899,6 @@
ifeq ($(BOARD_AVB_ENABLE),true)
$(BUILT_SYSTEMIMAGE): $(BOARD_AVB_SYSTEM_KEY_PATH)
endif
-ifeq ($(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA),true)
-$(BUILT_SYSTEMIMAGE): $(HOST_OUT_EXECUTABLES)/fsverity $(HOST_OUT_EXECUTABLES)/aapt2 $(HOST_OUT_EXECUTABLES)/apksigner \
- $(FSVERITY_APK_MANIFEST_PATH) $(FSVERITY_APK_KEY_PATH).x509.pem $(FSVERITY_APK_KEY_PATH).pk8
-endif
$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE)
$(call build-systemimage-target,$@)
@@ -4953,6 +4984,10 @@
# image.
ifdef BUILDING_SYSTEM_IMAGE
$(BUILT_TARGET_FILES_PACKAGE): $(FULL_SYSTEMIMAGE_DEPS)
+else
+ # releasetools may need the system build.prop even when building a
+ # system-image-less product.
+ $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_BUILD_PROP_TARGET)
endif
ifdef BUILDING_USERDATA_IMAGE
@@ -5199,6 +5234,12 @@
@# Contents of the system image
$(hide) $(call package_files-copy-root, \
$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
+else ifdef INSTALLED_BUILD_PROP_TARGET
+ @# Copy the system build.prop even if not building a system image
+ @# because add_img_to_target_files may need it to build other partition
+ @# images.
+ $(hide) mkdir -p "$(zip_root)/SYSTEM"
+ $(hide) cp "$(INSTALLED_BUILD_PROP_TARGET)" "$(patsubst $(TARGET_OUT)/%,$(zip_root)/SYSTEM/%,$(INSTALLED_BUILD_PROP_TARGET))"
endif
ifdef BUILDING_USERDATA_IMAGE
@# Contents of the data image
@@ -5338,7 +5379,7 @@
$(hide) cp $(INSTALLED_INIT_BOOT_IMAGE_TARGET) $(zip_root)/PREBUILT_IMAGES/
endif
ifndef BOARD_PREBUILT_BOOTIMAGE
-ifneq (,$(INTERNAL_PREBUILT_BOOTIMAGE) $(filter true,$(BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES)))
+ifneq (,$(strip $(INTERNAL_PREBUILT_BOOTIMAGE) $(filter true,$(BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES))))
ifdef INSTALLED_BOOTIMAGE_TARGET
$(hide) mkdir -p $(zip_root)/IMAGES
$(hide) cp $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/IMAGES/
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 8a5440f..cec7792 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -981,6 +981,18 @@
ALL_MODULES.$(my_register_name).SYSTEM_SHARED_LIBS := \
$(ALL_MODULES.$(my_register_name).SYSTEM_SHARED_LIBS) $(LOCAL_SYSTEM_SHARED_LIBRARIES)
+ifdef LOCAL_TEST_DATA
+ # Export the list of targets that are handled as data inputs and required
+ # by tests at runtime. The LOCAL_TEST_DATA format is generated from below
+ # https://cs.android.com/android/platform/superproject/+/master:build/soong/android/androidmk.go;l=925-944;drc=master
+ # which format is like $(path):$(relative_file) but for module-info, only
+ # the string after ":" is needed.
+ ALL_MODULES.$(my_register_name).TEST_DATA := \
+ $(strip $(ALL_MODULES.$(my_register_name).TEST_DATA) \
+ $(foreach f, $(LOCAL_TEST_DATA),\
+ $(call word-colon,2,$(f))))
+endif
+
##########################################################################
## When compiling against the VNDK, add the .vendor or .product suffix to
## required modules.
diff --git a/core/product.mk b/core/product.mk
index b069dda..7192226 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -445,7 +445,7 @@
# Install a copy of the debug policy to the system_ext partition, and allow
# init-second-stage to load debug policy from system_ext.
-# This option is only meant to be set by GSI products.
+# This option is only meant to be set by compliance GSI targets.
_product_single_value_vars += PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT
# If set, metadata files for the following artifacts will be generated.
diff --git a/core/product_config.mk b/core/product_config.mk
index 57b7724..6fae73e 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -420,9 +420,15 @@
$(error Only one file may be in PRODUCT_ADB_KEYS: $(PRODUCT_ADB_KEYS))
endif
+# Show a warning wall of text if non-compliance-GSI products set this option.
ifdef PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT
- ifeq (,$(filter gsi_arm gsi_arm64 gsi_x86 gsi_x86_64,$(PRODUCT_NAME)))
- $(error Only GSI products are allowed to set PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT)
+ ifeq (,$(filter gsi_arm gsi_arm64 gsi_x86 gsi_x86_64 gsi_car_arm64 gsi_car_x86_64,$(PRODUCT_NAME)))
+ $(warning PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT is set but \
+ PRODUCT_NAME ($(PRODUCT_NAME)) doesn't look like a GSI for compliance \
+ testing. This is a special configuration for compliance GSI, so do make \
+ sure you understand the security implications before setting this \
+ option. If you don't know what this option does, then you probably \
+ shouldn't set this.)
endif
endif
diff --git a/core/tasks/module-info.mk b/core/tasks/module-info.mk
index 5d5bfa8..aeeb403 100644
--- a/core/tasks/module-info.mk
+++ b/core/tasks/module-info.mk
@@ -23,6 +23,7 @@
'"classes_jar": [$(foreach w,$(sort $(ALL_MODULES.$(m).CLASSES_JAR)),"$(w)", )], ' \
'"test_mainline_modules": [$(foreach w,$(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES)),"$(w)", )], ' \
'"is_unit_test": "$(ALL_MODULES.$(m).IS_UNIT_TEST)", ' \
+ '"data": [$(foreach w,$(sort $(ALL_MODULES.$(m).TEST_DATA)),"$(w)", )], ' \
'},\n' \
) | sed -e 's/, *\]/]/g' -e 's/, *\}/ }/g' -e '$$s/,$$//' >> $@
$(hide) echo '}' >> $@
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index bf19c5c..051de62 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -85,7 +85,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-12-05
+ PLATFORM_SECURITY_PATCH := 2022-01-05
endif
.KATI_READONLY := PLATFORM_SECURITY_PATCH
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index 94aaea0..3cad6f1 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -56,9 +56,11 @@
VNDK-SP: libutils.so
VNDK-SP: libutilscallstack.so
VNDK-SP: libz.so
+VNDK-core: android.hardware.audio.common-V1-ndk.so
VNDK-core: android.hardware.audio.common@2.0.so
VNDK-core: android.hardware.authsecret-V1-ndk.so
VNDK-core: android.hardware.automotive.occupant_awareness-V1-ndk.so
+VNDK-core: android.hardware.bluetooth.audio-V1-ndk.so
VNDK-core: android.hardware.configstore-utils.so
VNDK-core: android.hardware.configstore@1.0.so
VNDK-core: android.hardware.configstore@1.1.so
@@ -104,6 +106,7 @@
VNDK-core: android.hardware.wifi.supplicant-V1-ndk.so
VNDK-core: android.hidl.token@1.0-utils.so
VNDK-core: android.hidl.token@1.0.so
+VNDK-core: android.media.audio.common.types-V1-ndk.so
VNDK-core: android.system.keystore2-V1-ndk.so
VNDK-core: android.system.suspend-V1-ndk.so
VNDK-core: android.system.suspend@1.0.so
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index bf7f9a0..f3123b2 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -554,12 +554,25 @@
}
python_binary_host {
- name: "fsverity_metadata_generator",
+ name: "fsverity_manifest_generator",
srcs: [
- "fsverity_metadata_generator.py",
+ "fsverity_manifest_generator.py",
],
libs: [
"fsverity_digests_proto_python",
+ "releasetools_common",
+ ],
+ required: [
+ "aapt2",
+ "apksigner",
+ "fsverity",
+ ],
+}
+
+python_binary_host {
+ name: "fsverity_metadata_generator",
+ srcs: [
+ "fsverity_metadata_generator.py",
],
required: [
"fsverity",
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 34aa1a6..a4377c7 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -35,9 +35,6 @@
import common
import verity_utils
-from fsverity_digests_pb2 import FSVerityDigests
-from fsverity_metadata_generator import FSVerityMetadataGenerator
-
logger = logging.getLogger(__name__)
OPTIONS = common.OPTIONS
@@ -451,69 +448,6 @@
return mkfs_output
-def GenerateFSVerityMetadata(in_dir, fsverity_path, apk_key_path, apk_manifest_path, apk_out_path):
- """Generates fsverity metadata files.
-
- By setting PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA := true, fsverity
- metadata files will be generated. For the input files, see `patterns` below.
-
- One metadata file per one input file will be generated with the suffix
- .fsv_meta. e.g. system/framework/foo.jar -> system/framework/foo.jar.fsv_meta
- Also a mapping file containing fsverity digests will be generated to
- system/etc/security/fsverity/BuildManifest.apk.
-
- Args:
- in_dir: temporary working directory (same as BuildImage)
- fsverity_path: path to host tool fsverity
- apk_key_path: path to key (e.g. build/make/target/product/security/platform)
- apk_manifest_path: path to AndroidManifest.xml for APK
- apk_out_path: path to the output APK
-
- Returns:
- None. The files are generated directly under in_dir.
- """
-
- patterns = [
- "system/framework/*.jar",
- "system/framework/oat/*/*.oat",
- "system/framework/oat/*/*.vdex",
- "system/framework/oat/*/*.art",
- "system/etc/boot-image.prof",
- "system/etc/dirty-image-objects",
- ]
- files = []
- for pattern in patterns:
- files += glob.glob(os.path.join(in_dir, pattern))
- files = sorted(set(files))
-
- generator = FSVerityMetadataGenerator(fsverity_path)
- generator.set_hash_alg("sha256")
-
- digests = FSVerityDigests()
- for f in files:
- generator.generate(f)
- # f is a full path for now; make it relative so it starts with {mount_point}/
- digest = digests.digests[os.path.relpath(f, in_dir)]
- digest.digest = generator.digest(f)
- digest.hash_alg = "sha256"
-
- temp_dir = common.MakeTempDir()
-
- os.mkdir(os.path.join(temp_dir, "assets"))
- metadata_path = os.path.join(temp_dir, "assets", "build_manifest")
- with open(metadata_path, "wb") as f:
- f.write(digests.SerializeToString())
-
- apk_path = os.path.join(in_dir, apk_out_path)
-
- common.RunAndCheckOutput(["aapt2", "link",
- "-A", os.path.join(temp_dir, "assets"),
- "-o", apk_path,
- "--manifest", apk_manifest_path])
- common.RunAndCheckOutput(["apksigner", "sign", "--in", apk_path,
- "--cert", apk_key_path + ".x509.pem",
- "--key", apk_key_path + ".pk8"])
-
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
"""Builds an image for the files under in_dir and writes it to out_file.
@@ -541,13 +475,6 @@
elif fs_type.startswith("f2fs") and prop_dict.get("f2fs_compress") == "true":
fs_spans_partition = False
- if "fsverity_generate_metadata" in prop_dict:
- GenerateFSVerityMetadata(in_dir,
- fsverity_path=prop_dict["fsverity"],
- apk_key_path=prop_dict["fsverity_apk_key"],
- apk_manifest_path=prop_dict["fsverity_apk_manifest"],
- apk_out_path=prop_dict["fsverity_apk_out"])
-
# Get a builder for creating an image that's to be verified by Verified Boot,
# or None if not applicable.
verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict)
@@ -801,11 +728,6 @@
copy_prop("system_root_image", "system_root_image")
copy_prop("root_dir", "root_dir")
copy_prop("root_fs_config", "root_fs_config")
- copy_prop("fsverity", "fsverity")
- copy_prop("fsverity_generate_metadata", "fsverity_generate_metadata")
- copy_prop("fsverity_apk_key","fsverity_apk_key")
- copy_prop("fsverity_apk_manifest","fsverity_apk_manifest")
- copy_prop("fsverity_apk_out","fsverity_apk_out")
elif mount_point == "data":
# Copy the generic fs type first, override with specific one if available.
copy_prop("flash_logical_block_size", "flash_logical_block_size")
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 6ec1b94..30dcf5b 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -73,6 +73,7 @@
self.search_path = os.environ["ANDROID_HOST_OUT"]
self.signapk_shared_library_path = "lib64" # Relative to search_path
self.extra_signapk_args = []
+ self.aapt2_path = "aapt2"
self.java_path = "java" # Use the one on the path by default.
self.java_args = ["-Xmx2048m"] # The default JVM args.
self.android_jar_path = None
@@ -1699,8 +1700,8 @@
Args:
image_path: The full path of the image, e.g., /path/to/boot.img.
prebuilt_name: The prebuilt image name, e.g., boot.img, boot-5.4-gz.img,
- boot-5.10.img, recovery.img.
- partition_name: The partition name, e.g., 'boot' or 'recovery'.
+ boot-5.10.img, recovery.img or init_boot.img.
+ partition_name: The partition name, e.g., 'boot', 'init_boot' or 'recovery'.
info_dict: The information dict read from misc_info.txt.
"""
if info_dict is None:
@@ -1724,6 +1725,35 @@
RunAndCheckOutput(cmd)
+def HasRamdisk(partition_name, info_dict=None):
+ """Returns true/false to see if a bootable image should have a ramdisk.
+
+ Args:
+ partition_name: The partition name, e.g., 'boot', 'init_boot' or 'recovery'.
+ info_dict: The information dict read from misc_info.txt.
+ """
+ if info_dict is None:
+ info_dict = OPTIONS.info_dict
+
+ if partition_name != "boot":
+ return True # init_boot.img or recovery.img has a ramdisk.
+
+ if info_dict.get("recovery_as_boot") == "true":
+ return True # the recovery-as-boot boot.img has a RECOVERY ramdisk.
+
+ if info_dict.get("system_root_image") == "true":
+ # The ramdisk content is merged into the system.img, so there is NO
+ # ramdisk in the boot.img or boot-<kernel version>.img.
+ return False
+
+ if info_dict.get("init_boot") == "true":
+ # The ramdisk is moved to the init_boot.img, so there is NO
+ # ramdisk in the boot.img or boot-<kernel version>.img.
+ return False
+
+ return True
+
+
def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir,
info_dict=None, two_step_image=False):
"""Return a File object with the desired bootable image.
@@ -1745,25 +1775,18 @@
logger.info("using prebuilt %s from IMAGES...", prebuilt_name)
return File.FromLocalFile(name, prebuilt_path)
+ partition_name = tree_subdir.lower()
prebuilt_path = os.path.join(unpack_dir, "PREBUILT_IMAGES", prebuilt_name)
if os.path.exists(prebuilt_path):
logger.info("Re-signing prebuilt %s from PREBUILT_IMAGES...", prebuilt_name)
signed_img = MakeTempFile()
shutil.copy(prebuilt_path, signed_img)
- partition_name = tree_subdir.lower()
_SignBootableImage(signed_img, prebuilt_name, partition_name, info_dict)
return File.FromLocalFile(name, signed_img)
logger.info("building image from target_files %s...", tree_subdir)
- # With system_root_image == "true", we don't pack ramdisk into the boot image.
- # With init_boot == "true", we don't pack the ramdisk into boot.img.
- # Unless "recovery_as_boot" is specified, in which case we carry the ramdisk
- # for recovery.
- has_ramdisk = ((info_dict.get("system_root_image") != "true" and
- info_dict.get("init_boot") != "true") or
- prebuilt_name != "boot.img" or
- info_dict.get("recovery_as_boot") == "true")
+ has_ramdisk = HasRamdisk(partition_name, info_dict)
fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
data = _BuildBootableImage(prebuilt_name, os.path.join(unpack_dir, tree_subdir),
@@ -2162,8 +2185,8 @@
def GetMinSdkVersion(apk_name):
"""Gets the minSdkVersion declared in the APK.
- It calls 'aapt2' to query the embedded minSdkVersion from the given APK file.
- This can be both a decimal number (API Level) or a codename.
+ It calls OPTIONS.aapt2_path to query the embedded minSdkVersion from the given
+ APK file. This can be both a decimal number (API Level) or a codename.
Args:
apk_name: The APK filename.
@@ -2175,7 +2198,7 @@
ExternalError: On failing to obtain the min SDK version.
"""
proc = Run(
- ["aapt2", "dump", "badging", apk_name], stdout=subprocess.PIPE,
+ [OPTIONS.aapt2_path, "dump", "badging", apk_name], stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdoutdata, stderrdata = proc.communicate()
if proc.returncode != 0:
@@ -2451,7 +2474,7 @@
opts, args = getopt.getopt(
argv, "hvp:s:x:" + extra_opts,
["help", "verbose", "path=", "signapk_path=",
- "signapk_shared_library_path=", "extra_signapk_args=",
+ "signapk_shared_library_path=", "extra_signapk_args=", "aapt2_path=",
"java_path=", "java_args=", "android_jar_path=", "public_key_suffix=",
"private_key_suffix=", "boot_signer_path=", "boot_signer_args=",
"verity_signer_path=", "verity_signer_args=", "device_specific=",
@@ -2475,6 +2498,8 @@
OPTIONS.signapk_shared_library_path = a
elif o in ("--extra_signapk_args",):
OPTIONS.extra_signapk_args = shlex.split(a)
+ elif o in ("--aapt2_path",):
+ OPTIONS.aapt2_path = a
elif o in ("--java_path",):
OPTIONS.java_path = a
elif o in ("--java_args",):
@@ -3870,7 +3895,10 @@
disable_sparse = OPTIONS.info_dict.get(which + "_disable_sparse")
image_blocks = int(image_size) // 4096 - 1
- assert image_blocks > 0, "blocks for {} must be positive".format(which)
+ # It's OK for image_blocks to be 0, because care map ranges are inclusive.
+ # So 0-0 means "just block 0", which is valid.
+ assert image_blocks >= 0, "blocks for {} must be non-negative, image size: {}".format(
+ which, image_size)
# For sparse images, we will only check the blocks that are listed in the care
# map, i.e. the ones with meaningful data.
diff --git a/tools/releasetools/fsverity_manifest_generator.py b/tools/releasetools/fsverity_manifest_generator.py
new file mode 100644
index 0000000..e61e257
--- /dev/null
+++ b/tools/releasetools/fsverity_manifest_generator.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 Google Inc. All rights reserved.
+#
+# 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.
+
+"""
+`fsverity_manifest_generator` generates build manifest APK file containing
+digests of target files. The APK file is signed so the manifest inside the APK
+can be trusted.
+"""
+
+import argparse
+import common
+import os
+import subprocess
+import sys
+from fsverity_digests_pb2 import FSVerityDigests
+
+HASH_ALGORITHM = 'sha256'
+
+def _digest(fsverity_path, input_file):
+ cmd = [fsverity_path, 'digest', input_file]
+ cmd.extend(['--compact'])
+ cmd.extend(['--hash-alg', HASH_ALGORITHM])
+ out = subprocess.check_output(cmd, universal_newlines=True).strip()
+ return bytes(bytearray.fromhex(out))
+
+if __name__ == '__main__':
+ p = argparse.ArgumentParser()
+ p.add_argument(
+ '--output',
+ help='Path to the output manifest APK',
+ required=True)
+ p.add_argument(
+ '--fsverity-path',
+ help='path to the fsverity program',
+ required=True)
+ p.add_argument(
+ '--aapt2-path',
+ help='path to the aapt2 program',
+ required=True)
+ p.add_argument(
+ '--apksigner-path',
+ help='path to the apksigner program',
+ required=True)
+ p.add_argument(
+ '--apk-key-path',
+ help='path to the apk key',
+ required=True)
+ p.add_argument(
+ '--apk-manifest-path',
+ help='path to AndroidManifest.xml',
+ required=True)
+ p.add_argument(
+ '--base-dir',
+ help='directory to use as a relative root for the inputs',
+ required=True)
+ p.add_argument(
+ 'inputs',
+ nargs='+',
+ help='input file for the build manifest')
+ args = p.parse_args(sys.argv[1:])
+
+ digests = FSVerityDigests()
+ for f in sorted(args.inputs):
+ # f is a full path for now; make it relative so it starts with {mount_point}/
+ digest = digests.digests[os.path.relpath(f, args.base_dir)]
+ digest.digest = _digest(args.fsverity_path, f)
+ digest.hash_alg = HASH_ALGORITHM
+
+ temp_dir = common.MakeTempDir()
+
+ os.mkdir(os.path.join(temp_dir, "assets"))
+ metadata_path = os.path.join(temp_dir, "assets", "build_manifest.pb")
+ with open(metadata_path, "wb") as f:
+ f.write(digests.SerializeToString())
+
+ common.RunAndCheckOutput([args.aapt2_path, "link",
+ "-A", os.path.join(temp_dir, "assets"),
+ "-o", args.output,
+ "--manifest", args.apk_manifest_path])
+ common.RunAndCheckOutput([args.apksigner_path, "sign", "--in", args.output,
+ "--cert", args.apk_key_path + ".x509.pem",
+ "--key", args.apk_key_path + ".pk8"])
diff --git a/tools/releasetools/fsverity_metadata_generator.py b/tools/releasetools/fsverity_metadata_generator.py
index a300d2e..fa7cd39 100644
--- a/tools/releasetools/fsverity_metadata_generator.py
+++ b/tools/releasetools/fsverity_metadata_generator.py
@@ -178,6 +178,7 @@
out.write(sig)
else:
out.write(pack('<I', SIG_TYPE_NONE))
+ out.write(pack('<I', 0))
# 4. merkle tree
with open(merkletree_file, 'rb') as f:
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index c21de14..58f0e85 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -230,6 +230,9 @@
--compressor_types
A colon ':' separated list of compressors. Allowed values are bz2 and brotli.
+
+ --enable_zucchini
+ Whether to enable to zucchini feature. Will generate smaller OTA but uses more memory.
"""
from __future__ import print_function
@@ -299,6 +302,7 @@
OPTIONS.enable_vabc_xor = True
OPTIONS.force_minor_version = None
OPTIONS.compressor_types = None
+OPTIONS.enable_zucchini = None
POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
@@ -1141,6 +1145,14 @@
partition_timestamps_flags = GeneratePartitionTimestampFlags(
metadata.postcondition.partition_state)
+ # Auto-check for compatibility only if --enable_zucchini omitted. Otherwise
+ # let user override zucchini settings. This is useful for testing.
+ if OPTIONS.enable_zucchini is None:
+ if not ota_utils.IsZucchiniCompatible(source_file, target_file):
+ additional_args += ["--enable_zucchini", "false"]
+ else:
+ additional_args += ["--enable_zucchini", str(OPTIONS.enable_zucchini).lower()]
+
if OPTIONS.disable_vabc:
additional_args += ["--disable_vabc", "true"]
if OPTIONS.enable_vabc_xor:
@@ -1326,6 +1338,8 @@
OPTIONS.force_minor_version = a
elif o == "--compressor_types":
OPTIONS.compressor_types = a
+ elif o == "--enable_zucchini":
+ OPTIONS.enable_zucchini = a.lower() != "false"
else:
return False
return True
@@ -1373,6 +1387,7 @@
"enable_vabc_xor=",
"force_minor_version=",
"compressor_types=",
+ "enable_zucchin=",
], extra_option_handler=option_handler)
if len(args) != 2:
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 6c5fc05..a4ec9e2 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -638,3 +638,38 @@
target_apex.source_version = source_apex_versions[name]
return target_apex_proto.SerializeToString()
+
+
+def IsZucchiniCompatible(source_file: str, target_file: str):
+ """Check whether zucchini versions in two builds are compatible
+
+ Args:
+ source_file: Path to source build's target_file.zip
+ target_file: Path to target build's target_file.zip
+
+ Returns:
+ bool true if and only if zucchini versions are compatible
+ """
+ if source_file is None or target_file is None:
+ return False
+ assert os.path.exists(source_file)
+ assert os.path.exists(target_file)
+
+ assert zipfile.is_zipfile(source_file) or os.path.isdir(source_file)
+ assert zipfile.is_zipfile(target_file) or os.path.isdir(target_file)
+ _ZUCCHINI_CONFIG_ENTRY_NAME = "META/zucchini_config.txt"
+
+ def ReadEntry(path, entry):
+ # Read an entry inside a .zip file or extracted dir of .zip file
+ if zipfile.is_zipfile(path):
+ with zipfile.ZipFile(path, "r", allowZip64=True) as zfp:
+ if entry in zfp.namelist():
+ return zfp.read(entry).decode()
+ else:
+ entry_path = os.path.join(entry, path)
+ if os.path.exists(entry_path):
+ with open(entry_path, "r") as fp:
+ return fp.read()
+ else:
+ return ""
+ return ReadEntry(source_file, _ZUCCHINI_CONFIG_ENTRY_NAME) == ReadEntry(target_file, _ZUCCHINI_CONFIG_ENTRY_NAME)