Generate retrofit OTA.

Test: m otapackage -j, manual apply on top of P
Bug: 118506262

Change-Id: Iedc389a1058007a604de0482f2348a9ef0d5892a
This commit is contained in:
Yifan Hong
2018-11-08 17:44:12 -08:00
parent c767f7cbfc
commit 50e7954ac9
3 changed files with 130 additions and 9 deletions

View File

@@ -3726,6 +3726,19 @@ ifeq ($(build_ota_package),true)
# -----------------------------------------------------------------
# OTA update package
# $(1): output file
# $(2): additional args
define build-ota-package-target
PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
build/make/tools/releasetools/ota_from_target_files -v \
--block \
--extracted_input_target_files $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE)) \
-p $(HOST_OUT) \
$(if $(OEM_OTA_CONFIG), -o $(OEM_OTA_CONFIG)) \
$(2) \
$(BUILT_TARGET_FILES_PACKAGE) $(1)
endef
name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
name := $(name)_debug
@@ -3745,18 +3758,39 @@ endif
$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) \
build/make/tools/releasetools/ota_from_target_files
@echo "Package OTA: $@"
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
build/make/tools/releasetools/ota_from_target_files -v \
--block \
--extracted_input_target_files $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE)) \
-p $(HOST_OUT) \
-k $(KEY_CERT_PAIR) \
$(if $(OEM_OTA_CONFIG), -o $(OEM_OTA_CONFIG)) \
$(BUILT_TARGET_FILES_PACKAGE) $@
$(call build-ota-package-target,$@,-k $(KEY_CERT_PAIR))
.PHONY: otapackage
otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
ifeq ($(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS),true)
name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
name := $(name)_debug
endif
name := $(name)-ota-retrofit-$(FILE_NAME_TAG)
INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
$(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
ifeq ($(AB_OTA_UPDATER),true)
$(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET): $(BRILLO_UPDATE_PAYLOAD)
else
$(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET): $(BROTLI)
endif
$(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) \
build/make/tools/releasetools/ota_from_target_files
@echo "Package OTA (retrofit dynamic partitions): $@"
$(call build-ota-package-target,$@,-k $(KEY_CERT_PAIR) --retrofit_dynamic_partitions)
.PHONY: otardppackage
otapackage otardppackage: $(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET)
endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
endif # build_ota_package
# -----------------------------------------------------------------

View File

@@ -1391,6 +1391,7 @@ else # TARGET_BUILD_APPS
$(call dist-for-goals, droidcore, \
$(INTERNAL_UPDATE_PACKAGE_TARGET) \
$(INTERNAL_OTA_PACKAGE_TARGET) \
$(INTERNAL_OTA_RETROFIT_DYNAMIC_PARTITIONS_PACKAGE_TARGET) \
$(BUILT_OTATOOLS_PACKAGE) \
$(SYMBOLS_ZIP) \
$(COVERAGE_ZIP) \

View File

@@ -64,6 +64,13 @@ Common options that apply to both of non-A/B and A/B OTAs
Generate an OTA package that will wipe the user data partition when
installed.
--retrofit_dynamic_partitions
Generates an OTA package that updates a device to support dynamic
partitions (default False). This flag is implied when generating
an incremental OTA where the base build does not support dynamic
partitions but the target build does. For A/B, when this flag is set,
--skip_postinstall is implied.
Non-A/B OTA specific options
-b (--binary) <file>
@@ -213,11 +220,14 @@ OPTIONS.payload_signer_args = []
OPTIONS.extracted_input = None
OPTIONS.key_passwords = []
OPTIONS.skip_postinstall = False
OPTIONS.retrofit_dynamic_partitions = False
METADATA_NAME = 'META-INF/com/android/metadata'
POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
UNZIP_PATTERN = ['IMAGES/*', 'META/*']
SUPER_SPLIT_PATTERN = ['OTA/super_*.img']
class BuildInfo(object):
@@ -1717,6 +1727,59 @@ def GetTargetFilesZipWithoutPostinstallConfig(input_file):
return target_file
def GetTargetFilesZipForRetrofitDynamicPartitions(input_file,
super_block_devices):
"""Returns a target-files.zip for retrofitting dynamic partitions.
This allows brillo_update_payload to generate an OTA based on the exact
bits on the block devices. Postinstall is disabled.
Args:
input_file: The input target-files.zip filename.
super_block_devices: The list of super block devices
Returns:
The filename of target-files.zip with *.img replaced with super_*.img for
each block device in super_block_devices.
"""
assert super_block_devices, "No super_block_devices are specified."
replace = {'OTA/super_{}.img'.format(dev): 'IMAGES/{}.img'.format(dev)
for dev in super_block_devices}
target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
shutil.copyfile(input_file, target_file)
with zipfile.ZipFile(input_file, 'r') as input_zip:
namelist = input_zip.namelist()
# Always skip postinstall for a retrofit update.
to_delete = [POSTINSTALL_CONFIG]
# Delete dynamic_partitions_info.txt so that brillo_update_payload thinks this
# is a regular update on devices without dynamic partitions support.
to_delete += [DYNAMIC_PARTITION_INFO]
# Remove the existing partition images.
to_delete += replace.values()
common.ZipDelete(target_file, to_delete)
input_tmp = common.UnzipTemp(input_file, SUPER_SPLIT_PATTERN)
target_zip = zipfile.ZipFile(target_file, 'a', allowZip64=True)
# Write super_{foo}.img as {foo}.img.
for src, dst in replace.items():
assert src in namelist, \
'Missing {} in {}; {} cannot be written'.format(src, input_file, dst)
unzipped_file = os.path.join(input_tmp, *src.split('/'))
common.ZipWrite(target_zip, unzipped_file, arcname=dst)
common.ZipClose(target_zip)
return target_file
def WriteABOTAPackageWithBrilloScript(target_file, output_file,
source_file=None):
"""Generates an Android OTA package that has A/B update payload."""
@@ -1738,7 +1801,10 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
# Metadata to comply with Android OTA package format.
metadata = GetPackageMetadata(target_info, source_info)
if OPTIONS.skip_postinstall:
if OPTIONS.retrofit_dynamic_partitions:
target_file = GetTargetFilesZipForRetrofitDynamicPartitions(
target_file, target_info.get("super_block_devices").strip().split())
elif OPTIONS.skip_postinstall:
target_file = GetTargetFilesZipWithoutPostinstallConfig(target_file)
# Generate payload.
@@ -1870,6 +1936,8 @@ def main(argv):
OPTIONS.extracted_input = a
elif o == "--skip_postinstall":
OPTIONS.skip_postinstall = True
elif o == "--retrofit_dynamic_partitions":
OPTIONS.retrofit_dynamic_partitions = True
else:
return False
return True
@@ -1900,6 +1968,7 @@ def main(argv):
"payload_signer_args=",
"extracted_input_target_files=",
"skip_postinstall",
"retrofit_dynamic_partitions",
], extra_option_handler=option_handler)
if len(args) != 2:
@@ -1943,6 +2012,23 @@ def main(argv):
# Load OEM dicts if provided.
OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)
# Assume retrofitting dynamic partitions when base build does not set
# dynamic_partition_use but target build does.
if (OPTIONS.source_info_dict and
OPTIONS.source_info_dict.get("dynamic_partition_use") != "true" and
OPTIONS.target_info_dict.get("dynamic_partition_use") == "true"):
if OPTIONS.target_info_dict.get("dynamic_partition_retrofit") != "true":
raise common.ExternalError(
"Expect to generate incremental OTA for retrofitting dynamic "
"partitions, but dynamic_partition_retrofit is not set in target "
"build.")
logger.info("Implicitly generating retrofit incremental OTA.")
OPTIONS.retrofit_dynamic_partitions = True
# Skip postinstall for retrofitting dynamic partitions.
if OPTIONS.retrofit_dynamic_partitions:
OPTIONS.skip_postinstall = True
ab_update = OPTIONS.info_dict.get("ab_update") == "true"
# Use the default key to sign the package if not specified with package_key.