aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2018-11-20 22:44:06 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-11-20 22:44:06 +0000
commitd585de5933aa44f30bf6538b637f3d6f1cb2ff65 (patch)
treea0810ae7cfaaa3faceeae4b354d43f3665ffd4ac
parentfec2671f002f9e972db3a8e9bcb7543c8c24724e (diff)
parent50e7954ac92f8eb307156333821b81a10a3eb532 (diff)
downloadbuild-d585de5933aa44f30bf6538b637f3d6f1cb2ff65.tar.gz
Merge changes from topic "dp_retrofit_gen"
* changes: Generate retrofit OTA. Add split super images to target_files.
-rw-r--r--core/Makefile63
-rw-r--r--core/config.mk9
-rw-r--r--core/main.mk1
-rwxr-xr-xtools/releasetools/add_img_to_target_files.py69
-rwxr-xr-xtools/releasetools/ota_from_target_files.py88
5 files changed, 215 insertions, 15 deletions
diff --git a/core/Makefile b/core/Makefile
index 565180b5f0..8bfe9601cb 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -3671,13 +3671,24 @@ endif
ifdef BUILT_VENDOR_MATRIX
$(hide) cp $(BUILT_VENDOR_MATRIX) $(zip_root)/META/vendor_matrix.xml
endif
+ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
+ $(hide) echo "dynamic_partition_use=true" >> $(zip_root)/META/misc_info.txt
+endif
+ifeq ($(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS),true)
+ $(hide) echo "dynamic_partition_retrofit=true" >> $(zip_root)/META/misc_info.txt
+endif
ifneq ($(BOARD_SUPER_PARTITION_SIZE),)
- $(hide) echo "super_size=$(BOARD_SUPER_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
$(hide) echo "lpmake=$(notdir $(LPMAKE))" >> $(zip_root)/META/misc_info.txt
$(hide) echo -n "lpmake_args=" >> $(zip_root)/META/misc_info.txt
$(hide) echo $(call build-superimage-target-args,$(call super-slot-suffix)) \
>> $(zip_root)/META/misc_info.txt
endif
+ifneq ($(BOARD_SUPER_PARTITION_BLOCK_DEVICES),)
+ $(hide) echo "super_block_devices=$(BOARD_SUPER_PARTITION_BLOCK_DEVICES)" >> $(zip_root)/META/misc_info.txt
+endif
+ifneq ($(BOARD_SUPER_PARTITION_PARTITION_LIST),)
+ $(hide) echo "dynamic_partition_list=$(BOARD_SUPER_PARTITION_PARTITION_LIST)" >> $(zip_root)/META/misc_info.txt
+endif
ifneq ($(BOARD_SUPER_PARTITION_GROUPS),)
$(hide) echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" > $(zip_root)/META/dynamic_partitions_info.txt
$(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \
@@ -3714,6 +3725,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
@@ -3733,18 +3757,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
# -----------------------------------------------------------------
diff --git a/core/config.mk b/core/config.mk
index 9e227e67bc..0c2b8c74f9 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -1041,8 +1041,13 @@ ifdef BOARD_SUPER_PARTITION_SIZE
ifeq ($(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS),true)
# The metadata device must be specified manually for retrofitting.
-ifndef BOARD_SUPER_PARTITION_METADATA_DEVICE
-$(error Must specify BOARD_SUPER_PARTITION_METADATA_DEVICE if BOARD_SUPER_PARTITION_BLOCK_DEVICES is used.)
+ifeq ($(BOARD_SUPER_PARTITION_METADATA_DEVICE),)
+$(error Must specify BOARD_SUPER_PARTITION_METADATA_DEVICE if PRODUCT_RETROFIT_DYNAMIC_PARTITIONS=true.)
+endif
+
+# The super partition block device list must be specified manually for retrofitting.
+ifeq ($(BOARD_SUPER_PARTITION_BLOCK_DEVICES),)
+$(error Must specify BOARD_SUPER_PARTITION_BLOCK_DEVICES if PRODUCT_RETROFIT_DYNAMIC_PARTITIONS=true.)
endif
# The metadata device must be included in the super partition block device list.
diff --git a/core/main.mk b/core/main.mk
index 08ab43d161..988fbc6558 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -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) \
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index ddc50be8b9..b0dd0f8deb 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -330,6 +330,12 @@ def CreateImage(input_dir, info_dict, what, output_file, block_list=None):
image_blocks_key = what + "_image_blocks"
info_dict[image_blocks_key] = int(image_size) / 4096 - 1
+ use_dynamic_size = (
+ info_dict.get("use_dynamic_partition_size") == "true" and
+ what in shlex.split(info_dict.get("dynamic_partition_list", "").strip()))
+ if use_dynamic_size:
+ info_dict.update(build_image.GlobalDictFromImageProp(image_props, what))
+
def AddUserdata(output_zip):
"""Create a userdata image and store it in output_zip.
@@ -656,8 +662,8 @@ def AddSuperEmpty(output_zip):
"""Create a super_empty.img and store it in output_zip."""
img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "super_empty.img")
- cmd = [OPTIONS.info_dict.get('lpmake')]
- cmd += shlex.split(OPTIONS.info_dict.get('lpmake_args').strip())
+ cmd = [OPTIONS.info_dict['lpmake']]
+ cmd += shlex.split(OPTIONS.info_dict['lpmake_args'].strip())
cmd += ['--output', img.name]
proc = common.Run(cmd)
@@ -668,6 +674,58 @@ def AddSuperEmpty(output_zip):
img.Write()
+def AddSuperSplit(output_zip):
+ """Create split super_*.img and store it in output_zip."""
+
+ def TransformPartitionArg(arg):
+ lst = arg.split(':')
+ # Because --auto-slot-suffixing for A/B, there is no need to remove suffix.
+ name = lst[0]
+ assert name + '_size' in OPTIONS.info_dict, (
+ "{} is a prebuilt. Dynamic partitions with prebuilt images "
+ "are not supported yet.".format(name))
+ size = OPTIONS.info_dict[name + '_size']
+ assert size is not None, \
+ '{0}_size is not found; is {0} built?'.format(name)
+ lst[2] = str(size)
+ return ':'.join(lst)
+
+ def GetLpmakeArgsWithSizes():
+ lpmake_args = shlex.split(OPTIONS.info_dict['lpmake_args'].strip())
+
+ for i, arg in enumerate(lpmake_args):
+ if arg == '--partition':
+ assert i + 1 < len(lpmake_args), \
+ 'lpmake_args has --partition without value'
+ lpmake_args[i + 1] = TransformPartitionArg(lpmake_args[i + 1])
+
+ return lpmake_args
+
+ outdir = OutputFile(output_zip, OPTIONS.input_tmp, "OTA", "")
+ cmd = [OPTIONS.info_dict['lpmake']]
+ cmd += GetLpmakeArgsWithSizes()
+
+ source = OPTIONS.info_dict.get('dynamic_partition_list', '').strip()
+ if source:
+ cmd.append('--sparse')
+ for name in shlex.split(source):
+ img = os.path.join(OPTIONS.input_tmp, "IMAGES", '{}.img'.format(name))
+ # Because --auto-slot-suffixing for A/B, there is no need to add suffix.
+ cmd += ['--image', '{}={}'.format(name, img)]
+
+ cmd += ['--output', outdir.name]
+
+ proc = common.Run(cmd)
+ stdoutdata, _ = proc.communicate()
+ assert proc.returncode == 0, \
+ "lpmake tool failed:\n{}".format(stdoutdata)
+
+ for dev in OPTIONS.info_dict['super_block_devices'].strip().split():
+ img = OutputFile(output_zip, OPTIONS.input_tmp, "OTA",
+ "super_" + dev + ".img")
+ img.Write()
+
+
def ReplaceUpdatedFiles(zip_filename, files_list):
"""Updates all the ZIP entries listed in files_list.
@@ -861,10 +919,15 @@ def AddImagesToTargetFiles(filename):
banner("vbmeta")
AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
- if OPTIONS.info_dict.get("super_size"):
+ if OPTIONS.info_dict.get("lpmake_args"):
banner("super_empty")
AddSuperEmpty(output_zip)
+ if OPTIONS.info_dict.get("dynamic_partition_retrofit") == "true":
+ banner("super split images")
+ AddSuperSplit(output_zip)
+ # TODO(b/119322123): Add super.img to target_files for non-retrofit
+
banner("radio")
ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META",
"ab_partitions.txt")
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 2264655b2e..68275dc8b8 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -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.