276f06275b
Bug: 137853921 Bug: 138671115 Test: python -m unittest test_common Test: python -m unittest test_add_img_to_target_files Test: Ran 'merge_builds --build_vbmeta' for two devices, one with the vbmeta struct on system.img and another with vbmeta_system.img. Flashed the regenerated vbmeta.img files on devices, devices boot. Change-Id: I8d7585c7af468be3d242d8aceeed6d27e6fc6d96
197 lines
6.9 KiB
Python
197 lines
6.9 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Copyright (C) 2019 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.
|
|
#
|
|
"""Merges two non-dist partial builds together.
|
|
|
|
Given two partial builds, a framework build and a vendor build, merge the builds
|
|
together so that the images can be flashed using 'fastboot flashall'.
|
|
|
|
To support both DAP and non-DAP vendor builds with a single framework partial
|
|
build, the framework partial build should always be built with DAP enabled. The
|
|
vendor partial build determines whether the merged result supports DAP.
|
|
|
|
This script does not require builds to be built with 'make dist'.
|
|
This script regenerates super_empty.img and vbmeta.img if necessary. Other
|
|
images are assumed to not require regeneration.
|
|
|
|
Usage: merge_builds.py [args]
|
|
|
|
--framework_images comma_separated_image_list
|
|
Comma-separated list of image names that should come from the framework
|
|
build.
|
|
|
|
--product_out_framework product_out_framework_path
|
|
Path to out/target/product/<framework build>.
|
|
|
|
--product_out_vendor product_out_vendor_path
|
|
Path to out/target/product/<vendor build>.
|
|
|
|
--build_vbmeta
|
|
If provided, vbmeta.img will be regenerated in out/target/product/<vendor
|
|
build>.
|
|
|
|
--framework_misc_info_keys
|
|
The optional path to a newline-separated config file containing keys to
|
|
obtain from the framework instance of misc_info.txt, used for creating
|
|
vbmeta.img. The remaining keys come from the vendor instance.
|
|
"""
|
|
from __future__ import print_function
|
|
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
import build_super_image
|
|
import common
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
OPTIONS = common.OPTIONS
|
|
OPTIONS.framework_images = ("system",)
|
|
OPTIONS.product_out_framework = None
|
|
OPTIONS.product_out_vendor = None
|
|
OPTIONS.build_vbmeta = False
|
|
OPTIONS.framework_misc_info_keys = None
|
|
|
|
|
|
def CreateImageSymlinks():
|
|
for image in OPTIONS.framework_images:
|
|
image_path = os.path.join(OPTIONS.product_out_framework, "%s.img" % image)
|
|
symlink_path = os.path.join(OPTIONS.product_out_vendor, "%s.img" % image)
|
|
if os.path.exists(symlink_path):
|
|
if os.path.islink(symlink_path):
|
|
os.remove(symlink_path)
|
|
else:
|
|
raise ValueError("Attempting to overwrite built image: %s" %
|
|
symlink_path)
|
|
os.symlink(image_path, symlink_path)
|
|
|
|
|
|
def BuildSuperEmpty():
|
|
framework_dict = common.LoadDictionaryFromFile(
|
|
os.path.join(OPTIONS.product_out_framework, "misc_info.txt"))
|
|
vendor_dict = common.LoadDictionaryFromFile(
|
|
os.path.join(OPTIONS.product_out_vendor, "misc_info.txt"))
|
|
# Regenerate super_empty.img if both partial builds enable DAP. If only the
|
|
# the vendor build enables DAP, the vendor build's existing super_empty.img
|
|
# will be reused. If only the framework build should enable DAP, super_empty
|
|
# should be included in the --framework_images flag to copy the existing
|
|
# super_empty.img from the framework build.
|
|
if (framework_dict.get("use_dynamic_partitions") == "true") and (
|
|
vendor_dict.get("use_dynamic_partitions") == "true"):
|
|
logger.info("Building super_empty.img.")
|
|
merged_dict = dict(vendor_dict)
|
|
merged_dict.update(
|
|
common.MergeDynamicPartitionInfoDicts(
|
|
framework_dict=framework_dict,
|
|
vendor_dict=vendor_dict,
|
|
size_prefix="super_",
|
|
size_suffix="_group_size",
|
|
list_prefix="super_",
|
|
list_suffix="_partition_list"))
|
|
output_super_empty_path = os.path.join(OPTIONS.product_out_vendor,
|
|
"super_empty.img")
|
|
build_super_image.BuildSuperImage(merged_dict, output_super_empty_path)
|
|
|
|
|
|
def BuildVBMeta():
|
|
logger.info("Building vbmeta.img.")
|
|
|
|
framework_dict = common.LoadDictionaryFromFile(
|
|
os.path.join(OPTIONS.product_out_framework, "misc_info.txt"))
|
|
vendor_dict = common.LoadDictionaryFromFile(
|
|
os.path.join(OPTIONS.product_out_vendor, "misc_info.txt"))
|
|
merged_dict = dict(vendor_dict)
|
|
if OPTIONS.framework_misc_info_keys:
|
|
for key in common.LoadListFromFile(OPTIONS.framework_misc_info_keys):
|
|
merged_dict[key] = framework_dict[key]
|
|
|
|
# Build vbmeta.img using partitions in product_out_vendor.
|
|
partitions = {}
|
|
for partition in common.AVB_PARTITIONS:
|
|
partition_path = os.path.join(OPTIONS.product_out_vendor,
|
|
"%s.img" % partition)
|
|
if os.path.exists(partition_path):
|
|
partitions[partition] = partition_path
|
|
|
|
# vbmeta_partitions includes the partitions that should be included into
|
|
# top-level vbmeta.img, which are the ones that are not included in any
|
|
# chained VBMeta image plus the chained VBMeta images themselves.
|
|
vbmeta_partitions = common.AVB_PARTITIONS[:]
|
|
for partition in common.AVB_VBMETA_PARTITIONS:
|
|
chained_partitions = merged_dict.get("avb_%s" % partition, "").strip()
|
|
if chained_partitions:
|
|
partitions[partition] = os.path.join(OPTIONS.product_out_vendor,
|
|
"%s.img" % partition)
|
|
vbmeta_partitions = [
|
|
item for item in vbmeta_partitions
|
|
if item not in chained_partitions.split()
|
|
]
|
|
vbmeta_partitions.append(partition)
|
|
|
|
output_vbmeta_path = os.path.join(OPTIONS.product_out_vendor, "vbmeta.img")
|
|
OPTIONS.info_dict = merged_dict
|
|
common.BuildVBMeta(output_vbmeta_path, partitions, "vbmeta",
|
|
vbmeta_partitions)
|
|
|
|
|
|
def MergeBuilds():
|
|
CreateImageSymlinks()
|
|
BuildSuperEmpty()
|
|
if OPTIONS.build_vbmeta:
|
|
BuildVBMeta()
|
|
|
|
|
|
def main():
|
|
common.InitLogging()
|
|
|
|
def option_handler(o, a):
|
|
if o == "--framework_images":
|
|
OPTIONS.framework_images = [i.strip() for i in a.split(",")]
|
|
elif o == "--product_out_framework":
|
|
OPTIONS.product_out_framework = a
|
|
elif o == "--product_out_vendor":
|
|
OPTIONS.product_out_vendor = a
|
|
elif o == "--build_vbmeta":
|
|
OPTIONS.build_vbmeta = True
|
|
elif o == "--framework_misc_info_keys":
|
|
OPTIONS.framework_misc_info_keys = a
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
args = common.ParseOptions(
|
|
sys.argv[1:],
|
|
__doc__,
|
|
extra_long_opts=[
|
|
"framework_images=",
|
|
"product_out_framework=",
|
|
"product_out_vendor=",
|
|
"build_vbmeta",
|
|
"framework_misc_info_keys=",
|
|
],
|
|
extra_option_handler=option_handler)
|
|
|
|
if (args or OPTIONS.product_out_framework is None or
|
|
OPTIONS.product_out_vendor is None):
|
|
common.Usage(__doc__)
|
|
sys.exit(1)
|
|
|
|
MergeBuilds()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|