Merge "Add an option to input the boot variables for OTA package generation" am: 1ca7b10456

Change-Id: I33bbd3bb27fcba8f6a40e7c79b78c6751a7fc817
This commit is contained in:
Tianjie Xu 2020-05-21 18:13:36 +00:00 committed by Automerger Merge Worker
commit 0dbde58c9b
2 changed files with 179 additions and 41 deletions

View file

@ -189,6 +189,13 @@ A/B OTA specific options
--payload_signer_key_size <key_size>
Deprecated. Use the '--payload_signer_maximum_signature_size' instead.
--boot_variable_file <path>
A file that contains the possible values of ro.boot.* properties. It's
used to calculate the possible runtime fingerprints when some
ro.product.* properties are overridden by the 'import' statement.
The file expects one property per line, and each line has the following
format: 'prop_name=value1,value2'. e.g. 'ro.boot.product.sku=std,pro'
--skip_postinstall
Skip the postinstall hooks when generating an A/B OTA package (default:
False). Note that this discards ALL the hooks, including non-optional
@ -257,8 +264,8 @@ OPTIONS.retrofit_dynamic_partitions = False
OPTIONS.skip_compatibility_check = False
OPTIONS.output_metadata_path = None
OPTIONS.disable_fec_computation = False
OPTIONS.boot_variable_values = None
OPTIONS.force_non_ab = False
OPTIONS.boot_variable_file = None
METADATA_NAME = 'META-INF/com/android/metadata'
@ -931,8 +938,18 @@ def GetPackageMetadata(target_info, source_info=None):
assert isinstance(target_info, common.BuildInfo)
assert source_info is None or isinstance(source_info, common.BuildInfo)
separator = '|'
boot_variable_values = {}
if OPTIONS.boot_variable_file:
d = common.LoadDictionaryFromFile(OPTIONS.boot_variable_file)
for key, values in d.items():
boot_variable_values[key] = [val.strip() for val in values.split(',')]
post_build_devices, post_build_fingerprints = \
CalculateRuntimeDevicesAndFingerprints(target_info, boot_variable_values)
metadata = {
'post-build' : target_info.fingerprint,
'post-build': separator.join(sorted(post_build_fingerprints)),
'post-build-incremental': target_info.GetBuildProp(
'ro.build.version.incremental'),
'post-sdk-level': target_info.GetBuildProp(
@ -955,12 +972,15 @@ def GetPackageMetadata(target_info, source_info=None):
is_incremental = source_info is not None
if is_incremental:
metadata['pre-build'] = source_info.fingerprint
pre_build_devices, pre_build_fingerprints = \
CalculateRuntimeDevicesAndFingerprints(source_info,
boot_variable_values)
metadata['pre-build'] = separator.join(sorted(pre_build_fingerprints))
metadata['pre-build-incremental'] = source_info.GetBuildProp(
'ro.build.version.incremental')
metadata['pre-device'] = source_info.device
metadata['pre-device'] = separator.join(sorted(pre_build_devices))
else:
metadata['pre-device'] = target_info.device
metadata['pre-device'] = separator.join(sorted(post_build_devices))
# Use the actual post-timestamp, even for a downgrade case.
metadata['post-timestamp'] = target_info.GetBuildProp('ro.build.date.utc')
@ -1972,24 +1992,24 @@ def GenerateNonAbOtaPackage(target_file, output_file, source_file=None):
output_file)
def CalculateRuntimeFingerprints():
"""Returns a set of runtime fingerprints based on the boot variables."""
def CalculateRuntimeDevicesAndFingerprints(build_info, boot_variable_values):
"""Returns a tuple of sets for runtime devices and fingerprints"""
build_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
device_names = {build_info.device}
fingerprints = {build_info.fingerprint}
if not OPTIONS.boot_variable_values:
return fingerprints
if not boot_variable_values:
return device_names, fingerprints
# Calculate all possible combinations of the values for the boot variables.
keys = OPTIONS.boot_variable_values.keys()
value_list = OPTIONS.boot_variable_values.values()
keys = boot_variable_values.keys()
value_list = boot_variable_values.values()
combinations = [dict(zip(keys, values))
for values in itertools.product(*value_list)]
for placeholder_values in combinations:
# Reload the info_dict as some build properties may change their values
# based on the value of ro.boot* properties.
info_dict = copy.deepcopy(OPTIONS.info_dict)
info_dict = copy.deepcopy(build_info.info_dict)
for partition in common.PARTITIONS_WITH_CARE_MAP:
partition_prop_key = "{}.build.prop".format(partition)
old_props = info_dict[partition_prop_key]
@ -1997,9 +2017,10 @@ def CalculateRuntimeFingerprints():
old_props.input_file, partition, placeholder_values)
info_dict["build.prop"] = info_dict["system.build.prop"]
build_info = common.BuildInfo(info_dict, OPTIONS.oem_dicts)
fingerprints.add(build_info.fingerprint)
return fingerprints
new_build_info = common.BuildInfo(info_dict, build_info.oem_dicts)
device_names.add(new_build_info.device)
fingerprints.add(new_build_info.fingerprint)
return device_names, fingerprints
def main(argv):
@ -2077,6 +2098,8 @@ def main(argv):
OPTIONS.disable_fec_computation = True
elif o == "--force_non_ab":
OPTIONS.force_non_ab = True
elif o == "--boot_variable_file":
OPTIONS.boot_variable_file = a
else:
return False
return True
@ -2114,6 +2137,7 @@ def main(argv):
"output_metadata_path=",
"disable_fec_computation",
"force_non_ab",
"boot_variable_file=",
], extra_option_handler=option_handler)
if len(args) != 2:

