From 0e97dbb8ca459c427f2f194d5796d49a14fa138e Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 17 Apr 2019 14:28:52 -0700 Subject: [PATCH] Add BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE flag. When set, product-img-tag.zip contains super.img instead of individual user images from target files. For virtual devices, super.img is needed to boot the device, but individual user images aren't needed. Test: on A/B DAP, with flag set: - m updatepackage and look at img.zip - img_from_target_files both have super.img and not system / vendor / system_other Test: on non-A/B DAP, with the flag set: - m updatepackage and look at img.zip - img_from_target_files both have super.img and not system / vendor Test: on A/B retrofit, with the flag set: - m updatepackage and look at img.zip - img_from_target_files both have super_*.img and system_other.img, but not system / vendor Bug: 113175337 Change-Id: I94e33091d0c837cae40776176b4dcfdd338aba90 --- core/Makefile | 69 +++++++---- tools/releasetools/img_from_target_files.py | 122 +++++++++++++++++--- 2 files changed, 152 insertions(+), 39 deletions(-) diff --git a/core/Makefile b/core/Makefile index 603ad109b7..c7f1fa4fca 100644 --- a/core/Makefile +++ b/core/Makefile @@ -3793,6 +3793,8 @@ define dump-dynamic-partitions-info echo "super_$(group)_partition_list=$(BOARD_$(call to-upper,$(group))_PARTITION_LIST)" >> $(1);)) $(if $(filter true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED)), \ echo "build_non_sparse_super_partition=true" >> $(1)) + $(if $(filter true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)), \ + echo "super_image_in_update_package=true" >> $(1)) endef # By conditionally including the dependency of the target files package on the @@ -4306,25 +4308,6 @@ endif # BOARD_BUILD_RETROFIT_DYNAMIC_PARTITIONS_OTA_PACKAGE endif # build_ota_package -# ----------------------------------------------------------------- -# The update package - -name := $(TARGET_PRODUCT) -ifeq ($(TARGET_BUILD_TYPE),debug) - name := $(name)_debug -endif -name := $(name)-img-$(FILE_NAME_TAG) - -INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip - -$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(ZIP2ZIP) - @echo "Package: $@" - $(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \ - OTA/android-info.txt:android-info.txt "IMAGES/*.img:." - -.PHONY: updatepackage -updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET) - # ----------------------------------------------------------------- # A zip of the appcompat directory containing logs APPCOMPAT_ZIP := $(PRODUCT_OUT)/appcompat.zip @@ -4346,7 +4329,6 @@ $(APPCOMPAT_ZIP): $(SOONG_ZIP) $(hide) find $(PRODUCT_OUT)/appcompat | sort >$(PRIVATE_LIST_FILE) $(hide) $(SOONG_ZIP) -d -o $@ -C $(PRODUCT_OUT)/appcompat -l $(PRIVATE_LIST_FILE) - # ----------------------------------------------------------------- # A zip of the symbols directory. Keep the full paths to make it # more obvious where these files came from. @@ -4495,7 +4477,10 @@ $(INTERNAL_SUPERIMAGE_DIST_TARGET): $(LPMAKE) $(BUILT_TARGET_FILES_PACKAGE) $(BU PATH=$(dir $(LPMAKE)):$$PATH \ $(BUILD_SUPER_IMAGE) -v $(extracted_input_target_files) $@ +# Skip packing it in dist package because it is in update package. +ifneq (true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)) $(call dist-for-goals,dist_files,$(INTERNAL_SUPERIMAGE_DIST_TARGET)) +endif .PHONY: superimage_dist superimage_dist: $(INTERNAL_SUPERIMAGE_DIST_TARGET) @@ -4579,6 +4564,50 @@ $(call dist-for-goals,dist_files,$(INSTALLED_SUPERIMAGE_EMPTY_TARGET)) endif # BOARD_SUPER_PARTITION_SIZE != "" endif # PRODUCT_BUILD_SUPER_PARTITION == "true" + +# ----------------------------------------------------------------- +# The update package + +name := $(TARGET_PRODUCT) +ifeq ($(TARGET_BUILD_TYPE),debug) + name := $(name)_debug +endif +name := $(name)-img-$(FILE_NAME_TAG) + +INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip + +$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(ZIP2ZIP) + +ifeq (true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)) +$(INTERNAL_UPDATE_PACKAGE_TARGET): $(INTERNAL_SUPERIMAGE_DIST_TARGET) + @echo "Package: $@" + # Filter out super_empty and images in BOARD_SUPER_PARTITION_PARTITION_LIST. + # Filter out system_other for launch DAP devices because it is in super image. + # Include OTA/super_*.img for retrofit devices and super.img for non-retrofit + # devices. + $(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \ + -x IMAGES/super_empty.img \ + $(foreach partition,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \ + -x IMAGES/$(partition).img) \ + $(if $(filter system, $(BOARD_SUPER_PARTITION_PARTITION_LIST)), \ + $(if $(filter true, $(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)),, \ + -x IMAGES/system_other.img)) \ + $(if $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)), \ + $(foreach device,$(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \ + OTA/super_$(device).img:super_$(device).img)) \ + OTA/android-info.txt:android-info.txt "IMAGES/*.img:." + $(if $(INTERNAL_SUPERIMAGE_DIST_TARGET), zip -q -j -u $@ $(INTERNAL_SUPERIMAGE_DIST_TARGET)) +else +$(INTERNAL_UPDATE_PACKAGE_TARGET): + @echo "Package: $@" + $(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \ + OTA/android-info.txt:android-info.txt "IMAGES/*.img:." +endif # BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE + +.PHONY: updatepackage +updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET) + + # ----------------------------------------------------------------- # dalvik something .PHONY: dalvikfiles diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py index e1105bb362..6165d96d6e 100755 --- a/tools/releasetools/img_from_target_files.py +++ b/tools/releasetools/img_from_target_files.py @@ -22,7 +22,8 @@ Usage: img_from_target_files [flags] input_target_files output_image_zip input_target_files: one of the following: - directory containing extracted target files. It will load info from - OTA/android-info.txt and build the image zipfile using images from IMAGES/. + OTA/android-info.txt, META/misc_info.txt and build the image zipfile using + images from IMAGES/. - target files package. Same as above, but extracts the archive before building the image zipfile. @@ -42,6 +43,7 @@ import sys import zipfile import common +from build_super_image import BuildSuperImage if sys.hexversion < 0x02070000: print("Python 2.7 or newer is required.", file=sys.stderr) @@ -52,13 +54,102 @@ logger = logging.getLogger(__name__) OPTIONS = common.OPTIONS -def CopyInfo(output_zip): +def LoadOptions(input_file): + """ + Load information from input_file to OPTIONS. + + Args: + input_file: A Zipfile instance of input zip file, or path to the directory + of extracted zip. + """ + info = OPTIONS.info_dict = common.LoadInfoDict(input_file) + + OPTIONS.put_super = info.get("super_image_in_update_package") == "true" + OPTIONS.dynamic_partition_list = info.get("dynamic_partition_list", + "").strip().split() + OPTIONS.super_device_list = info.get("super_block_devices", + "").strip().split() + OPTIONS.retrofit_dap = info.get("dynamic_partition_retrofit") == "true" + OPTIONS.build_super = info.get("build_super_partition") == "true" + OPTIONS.sparse_userimages = bool(info.get("extfs_sparse_flag")) + + +def CopyInfo(input_tmp, output_zip): """Copy the android-info.txt file from the input to the output.""" common.ZipWrite( - output_zip, os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"), + output_zip, os.path.join(input_tmp, "OTA", "android-info.txt"), "android-info.txt") +def CopyUserImages(input_tmp, output_zip): + """ + Copy user images from the unzipped input and write to output_zip. + + Args: + input_tmp: path to the unzipped input. + output_zip: a ZipFile instance to write images to. + """ + dynamic_images = [p + ".img" for p in OPTIONS.dynamic_partition_list] + + # Filter out system_other for launch DAP devices because it is in super image. + if not OPTIONS.retrofit_dap and "system" in OPTIONS.dynamic_partition_list: + dynamic_images.append("system_other.img") + + images_path = os.path.join(input_tmp, "IMAGES") + # A target-files zip must contain the images since Lollipop. + assert os.path.exists(images_path) + for image in sorted(os.listdir(images_path)): + if OPTIONS.bootable_only and image not in ("boot.img", "recovery.img"): + continue + if not image.endswith(".img"): + continue + if image == "recovery-two-step.img": + continue + if OPTIONS.put_super: + if image == "super_empty.img": + continue + if image in dynamic_images: + continue + logger.info("writing %s to archive...", os.path.join("IMAGES", image)) + common.ZipWrite(output_zip, os.path.join(images_path, image), image) + + +def WriteSuperImages(input_tmp, output_zip): + """ + Write super images from the unzipped input and write to output_zip. This is + only done if super_image_in_update_package is set to "true". + + - For retrofit dynamic partition devices, copy split super images from target + files package. + - For devices launched with dynamic partitions, build super image from target + files package. + + Args: + input_tmp: path to the unzipped input. + output_zip: a ZipFile instance to write images to. + """ + if not OPTIONS.build_super or not OPTIONS.put_super: + return + + if OPTIONS.retrofit_dap: + # retrofit devices already have split super images under OTA/ + images_path = os.path.join(input_tmp, "OTA") + for device in OPTIONS.super_device_list: + image = "super_%s.img" % device + image_path = os.path.join(images_path, image) + assert os.path.exists(image_path) + logger.info("writing %s to archive...", os.path.join("OTA", image)) + common.ZipWrite(output_zip, image_path, image) + else: + # super image for non-retrofit devices aren't in target files package, + # so build it. + super_file = common.MakeTempFile("super_", ".img") + logger.info("building super image %s...", super_file) + BuildSuperImage(input_tmp, super_file) + logger.info("writing super.img to archive...") + common.ZipWrite(output_zip, super_file, "super.img") + + def main(argv): # This allows modifying the value from inner function. bootable_only_array = [False] @@ -75,7 +166,7 @@ def main(argv): extra_long_opts=["bootable_zip"], extra_option_handler=option_handler) - bootable_only = bootable_only_array[0] + OPTIONS.bootable_only = bootable_only_array[0] if len(args) != 2: common.Usage(__doc__) @@ -89,26 +180,19 @@ def main(argv): OPTIONS.input_tmp = target_files elif zipfile.is_zipfile(target_files): logger.info("Building image zip from target files zip.") - OPTIONS.input_tmp = common.UnzipTemp(args[0], ["IMAGES/*", "OTA/*"]) + OPTIONS.input_tmp = common.UnzipTemp(target_files, + ["IMAGES/*", "OTA/*", "META/*"]) else: raise ValueError("%s is not a valid path." % target_files) - output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) - CopyInfo(output_zip) + LoadOptions(OPTIONS.input_tmp) + output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED, + allowZip64=not OPTIONS.sparse_userimages) try: - images_path = os.path.join(OPTIONS.input_tmp, "IMAGES") - # A target-files zip must contain the images since Lollipop. - assert os.path.exists(images_path) - for image in sorted(os.listdir(images_path)): - if bootable_only and image not in ("boot.img", "recovery.img"): - continue - if not image.endswith(".img"): - continue - if image == "recovery-two-step.img": - continue - common.ZipWrite(output_zip, os.path.join(images_path, image), image) - + CopyInfo(OPTIONS.input_tmp, output_zip) + CopyUserImages(OPTIONS.input_tmp, output_zip) + WriteSuperImages(OPTIONS.input_tmp, output_zip) finally: logger.info("cleaning up...") common.ZipClose(output_zip)