diff --git a/core/Makefile b/core/Makefile index 951761ce7..c9741a0a2 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1924,7 +1924,8 @@ endif ifeq (,$(filter true, $(BOARD_USES_FULL_RECOVERY_IMAGE) $(BOARD_USES_RECOVERY_AS_BOOT) \ $(BOARD_BUILD_SYSTEM_ROOT_IMAGE) $(BOARD_INCLUDE_RECOVERY_DTBO) $(BOARD_INCLUDE_RECOVERY_ACPIO))) # Named '.dat' so we don't attempt to use imgdiff for patching it. -RECOVERY_RESOURCE_ZIP := $(TARGET_OUT)/etc/recovery-resource.dat +RECOVERY_RESOURCE_ZIP := $(TARGET_OUT_VENDOR)/etc/recovery-resource.dat +ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_RESOURCE_ZIP) else RECOVERY_RESOURCE_ZIP := endif @@ -2294,8 +2295,7 @@ PDK_FUSION_SYSIMG_FILES := \ INTERNAL_SYSTEMIMAGE_FILES := $(sort $(filter $(TARGET_OUT)/%, \ $(ALL_GENERATED_SOURCES) \ $(ALL_DEFAULT_INSTALLED_MODULES) \ - $(PDK_FUSION_SYSIMG_FILES) \ - $(RECOVERY_RESOURCE_ZIP)) \ + $(PDK_FUSION_SYSIMG_FILES)) \ $(PDK_FUSION_SYMLINK_STAMP)) FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS) @@ -3893,6 +3893,9 @@ endif ifeq ($(BOARD_USES_FULL_RECOVERY_IMAGE),true) $(hide) echo "full_recovery_image=true" >> $@ endif +ifdef BOARD_USES_VENDORIMAGE + $(hide) echo "board_uses_vendorimage=true" >> $@ +endif ifeq ($(BOARD_AVB_ENABLE),true) $(hide) echo "avb_enable=true" >> $@ $(hide) echo "avb_vbmeta_key_path=$(BOARD_AVB_KEY_PATH)" >> $@ @@ -4299,10 +4302,8 @@ ifneq ($(PRODUCT_ODM_BASE_FS_PATH),) $(zip_root)/META/$(notdir $(PRODUCT_ODM_BASE_FS_PATH)) endif ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),) -ifdef BUILDING_SYSTEM_IMAGE $(hide) PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH MKBOOTIMG=$(MKBOOTIMG) \ $(MAKE_RECOVERY_PATCH) $(zip_root) $(zip_root) -endif # BUILDING_SYSTEM_IMAGE endif ifeq ($(AB_OTA_UPDATER),true) @# When using the A/B updater, include the updater config files in the zip. diff --git a/target/product/base_system.mk b/target/product/base_system.mk index ec373dbc9..a8ed28ae8 100644 --- a/target/product/base_system.mk +++ b/target/product/base_system.mk @@ -29,7 +29,6 @@ PRODUCT_PACKAGES += \ android.test.mock \ android.test.runner \ apexd \ - applypatch \ appops \ app_process \ appwidget \ diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk index 9d79e0f06..1657e7112 100644 --- a/target/product/base_vendor.mk +++ b/target/product/base_vendor.mk @@ -75,3 +75,8 @@ PRODUCT_PACKAGES += \ # VINTF data for vendor image PRODUCT_PACKAGES += \ device_compatibility_matrix.xml \ + +# Packages to update the recovery partition, which will be installed on +# /vendor. TODO(b/141648565): Don't install these unless they're needed. +PRODUCT_PACKAGES += \ + applypatch diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py index a5816bc17..1a1f6fd7d 100755 --- a/tools/releasetools/add_img_to_target_files.py +++ b/tools/releasetools/add_img_to_target_files.py @@ -165,9 +165,12 @@ def AddSystem(output_zip, recovery_img=None, boot_img=None): else: common.ZipWrite(output_zip, output_file, arc_name) - if (OPTIONS.rebuild_recovery and recovery_img is not None and - boot_img is not None): - logger.info("Building new recovery patch") + board_uses_vendorimage = OPTIONS.info_dict.get( + "board_uses_vendorimage") == "true" + + if (OPTIONS.rebuild_recovery and not board_uses_vendorimage and + recovery_img is not None and boot_img is not None): + logger.info("Building new recovery patch on system at system/vendor") common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, boot_img, info_dict=OPTIONS.info_dict) @@ -190,7 +193,7 @@ def AddSystemOther(output_zip): CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system_other", img) -def AddVendor(output_zip): +def AddVendor(output_zip, recovery_img=None, boot_img=None): """Turn the contents of VENDOR into a vendor image and store in it output_zip.""" @@ -199,6 +202,27 @@ def AddVendor(output_zip): logger.info("vendor.img already exists; no need to rebuild...") return img.name + def output_sink(fn, data): + ofile = open(os.path.join(OPTIONS.input_tmp, "VENDOR", fn), "w") + ofile.write(data) + ofile.close() + + if output_zip: + arc_name = "VENDOR/" + fn + if arc_name in output_zip.namelist(): + OPTIONS.replace_updated_files_list.append(arc_name) + else: + common.ZipWrite(output_zip, ofile.name, arc_name) + + board_uses_vendorimage = OPTIONS.info_dict.get( + "board_uses_vendorimage") == "true" + + if (OPTIONS.rebuild_recovery and board_uses_vendorimage and + recovery_img is not None and boot_img is not None): + logger.info("Building new recovery patch on vendor") + common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, + boot_img, info_dict=OPTIONS.info_dict) + block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.map") CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "vendor", img, block_list=block_list) @@ -781,7 +805,8 @@ def AddImagesToTargetFiles(filename): if has_vendor: banner("vendor") - partitions['vendor'] = AddVendor(output_zip) + partitions['vendor'] = AddVendor( + output_zip, recovery_img=recovery_image, boot_img=boot_image) if has_product: banner("product") diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 974d4b039..04c721d22 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -2535,13 +2535,25 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, info_dict = OPTIONS.info_dict full_recovery_image = info_dict.get("full_recovery_image") == "true" + board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true" + + if board_uses_vendorimage: + # In this case, the output sink is rooted at VENDOR + recovery_img_path = "etc/recovery.img" + recovery_resource_dat_path = "VENDOR/etc/recovery-resource.dat" + sh_dir = "bin" + else: + # In this case the output sink is rooted at SYSTEM + recovery_img_path = "vendor/etc/recovery.img" + recovery_resource_dat_path = "SYSTEM/vendor/etc/recovery-resource.dat" + sh_dir = "vendor/bin" if full_recovery_image: - output_sink("etc/recovery.img", recovery_img.data) + output_sink(recovery_img_path, recovery_img.data) else: system_root_image = info_dict.get("system_root_image") == "true" - path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat") + path = os.path.join(input_dir, recovery_resource_dat_path) # With system-root-image, boot and recovery images will have mismatching # entries (only recovery has the ramdisk entry) (Bug: 72731506). Use bsdiff # to handle such a case. @@ -2554,7 +2566,7 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, if os.path.exists(path): diff_program.append("-b") diff_program.append(path) - bonus_args = "--bonus /system/etc/recovery-resource.dat" + bonus_args = "--bonus /vendor/etc/recovery-resource.dat" else: bonus_args = "" @@ -2571,10 +2583,16 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, return if full_recovery_image: - sh = """#!/system/bin/sh + + # Note that we use /vendor to refer to the recovery resources. This will + # work for a separate vendor partition mounted at /vendor or a + # /system/vendor subdirectory on the system partition, for which init will + # create a symlink from /vendor to /system/vendor. + + sh = """#!/vendor/bin/sh if ! applypatch --check %(type)s:%(device)s:%(size)d:%(sha1)s; then applypatch \\ - --flash /system/etc/recovery.img \\ + --flash /vendor/etc/recovery.img \\ --target %(type)s:%(device)s:%(size)d:%(sha1)s && \\ log -t recovery "Installing new recovery image: succeeded" || \\ log -t recovery "Installing new recovery image: failed" @@ -2586,10 +2604,10 @@ fi 'sha1': recovery_img.sha1, 'size': recovery_img.size} else: - sh = """#!/system/bin/sh + sh = """#!/vendor/bin/sh if ! applypatch --check %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then applypatch %(bonus_args)s \\ - --patch /system/recovery-from-boot.p \\ + --patch /vendor/recovery-from-boot.p \\ --source %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s \\ --target %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s && \\ log -t recovery "Installing new recovery image: succeeded" || \\ @@ -2607,9 +2625,9 @@ fi 'recovery_device': recovery_device, 'bonus_args': bonus_args} - # The install script location moved from /system/etc to /system/bin - # in the L release. - sh_location = "bin/install-recovery.sh" + # The install script location moved from /system/etc to /system/bin in the L + # release. In the R release it is in VENDOR/bin or SYSTEM/vendor/bin. + sh_location = os.path.join(sh_dir, "install-recovery.sh") logger.info("putting script in %s", sh_location) diff --git a/tools/releasetools/make_recovery_patch.py b/tools/releasetools/make_recovery_patch.py index 725b3550a..1497d69ed 100644 --- a/tools/releasetools/make_recovery_patch.py +++ b/tools/releasetools/make_recovery_patch.py @@ -47,8 +47,17 @@ def main(argv): if not recovery_img or not boot_img: sys.exit(0) + board_uses_vendorimage = OPTIONS.info_dict.get( + "board_uses_vendorimage") == "true" + + if board_uses_vendorimage: + target_files_dir = "VENDOR" + else: + target_files_dir = "SYSTEM" + def output_sink(fn, data): - with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f: + with open(os.path.join(output_dir, target_files_dir, + *fn.split("/")), "wb") as f: f.write(data) common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img) diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py index ba7098645..544f996f9 100755 --- a/tools/releasetools/merge_target_files.py +++ b/tools/releasetools/merge_target_files.py @@ -68,8 +68,7 @@ Usage: merge_target_files.py [args] files package and saves it at this path. --rebuild_recovery - Rebuild the recovery patch used by non-A/B devices and write it to the - system image. + Deprecated; does nothing. --keep-tmp Keep tempoary files for debugging purposes. @@ -106,6 +105,7 @@ OPTIONS.output_item_list = None OPTIONS.output_ota = None OPTIONS.output_img = None OPTIONS.output_super_empty = None +# TODO(b/132730255): Remove this option. OPTIONS.rebuild_recovery = False OPTIONS.keep_tmp = False @@ -372,32 +372,6 @@ def process_ab_partitions_txt(framework_target_files_temp_dir, write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt) -def append_recovery_to_filesystem_config(output_target_files_temp_dir): - """Performs special processing for META/filesystem_config.txt. - - This function appends recovery information to META/filesystem_config.txt so - that recovery patch regeneration will succeed. - - Args: - output_target_files_temp_dir: The name of a directory that will be used to - create the output target files package after all the special cases are - processed. We find filesystem_config.txt here. - """ - - filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META', - 'filesystem_config.txt') - - with open(filesystem_config_txt, 'a') as f: - # TODO(bpeckham) this data is hard coded. It should be generated - # programmatically. - f.write('system/bin/install-recovery.sh 0 0 750 ' - 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') - f.write('system/recovery-from-boot.p 0 0 644 ' - 'selabel=u:object_r:system_file:s0 capabilities=0x0\n') - f.write('system/etc/recovery.img 0 0 440 ' - 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') - - def process_misc_info_txt(framework_target_files_temp_dir, vendor_target_files_temp_dir, output_target_files_temp_dir, @@ -594,7 +568,7 @@ def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir, def process_special_cases(framework_target_files_temp_dir, vendor_target_files_temp_dir, output_target_files_temp_dir, - framework_misc_info_keys, rebuild_recovery): + framework_misc_info_keys): """Performs special-case processing for certain target files items. Certain files in the output target files package require special-case @@ -611,8 +585,6 @@ def process_special_cases(framework_target_files_temp_dir, framework_misc_info_keys: A list of keys to obtain from the framework instance of META/misc_info.txt. The remaining keys from the vendor instance. - rebuild_recovery: If true, rebuild the recovery patch used by non-A/B - devices and write it to the system image. """ if 'ab_update' in framework_misc_info_keys: @@ -621,10 +593,6 @@ def process_special_cases(framework_target_files_temp_dir, vendor_target_files_temp_dir=vendor_target_files_temp_dir, output_target_files_temp_dir=output_target_files_temp_dir) - if rebuild_recovery: - append_recovery_to_filesystem_config( - output_target_files_temp_dir=output_target_files_temp_dir) - copy_file_contexts( framework_target_files_dir=framework_target_files_temp_dir, vendor_target_files_dir=vendor_target_files_temp_dir, @@ -757,8 +725,7 @@ def create_merged_package(temp_dir, framework_target_files, framework_item_list, framework_target_files_temp_dir=framework_target_files_temp_dir, vendor_target_files_temp_dir=vendor_target_files_temp_dir, output_target_files_temp_dir=output_target_files_temp_dir, - framework_misc_info_keys=framework_misc_info_keys, - rebuild_recovery=rebuild_recovery) + framework_misc_info_keys=framework_misc_info_keys) return output_target_files_temp_dir @@ -779,6 +746,7 @@ def generate_images(target_files_dir, rebuild_recovery): add_img_args = ['--verbose'] add_img_args.append('--add_missing') + # TODO(b/132730255): Remove this if statement. if rebuild_recovery: add_img_args.append('--rebuild_recovery') add_img_args.append(target_files_dir) @@ -1016,7 +984,7 @@ def main(): OPTIONS.output_img = a elif o == '--output-super-empty': OPTIONS.output_super_empty = a - elif o == '--rebuild_recovery': + elif o == '--rebuild_recovery': # TODO(b/132730255): Warn OPTIONS.rebuild_recovery = True elif o == '--keep-tmp': OPTIONS.keep_tmp = True diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py index de947f329..3fc3c2249 100755 --- a/tools/releasetools/ota_from_target_files.py +++ b/tools/releasetools/ota_from_target_files.py @@ -731,10 +731,19 @@ def _WriteRecoveryImageToBoot(script, output_zip): script.WriteRawImage("/boot", "recovery.img") -def HasRecoveryPatch(target_files_zip): +def HasRecoveryPatch(target_files_zip, info_dict): + board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true" + + if board_uses_vendorimage: + target_files_dir = "VENDOR" + else: + target_files_dir = "SYSTEM/vendor" + + patch = "%s/recovery-from-boot.p" % target_files_dir + img = "%s/etc/recovery.img" %target_files_dir + namelist = [name for name in target_files_zip.namelist()] - return ("SYSTEM/recovery-from-boot.p" in namelist or - "SYSTEM/etc/recovery.img" in namelist) + return (patch in namelist or img in namelist) def HasPartition(target_files_zip, partition): @@ -925,7 +934,7 @@ def WriteFullOTAPackage(input_zip, output_file): metadata=metadata, info_dict=OPTIONS.info_dict) - assert HasRecoveryPatch(input_zip) + assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict) # Assertions (e.g. downgrade check, device properties check). ts = target_info.GetBuildProp("ro.build.date.utc") diff --git a/tools/releasetools/validate_target_files.py b/tools/releasetools/validate_target_files.py index c299a488a..a5e1930b6 100755 --- a/tools/releasetools/validate_target_files.py +++ b/tools/releasetools/validate_target_files.py @@ -138,7 +138,7 @@ def ValidateInstallRecoveryScript(input_tmp, info_dict): 1. full recovery: ... if ! applypatch --check type:device:size:sha1; then - applypatch --flash /system/etc/recovery.img \\ + applypatch --flash /vendor/etc/recovery.img \\ type:device:size:sha1 && \\ ... @@ -146,18 +146,26 @@ def ValidateInstallRecoveryScript(input_tmp, info_dict): ... if ! applypatch --check type:recovery_device:recovery_size:recovery_sha1; then applypatch [--bonus bonus_args] \\ - --patch /system/recovery-from-boot.p \\ + --patch /vendor/recovery-from-boot.p \\ --source type:boot_device:boot_size:boot_sha1 \\ --target type:recovery_device:recovery_size:recovery_sha1 && \\ ... - For full recovery, we want to calculate the SHA-1 of /system/etc/recovery.img + For full recovery, we want to calculate the SHA-1 of /vendor/etc/recovery.img and compare it against the one embedded in the script. While for recovery from boot, we want to check the SHA-1 for both recovery.img and boot.img under IMAGES/. """ - script_path = 'SYSTEM/bin/install-recovery.sh' + board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true" + + if board_uses_vendorimage: + script_path = 'VENDOR/bin/install-recovery.sh' + recovery_img = 'VENDOR/etc/recovery.img' + else: + script_path = 'SYSTEM/vendor/bin/install-recovery.sh' + recovery_img = 'SYSTEM/vendor/etc/recovery.img' + if not os.path.exists(os.path.join(input_tmp, script_path)): logging.info('%s does not exist in input_tmp', script_path) return @@ -188,7 +196,7 @@ def ValidateInstallRecoveryScript(input_tmp, info_dict): # Validate the SHA-1 of the recovery image. recovery_sha1 = flash_partition.split(':')[3] ValidateFileAgainstSha1( - input_tmp, 'recovery.img', 'SYSTEM/etc/recovery.img', recovery_sha1) + input_tmp, 'recovery.img', recovery_img, recovery_sha1) else: assert len(lines) == 11, "Invalid line count: {}".format(lines)