Build super.img from images in target_files

For non-retrofit (launch) devices, super.img is used for factory, so
source images should be from target_files.

In this change, build-superimage-target procedure is converted to a
more flexible script so that it can be built.

Bug: 119322123
Test: build target files for device launch with dynamic partitions
Change-Id: I6ee0cc3e145357dfc74be248f81f5f8f4e51fc5c
This commit is contained in:
Yifan Hong 2018-11-29 12:06:31 -08:00
parent 9814cb6b23
commit 2b891ac024
3 changed files with 250 additions and 31 deletions

View File

@ -2967,19 +2967,6 @@ define build-superimage-target
--output $(1) --output $(1)
endef endef
# For A/B devices, super partition always contains sub-partitions in the _a slot, because this
# image should only be used for bootstrapping / initializing the device. When flashing the image,
# bootloader fastboot should always mark _a slot as bootable.
ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS))
INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img
$(INSTALLED_SUPERIMAGE_TARGET): $(LPMAKE) $(call images-for-partitions,$(BOARD_SUPER_PARTITION_PARTITION_LIST))
$(call pretty,"Target super fs image: $@")
$(call build-superimage-target,$@,$(call super-slot-suffix),true)
endif
$(call dist-for-goals,dist_files,$(INSTALLED_SUPERIMAGE_TARGET))
INSTALLED_SUPERIMAGE_EMPTY_TARGET := $(PRODUCT_OUT)/super_empty.img INSTALLED_SUPERIMAGE_EMPTY_TARGET := $(PRODUCT_OUT)/super_empty.img
$(INSTALLED_SUPERIMAGE_EMPTY_TARGET): $(LPMAKE) $(INSTALLED_SUPERIMAGE_EMPTY_TARGET): $(LPMAKE)
$(call pretty,"Target empty super fs image: $@") $(call pretty,"Target empty super fs image: $@")
@ -3329,6 +3316,31 @@ define fs_config
(cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) -R "$(2)" (cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) -R "$(2)"
endef endef
# $(1): file
define dump-dynamic-partitions-info
$(if $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITIONS)), \
echo "use_dynamic_partitions=true" >> $(1))
$(if $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)), \
echo "dynamic_partition_retrofit=true" >> $(1))
$(if $(BOARD_SUPER_PARTITION_SIZE), \
echo "lpmake=$(notdir $(LPMAKE))" >> $(1); \
echo -n "lpmake_args=" >> $(1); \
echo $(call build-superimage-target-args,$(call super-slot-suffix)) >> $(1))
echo "super_metadata_device=$(BOARD_SUPER_PARTITION_METADATA_DEVICE)" >> $(1)
$(if $(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \
echo "super_block_devices=$(BOARD_SUPER_PARTITION_BLOCK_DEVICES)" >> $(1))
$(foreach device,$(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \
echo "super_$(device)_device_size=$(BOARD_SUPER_PARTITION_$(call to-upper,$(device))_DEVICE_SIZE)" >> $(1);)
$(if $(BOARD_SUPER_PARTITION_PARTITION_LIST), \
echo "dynamic_partition_list=$(BOARD_SUPER_PARTITION_PARTITION_LIST)" >> $(1))
$(if $(BOARD_SUPER_PARTITION_GROUPS),
echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" >> $(1))
$(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \
echo "super_$(group)_group_size=$(BOARD_$(call to-upper,$(group))_SIZE)" >> $(1); \
$(if $(BOARD_$(call to-upper,$(group))_PARTITION_LIST), \
echo "super_$(group)_partition_list=$(BOARD_$(call to-upper,$(group))_PARTITION_LIST)" >> $(1);))
endef
# Depending on the various images guarantees that the underlying # Depending on the various images guarantees that the underlying
# directories are up-to-date. # directories are up-to-date.
$(BUILT_TARGET_FILES_PACKAGE): \ $(BUILT_TARGET_FILES_PACKAGE): \
@ -3644,6 +3656,7 @@ ifdef BOARD_AVB_DTBO_KEY_PATH
endif # BOARD_AVB_DTBO_KEY_PATH endif # BOARD_AVB_DTBO_KEY_PATH
endif # BOARD_AVB_ENABLE endif # BOARD_AVB_ENABLE
endif # BOARD_PREBUILT_DTBOIMAGE endif # BOARD_PREBUILT_DTBOIMAGE
$(call dump-dynamic-partitions-info,$(zip_root)/META/misc_info.txt)
@# The radio images in BOARD_PACK_RADIOIMAGES will be additionally copied from RADIO/ into @# The radio images in BOARD_PACK_RADIOIMAGES will be additionally copied from RADIO/ into
@# IMAGES/, which then will be added into <product>-img.zip. Such images must be listed in @# IMAGES/, which then will be added into <product>-img.zip. Such images must be listed in
@# INSTALLED_RADIOIMAGE_TARGET. @# INSTALLED_RADIOIMAGE_TARGET.
@ -3689,24 +3702,6 @@ endif
ifdef BUILT_VENDOR_MATRIX ifdef BUILT_VENDOR_MATRIX
$(hide) cp $(BUILT_VENDOR_MATRIX) $(zip_root)/META/vendor_matrix.xml $(hide) cp $(BUILT_VENDOR_MATRIX) $(zip_root)/META/vendor_matrix.xml
endif endif
ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
$(hide) echo "use_dynamic_partitions=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 "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),) ifneq ($(BOARD_SUPER_PARTITION_GROUPS),)
$(hide) echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" > $(zip_root)/META/dynamic_partitions_info.txt $(hide) echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" > $(zip_root)/META/dynamic_partitions_info.txt
$(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \ $(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \
@ -3974,6 +3969,27 @@ $(PROGUARD_DICT_ZIP) :
endif # TARGET_BUILD_APPS endif # TARGET_BUILD_APPS
# -----------------------------------------------------------------
# super partition image
ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION))
# BOARD_SUPER_PARTITION_SIZE must be defined to build super image.
ifneq ($(BOARD_SUPER_PARTITION_SIZE),)
ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS))
INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img
$(INSTALLED_SUPERIMAGE_TARGET): extracted_input_target_files := $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE))
$(INSTALLED_SUPERIMAGE_TARGET): $(LPMAKE) $(BUILT_TARGET_FILES_PACKAGE) $(BUILD_SUPER_IMAGE)
$(call pretty,"Target super fs image: $@")
$(BUILD_SUPER_IMAGE) -v $(extracted_input_target_files) $@
endif
$(call dist-for-goals,dist_files,$(INSTALLED_SUPERIMAGE_TARGET))
endif # BOARD_SUPER_PARTITION_SIZE != ""
endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# dalvik something # dalvik something
.PHONY: dalvikfiles .PHONY: dalvikfiles