View file

@ -27,7 +27,7 @@ from ota_from_target_files import (
GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
StreamingPropertyFiles, WriteFingerprintAssertion,
CalculateRuntimeFingerprints)
CalculateRuntimeDevicesAndFingerprints)
def construct_target_files(secondary=False):
@ -1334,6 +1334,9 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
'ro.build.version.incremental=version-incremental',
'ro.build.type=build-type',
'ro.build.tags=build-tags',
'ro.build.version.sdk=30',
'ro.build.version.security_patch=2020',
'ro.build.date.utc=12345678'
]
VENDOR_BUILD_PROP = [
@ -1345,11 +1348,12 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
def setUp(self):
common.OPTIONS.oem_dicts = None
self.test_dir = common.MakeTempDir()
self.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)})
self.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)},
self.test_dir)
def writeFiles(self, contents_dict):
def writeFiles(self, contents_dict, out_dir):
for path, content in contents_dict.items():
abs_path = os.path.join(self.test_dir, path)
abs_path = os.path.join(out_dir, path)
dir_name = os.path.dirname(abs_path)
if not os.path.exists(dir_name):
os.makedirs(dir_name)
@ -1371,12 +1375,14 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
self.writeFiles({
'SYSTEM/build.prop': '\n'.join(build_prop),
'VENDOR/build.prop': '\n'.join(self.VENDOR_BUILD_PROP),
})
common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
}, self.test_dir)
self.assertEqual({
self.constructFingerprint('product-brand/product-name/product-device')
}, CalculateRuntimeFingerprints())
build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
expected = ({'product-device'},
{self.constructFingerprint(
'product-brand/product-name/product-device')})
self.assertEqual(expected,
CalculateRuntimeDevicesAndFingerprints(build_info, {}))
def test_CalculatePossibleFingerprints_single_override(self):
vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
@ -1390,20 +1396,22 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
'ro.product.vendor.name=vendor-product-std',
'VENDOR/etc/build_pro.prop':
'ro.product.vendor.name=vendor-product-pro',
})
common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
common.OPTIONS.boot_variable_values = {
'ro.boot.sku_name': ['std', 'pro']
}
}, self.test_dir)
self.assertEqual({
build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
boot_variable_values = {'ro.boot.sku_name': ['std', 'pro']}
expected = ({'vendor-product-device'}, {
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-product-device'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-std/vendor-product-device'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-pro/vendor-product-device'),
}, CalculateRuntimeFingerprints())
})
self.assertEqual(
expected, CalculateRuntimeDevicesAndFingerprints(
build_info, boot_variable_values))
def test_CalculatePossibleFingerprints_multiple_overrides(self):
vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
@ -1422,14 +1430,17 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
'ro.product.vendor.name=vendor-product-pro',
'VENDOR/etc/build_product2.prop':
'ro.product.vendor.device=vendor-device-product2',
})
common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
common.OPTIONS.boot_variable_values = {
}, self.test_dir)
build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
boot_variable_values = {
'ro.boot.sku_name': ['std', 'pro'],
'ro.boot.device_name': ['product1', 'product2'],
}
self.assertEqual({
expected_devices = {'vendor-product-device', 'vendor-device-product1',
'vendor-device-product2'}
expected_fingerprints = {
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-product-device'),
self.constructFingerprint(
@ -1439,5 +1450,108 @@ class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
self.constructFingerprint(
'vendor-product-brand/vendor-product-std/vendor-device-product2'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-pro/vendor-device-product2'),
}, CalculateRuntimeFingerprints())
'vendor-product-brand/vendor-product-pro/vendor-device-product2')
}
self.assertEqual((expected_devices, expected_fingerprints),
CalculateRuntimeDevicesAndFingerprints(
build_info, boot_variable_values))
def test_GetPackageMetadata_full_package(self):
vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
vendor_build_prop.extend([
'import /vendor/etc/build_${ro.boot.sku_name}.prop',
])
self.writeFiles({
'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
'VENDOR/build.prop': '\n'.join(vendor_build_prop),
'VENDOR/etc/build_std.prop':
'ro.product.vendor.name=vendor-product-std',
'VENDOR/etc/build_pro.prop':
'ro.product.vendor.name=vendor-product-pro',
}, self.test_dir)
common.OPTIONS.boot_variable_file = common.MakeTempFile()
with open(common.OPTIONS.boot_variable_file, 'w') as f:
f.write('ro.boot.sku_name=std,pro')
build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
metadata = GetPackageMetadata(build_info)
self.assertEqual('vendor-product-device', metadata['pre-device'])
fingerprints = [
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-product-device'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-pro/vendor-product-device'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-std/vendor-product-device'),
]
self.assertEqual('|'.join(fingerprints), metadata['post-build'])
def test_GetPackageMetadata_incremental_package(self):
vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
vendor_build_prop.extend([
'import /vendor/etc/build_${ro.boot.sku_name}.prop',
])
self.writeFiles({
'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
'VENDOR/build.prop': '\n'.join(vendor_build_prop),
'VENDOR/etc/build_std.prop':
'ro.product.vendor.device=vendor-device-std',
'VENDOR/etc/build_pro.prop':
'ro.product.vendor.device=vendor-device-pro',
}, self.test_dir)
common.OPTIONS.boot_variable_file = common.MakeTempFile()
with open(common.OPTIONS.boot_variable_file, 'w') as f:
f.write('ro.boot.sku_name=std,pro')
source_dir = common.MakeTempDir()
source_build_prop = [
'ro.build.version.release=source-version-release',
'ro.build.id=source-build-id',
'ro.build.version.incremental=source-version-incremental',
'ro.build.type=build-type',
'ro.build.tags=build-tags',
'ro.build.version.sdk=29',
'ro.build.version.security_patch=2020',
'ro.build.date.utc=12340000'
]
self.writeFiles({
'META/misc_info.txt': '\n'.join(self.MISC_INFO),
'SYSTEM/build.prop': '\n'.join(source_build_prop),
'VENDOR/build.prop': '\n'.join(vendor_build_prop),
'VENDOR/etc/build_std.prop':
'ro.product.vendor.device=vendor-device-std',
'VENDOR/etc/build_pro.prop':
'ro.product.vendor.device=vendor-device-pro',
}, source_dir)
common.OPTIONS.incremental_source = source_dir
target_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
source_info = common.BuildInfo(common.LoadInfoDict(source_dir))
metadata = GetPackageMetadata(target_info, source_info)
self.assertEqual(
'vendor-device-pro|vendor-device-std|vendor-product-device',
metadata['pre-device'])
suffix = ':source-version-release/source-build-id/' \
'source-version-incremental:build-type/build-tags'
pre_fingerprints = [
'vendor-product-brand/vendor-product-name/vendor-device-pro'
'{}'.format(suffix),
'vendor-product-brand/vendor-product-name/vendor-device-std'
'{}'.format(suffix),
'vendor-product-brand/vendor-product-name/vendor-product-device'
'{}'.format(suffix),
]
self.assertEqual('|'.join(pre_fingerprints), metadata['pre-build'])
post_fingerprints = [
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-device-pro'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-device-std'),
self.constructFingerprint(
'vendor-product-brand/vendor-product-name/vendor-product-device'),
]
self.assertEqual('|'.join(post_fingerprints), metadata['post-build'])