Merge "Add an option to input the boot variables for OTA package generation"
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 16b278a..b753414 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -189,6 +189,13 @@
--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.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,13 +938,23 @@
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-incremental' : target_info.GetBuildProp(
+ 'post-build': separator.join(sorted(post_build_fingerprints)),
+ 'post-build-incremental': target_info.GetBuildProp(
'ro.build.version.incremental'),
- 'post-sdk-level' : target_info.GetBuildProp(
+ 'post-sdk-level': target_info.GetBuildProp(
'ro.build.version.sdk'),
- 'post-security-patch-level' : target_info.GetBuildProp(
+ 'post-security-patch-level': target_info.GetBuildProp(
'ro.build.version.security_patch'),
}
@@ -955,12 +972,15 @@
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 @@
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 @@
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 @@
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 @@
"output_metadata_path=",
"disable_fec_computation",
"force_non_ab",
+ "boot_variable_file=",
], extra_option_handler=option_handler)
if len(args) != 2:
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 4077d06..7783f96 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -27,7 +27,7 @@
GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
StreamingPropertyFiles, WriteFingerprintAssertion,
- CalculateRuntimeFingerprints)
+ CalculateRuntimeDevicesAndFingerprints)
def construct_target_files(secondary=False):
@@ -1334,6 +1334,9 @@
'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 @@
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 @@
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 @@
'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 @@
'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 @@
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'])