Adds new merge builds script for use in merging two non-dist builds.
Bug: 137853921 Test: python -m unittest test_common Test: python -m unittest test_merge_target_files Test: Built two partial builds without dist. Ran out/host/linux-x86/bin/merge_builds. Flashed using `fastboot flashall`. Device boots. Change-Id: Iffd0a447cdf19a7775a813b4b896178aa6f861f3
This commit is contained in:
parent
6f8e3da035
commit
bfc51efa97
6 changed files with 274 additions and 124 deletions
|
@ -106,6 +106,19 @@ python_binary_host {
|
|||
],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "merge_builds",
|
||||
defaults: ["releasetools_binary_defaults"],
|
||||
srcs: [
|
||||
"build_super_image.py",
|
||||
"merge_builds.py",
|
||||
],
|
||||
main: "merge_builds.py",
|
||||
libs: [
|
||||
"releasetools_common",
|
||||
],
|
||||
}
|
||||
|
||||
python_defaults {
|
||||
name: "releasetools_test_defaults",
|
||||
srcs: [
|
||||
|
|
|
@ -554,6 +554,64 @@ def DumpInfoDict(d):
|
|||
logger.info("%-25s = (%s) %s", k, type(v).__name__, v)
|
||||
|
||||
|
||||
def MergeDynamicPartitionInfoDicts(framework_dict,
|
||||
vendor_dict,
|
||||
include_dynamic_partition_list=True,
|
||||
size_prefix="",
|
||||
size_suffix="",
|
||||
list_prefix="",
|
||||
list_suffix=""):
|
||||
"""Merges dynamic partition info variables.
|
||||
|
||||
Args:
|
||||
framework_dict: The dictionary of dynamic partition info variables from the
|
||||
partial framework target files.
|
||||
vendor_dict: The dictionary of dynamic partition info variables from the
|
||||
partial vendor target files.
|
||||
include_dynamic_partition_list: If true, merges the dynamic_partition_list
|
||||
variable. Not all use cases need this variable merged.
|
||||
size_prefix: The prefix in partition group size variables that precedes the
|
||||
name of the partition group. For example, partition group 'group_a' with
|
||||
corresponding size variable 'super_group_a_group_size' would have the
|
||||
size_prefix 'super_'.
|
||||
size_suffix: Similar to size_prefix but for the variable's suffix. For
|
||||
example, 'super_group_a_group_size' would have size_suffix '_group_size'.
|
||||
list_prefix: Similar to size_prefix but for the partition group's
|
||||
partition_list variable.
|
||||
list_suffix: Similar to size_suffix but for the partition group's
|
||||
partition_list variable.
|
||||
|
||||
Returns:
|
||||
The merged dynamic partition info dictionary.
|
||||
"""
|
||||
merged_dict = {}
|
||||
# Partition groups and group sizes are defined by the vendor dict because
|
||||
# these values may vary for each board that uses a shared system image.
|
||||
merged_dict["super_partition_groups"] = vendor_dict["super_partition_groups"]
|
||||
if include_dynamic_partition_list:
|
||||
framework_dynamic_partition_list = framework_dict.get(
|
||||
"dynamic_partition_list", "")
|
||||
vendor_dynamic_partition_list = vendor_dict.get("dynamic_partition_list",
|
||||
"")
|
||||
merged_dict["dynamic_partition_list"] = (
|
||||
"%s %s" % (framework_dynamic_partition_list,
|
||||
vendor_dynamic_partition_list)).strip()
|
||||
for partition_group in merged_dict["super_partition_groups"].split(" "):
|
||||
# Set the partition group's size using the value from the vendor dict.
|
||||
key = "%s%s%s" % (size_prefix, partition_group, size_suffix)
|
||||
if key not in vendor_dict:
|
||||
raise ValueError("Vendor dict does not contain required key %s." % key)
|
||||
merged_dict[key] = vendor_dict[key]
|
||||
|
||||
# Set the partition group's partition list using a concatenation of the
|
||||
# framework and vendor partition lists.
|
||||
key = "%s%s%s" % (list_prefix, partition_group, list_suffix)
|
||||
merged_dict[key] = (
|
||||
"%s %s" %
|
||||
(framework_dict.get(key, ""), vendor_dict.get(key, ""))).strip()
|
||||
return merged_dict
|
||||
|
||||
|
||||
def AppendAVBSigningArgs(cmd, partition):
|
||||
"""Append signing arguments for avbtool."""
|
||||
# e.g., "--key path/to/signing_key --algorithm SHA256_RSA4096"
|
||||
|
|
138
tools/releasetools/merge_builds.py
Normal file
138
tools/releasetools/merge_builds.py
Normal file
|
@ -0,0 +1,138 @@
|
|||
#!/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 assumes that images other than super_empty.img do not require
|
||||
regeneration, including vbmeta images.
|
||||
TODO(b/137853921): Add support for regenerating vbmeta images.
|
||||
|
||||
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>.
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
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"):
|
||||
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 MergeBuilds():
|
||||
CreateImageSymlinks()
|
||||
BuildSuperEmpty()
|
||||
# TODO(b/137853921): Add support for regenerating vbmeta images.
|
||||
|
||||
|
||||
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
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
args = common.ParseOptions(
|
||||
sys.argv[1:],
|
||||
__doc__,
|
||||
extra_long_opts=[
|
||||
"framework_images=",
|
||||
"product_out_framework=",
|
||||
"product_out_vendor=",
|
||||
],
|
||||
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()
|
|
@ -402,64 +402,6 @@ def append_recovery_to_filesystem_config(output_target_files_temp_dir):
|
|||
'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
|
||||
|
||||
|
||||
def merge_dynamic_partition_info_dicts(framework_dict,
|
||||
vendor_dict,
|
||||
include_dynamic_partition_list=True,
|
||||
size_prefix='',
|
||||
size_suffix='',
|
||||
list_prefix='',
|
||||
list_suffix=''):
|
||||
"""Merges dynamic partition info variables.
|
||||
|
||||
Args:
|
||||
framework_dict: The dictionary of dynamic partition info variables from the
|
||||
partial framework target files.
|
||||
vendor_dict: The dictionary of dynamic partition info variables from the
|
||||
partial vendor target files.
|
||||
include_dynamic_partition_list: If true, merges the dynamic_partition_list
|
||||
variable. Not all use cases need this variable merged.
|
||||
size_prefix: The prefix in partition group size variables that precedes the
|
||||
name of the partition group. For example, partition group 'group_a' with
|
||||
corresponding size variable 'super_group_a_group_size' would have the
|
||||
size_prefix 'super_'.
|
||||
size_suffix: Similar to size_prefix but for the variable's suffix. For
|
||||
example, 'super_group_a_group_size' would have size_suffix '_group_size'.
|
||||
list_prefix: Similar to size_prefix but for the partition group's
|
||||
partition_list variable.
|
||||
list_suffix: Similar to size_suffix but for the partition group's
|
||||
partition_list variable.
|
||||
|
||||
Returns:
|
||||
The merged dynamic partition info dictionary.
|
||||
"""
|
||||
merged_dict = {}
|
||||
# Partition groups and group sizes are defined by the vendor dict because
|
||||
# these values may vary for each board that uses a shared system image.
|
||||
merged_dict['super_partition_groups'] = vendor_dict['super_partition_groups']
|
||||
if include_dynamic_partition_list:
|
||||
framework_dynamic_partition_list = framework_dict.get(
|
||||
'dynamic_partition_list', '')
|
||||
vendor_dynamic_partition_list = vendor_dict.get('dynamic_partition_list',
|
||||
'')
|
||||
merged_dict['dynamic_partition_list'] = (
|
||||
'%s %s' % (framework_dynamic_partition_list,
|
||||
vendor_dynamic_partition_list)).strip()
|
||||
for partition_group in merged_dict['super_partition_groups'].split(' '):
|
||||
# Set the partition group's size using the value from the vendor dict.
|
||||
key = '%s%s%s' % (size_prefix, partition_group, size_suffix)
|
||||
if key not in vendor_dict:
|
||||
raise ValueError('Vendor dict does not contain required key %s.' % key)
|
||||
merged_dict[key] = vendor_dict[key]
|
||||
|
||||
# Set the partition group's partition list using a concatenation of the
|
||||
# framework and vendor partition lists.
|
||||
key = '%s%s%s' % (list_prefix, partition_group, list_suffix)
|
||||
merged_dict[key] = (
|
||||
'%s %s' %
|
||||
(framework_dict.get(key, ''), vendor_dict.get(key, ''))).strip()
|
||||
return merged_dict
|
||||
|
||||
|
||||
def process_misc_info_txt(framework_target_files_temp_dir,
|
||||
vendor_target_files_temp_dir,
|
||||
output_target_files_temp_dir,
|
||||
|
@ -503,7 +445,7 @@ def process_misc_info_txt(framework_target_files_temp_dir,
|
|||
# Merge misc info keys used for Dynamic Partitions.
|
||||
if (merged_dict.get('use_dynamic_partitions') == 'true') and (
|
||||
framework_dict.get('use_dynamic_partitions') == 'true'):
|
||||
merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
|
||||
merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
|
||||
framework_dict=framework_dict,
|
||||
vendor_dict=merged_dict,
|
||||
size_prefix='super_',
|
||||
|
@ -566,7 +508,7 @@ def process_dynamic_partitions_info_txt(framework_target_files_dir,
|
|||
vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
|
||||
os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
|
||||
|
||||
merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
|
||||
merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
|
||||
framework_dict=framework_dynamic_partitions_dict,
|
||||
vendor_dict=vendor_dynamic_partitions_dict,
|
||||
# META/dynamic_partitions_info.txt does not use dynamic_partition_list.
|
||||
|
|
|
@ -1074,6 +1074,69 @@ class CommonUtilsTest(test_utils.ReleaseToolsTestCase):
|
|||
self.assertRaises(
|
||||
AssertionError, common.LoadInfoDict, target_files_zip, True)
|
||||
|
||||
def test_MergeDynamicPartitionInfoDicts_ReturnsMergedDict(self):
|
||||
framework_dict = {
|
||||
'super_partition_groups': 'group_a',
|
||||
'dynamic_partition_list': 'system',
|
||||
'super_group_a_list': 'system',
|
||||
}
|
||||
vendor_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'vendor product',
|
||||
'super_group_a_list': 'vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
merged_dict = common.MergeDynamicPartitionInfoDicts(
|
||||
framework_dict=framework_dict,
|
||||
vendor_dict=vendor_dict,
|
||||
size_prefix='super_',
|
||||
size_suffix='_size',
|
||||
list_prefix='super_',
|
||||
list_suffix='_list')
|
||||
expected_merged_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'system vendor product',
|
||||
'super_group_a_list': 'system vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
self.assertEqual(merged_dict, expected_merged_dict)
|
||||
|
||||
def test_MergeDynamicPartitionInfoDicts_IgnoringFrameworkGroupSize(self):
|
||||
framework_dict = {
|
||||
'super_partition_groups': 'group_a',
|
||||
'dynamic_partition_list': 'system',
|
||||
'super_group_a_list': 'system',
|
||||
'super_group_a_size': '5000',
|
||||
}
|
||||
vendor_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'vendor product',
|
||||
'super_group_a_list': 'vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
merged_dict = common.MergeDynamicPartitionInfoDicts(
|
||||
framework_dict=framework_dict,
|
||||
vendor_dict=vendor_dict,
|
||||
size_prefix='super_',
|
||||
size_suffix='_size',
|
||||
list_prefix='super_',
|
||||
list_suffix='_list')
|
||||
expected_merged_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'system vendor product',
|
||||
'super_group_a_list': 'system vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
self.assertEqual(merged_dict, expected_merged_dict)
|
||||
|
||||
|
||||
class InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
|
||||
"""Checks the format of install-recovery.sh.
|
||||
|
|
|
@ -22,7 +22,6 @@ from merge_target_files import (validate_config_lists,
|
|||
DEFAULT_FRAMEWORK_ITEM_LIST,
|
||||
DEFAULT_VENDOR_ITEM_LIST,
|
||||
DEFAULT_FRAMEWORK_MISC_INFO_KEYS, copy_items,
|
||||
merge_dynamic_partition_info_dicts,
|
||||
process_apex_keys_apk_certs_common)
|
||||
|
||||
|
||||
|
@ -126,69 +125,6 @@ class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
|
|||
framework_misc_info_keys,
|
||||
DEFAULT_VENDOR_ITEM_LIST))
|
||||
|
||||
def test_merge_dynamic_partition_info_dicts_ReturnsMergedDict(self):
|
||||
framework_dict = {
|
||||
'super_partition_groups': 'group_a',
|
||||
'dynamic_partition_list': 'system',
|
||||
'super_group_a_list': 'system',
|
||||
}
|
||||
vendor_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'vendor product',
|
||||
'super_group_a_list': 'vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
merged_dict = merge_dynamic_partition_info_dicts(
|
||||
framework_dict=framework_dict,
|
||||
vendor_dict=vendor_dict,
|
||||
size_prefix='super_',
|
||||
size_suffix='_size',
|
||||
list_prefix='super_',
|
||||
list_suffix='_list')
|
||||
expected_merged_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'system vendor product',
|
||||
'super_group_a_list': 'system vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
self.assertEqual(merged_dict, expected_merged_dict)
|
||||
|
||||
def test_merge_dynamic_partition_info_dicts_IgnoringFrameworkGroupSize(self):
|
||||
framework_dict = {
|
||||
'super_partition_groups': 'group_a',
|
||||
'dynamic_partition_list': 'system',
|
||||
'super_group_a_list': 'system',
|
||||
'super_group_a_size': '5000',
|
||||
}
|
||||
vendor_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'vendor product',
|
||||
'super_group_a_list': 'vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
merged_dict = merge_dynamic_partition_info_dicts(
|
||||
framework_dict=framework_dict,
|
||||
vendor_dict=vendor_dict,
|
||||
size_prefix='super_',
|
||||
size_suffix='_size',
|
||||
list_prefix='super_',
|
||||
list_suffix='_list')
|
||||
expected_merged_dict = {
|
||||
'super_partition_groups': 'group_a group_b',
|
||||
'dynamic_partition_list': 'system vendor product',
|
||||
'super_group_a_list': 'system vendor',
|
||||
'super_group_a_size': '1000',
|
||||
'super_group_b_list': 'product',
|
||||
'super_group_b_size': '2000',
|
||||
}
|
||||
self.assertEqual(merged_dict, expected_merged_dict)
|
||||
|
||||
def test_process_apex_keys_apk_certs_ReturnsTrueIfNoConflicts(self):
|
||||
output_dir = common.MakeTempDir()
|
||||
os.makedirs(os.path.join(output_dir, 'META'))
|
||||
|
|
Loading…
Reference in a new issue