View File

@ -698,6 +698,7 @@ DATA_BINDING_COMPILER := $(HOST_OUT_JAVA_LIBRARIES)/databinding-compiler.jar
FAT16COPY := build/make/tools/fat16copy.py FAT16COPY := build/make/tools/fat16copy.py
CHECK_LINK_TYPE := build/make/tools/check_link_type.py CHECK_LINK_TYPE := build/make/tools/check_link_type.py
LPMAKE := $(HOST_OUT_EXECUTABLES)/lpmake$(HOST_EXECUTABLE_SUFFIX) LPMAKE := $(HOST_OUT_EXECUTABLES)/lpmake$(HOST_EXECUTABLE_SUFFIX)
BUILD_SUPER_IMAGE := build/make/tools/releasetools/build_super_image.py
PROGUARD := external/proguard/bin/proguard.sh PROGUARD := external/proguard/bin/proguard.sh
JAVATAGS := build/make/tools/java-event-log-tags.py JAVATAGS := build/make/tools/java-event-log-tags.py

View File

@ -0,0 +1,202 @@
#!/usr/bin/env python
#
# Copyright (C) 2018 The Android Open Source Project
#
# 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.
"""
Usage: build_super_image input_file output_dir_or_file
input_file: one of the following:
- directory containing extracted target files. It will load info from
META/misc_info.txt and build full super image / split images using source
images from IMAGES/.
- target files package. Same as above, but extracts the archive before
building super image.
- a dictionary file containing input arguments to build. Check
`dump_dynamic_partitions_info' for details.
In addition:
- "ab_update" needs to be true for A/B devices.
- If source images should be included in the output image (for super.img
and super split images), a list of "*_image" should be paths of each
source images.
output_dir_or_file:
If a single super image is built (for super_empty.img, or super.img for
launch devices), this argument is the output file.
If a collection of split images are built (for retrofit devices), this
argument is the output directory.
"""
from __future__ import print_function
import logging
import os.path
import shlex
import sys
import zipfile
import common
import sparse_img
if sys.hexversion < 0x02070000:
print("Python 2.7 or newer is required.", file=sys.stderr)
sys.exit(1)
logger = logging.getLogger(__name__)
UNZIP_PATTERN = ["IMAGES/*", "META/*"]
def GetPartitionSizeFromImage(img):
try:
simg = sparse_img.SparseImage(img)
return simg.blocksize * simg.total_blocks
except ValueError:
return os.path.getsize(img)
def BuildSuperImageFromDict(info_dict, output):
cmd = [info_dict["lpmake"],
"--metadata-size", "65536",
"--super-name", info_dict["super_metadata_device"]]
ab_update = info_dict.get("ab_update") == "true"
retrofit = info_dict.get("dynamic_partition_retrofit") == "true"
block_devices = shlex.split(info_dict.get("super_block_devices", "").strip())
groups = shlex.split(info_dict.get("super_partition_groups", "").strip())
if ab_update:
cmd += ["--metadata-slots", "2"]
else:
cmd += ["--metadata-slots", "1"]
if ab_update and retrofit:
cmd.append("--auto-slot-suffixing")
for device in block_devices:
size = info_dict["super_{}_device_size".format(device)]
cmd += ["--device", "{}:{}".format(device, size)]
append_suffix = ab_update and not retrofit
has_image = False
for group in groups:
group_size = info_dict["super_{}_group_size".format(group)]
if append_suffix:
cmd += ["--group", "{}_a:{}".format(group, group_size),
"--group", "{}_b:{}".format(group, group_size)]
else:
cmd += ["--group", "{}:{}".format(group, group_size)]
partition_list = shlex.split(
info_dict["super_{}_partition_list".format(group)].strip())
for partition in partition_list:
image = info_dict.get("{}_image".format(partition))
image_size = 0
if image:
image_size = GetPartitionSizeFromImage(image)
has_image = True
if append_suffix:
cmd += ["--partition",
"{}_a:readonly:{}:{}_a".format(partition, image_size, group),
"--partition",
"{}_b:readonly:0:{}_b".format(partition, group)]
if image:
# For A/B devices, super partition always contains sub-partitions in
# the _a slot, because this image should only be used for
# bootstrapping / initializing the device. When flashing the image,
# bootloader fastboot should always mark _a slot as bootable.
cmd += ["--image", "{}_a={}".format(partition, image)]
else:
cmd += ["--partition",
"{}:readonly:{}:{}".format(partition, image_size, group)]
if image:
cmd += ["--image", "{}={}".format(partition, image)]
if has_image:
cmd.append("--sparse")
cmd += ["--output", output]
common.RunAndCheckOutput(cmd)
if retrofit and has_image:
logger.info("Done writing images to directory %s", output)
else:
logger.info("Done writing image %s", output)
def BuildSuperImageFromExtractedTargetFiles(inp, out):
info_dict = common.LoadInfoDict(inp)
partition_list = shlex.split(
info_dict.get("dynamic_partition_list", "").strip())
for partition in partition_list:
info_dict["{}_image".format(partition)] = os.path.join(
inp, "IMAGES", "{}.img".format(partition))
return BuildSuperImageFromDict(info_dict, out)
def BuildSuperImageFromTargetFiles(inp, out):
input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN)
return BuildSuperImageFromExtractedTargetFiles(input_tmp, out)
def BuildSuperImage(inp, out):
if isinstance(inp, dict):
logger.info("Building super image from info dict...")
return BuildSuperImageFromDict(inp, out)
if isinstance(inp, str):
if os.path.isdir(inp):
logger.info("Building super image from extracted target files...")
return BuildSuperImageFromExtractedTargetFiles(inp, out)
if zipfile.is_zipfile(inp):
logger.info("Building super image from target files...")
return BuildSuperImageFromTargetFiles(inp, out)
if os.path.isfile(inp):
with open(inp) as f:
lines = f.read()
logger.info("Building super image from info dict...")
return BuildSuperImageFromDict(common.LoadDictionaryFromLines(lines.split("\n")), out)
raise ValueError("{} is not a dictionary or a valid path".format(inp))
def main(argv):
args = common.ParseOptions(argv, __doc__)
if len(args) != 2:
common.Usage(__doc__)
sys.exit(1)
common.InitLogging()
BuildSuperImage(args[0], args[1])
if __name__ == "__main__":
try:
common.CloseInheritedPipes()
main(sys.argv[1:])
except common.ExternalError:
logger.exception("\n ERROR:\n")
sys.exit(1)
finally:
common.Cleanup()