blob: 4077d06e6930b7e11d6f64afd910dbd4cc2706dd [file] [log] [blame]
Tao Bao481bab82017-12-21 11:23:09 -08001#
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import copy
Tao Baoc7b403a2018-01-30 18:19:04 -080018import os
Tao Baofabe0832018-01-17 15:52:28 -080019import os.path
Tao Baoc7b403a2018-01-30 18:19:04 -080020import zipfile
Tao Bao481bab82017-12-21 11:23:09 -080021
22import common
Tao Bao04e1f012018-02-04 12:13:35 -080023import test_utils
Tao Bao481bab82017-12-21 11:23:09 -080024from ota_from_target_files import (
Tao Bao1c320f82019-10-04 23:25:12 -070025 _LoadOemDicts, AbOtaPropertyFiles, FinalizeMetadata,
Tao Bao3bf8c652018-03-16 12:59:42 -070026 GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
Tao Baoc0746f42018-02-21 13:17:22 -080027 GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
Tao Bao69203522018-03-08 16:09:01 -080028 Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
Tianjie0d2fcd52020-05-06 21:54:21 -070029 StreamingPropertyFiles, WriteFingerprintAssertion,
30 CalculateRuntimeFingerprints)
Tao Baofabe0832018-01-17 15:52:28 -080031
32
Tao Baof7140c02018-01-30 17:09:24 -080033def construct_target_files(secondary=False):
34 """Returns a target-files.zip file for generating OTA packages."""
35 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
36 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
37 # META/update_engine_config.txt
38 target_files_zip.writestr(
39 'META/update_engine_config.txt',
40 "PAYLOAD_MAJOR_VERSION=2\nPAYLOAD_MINOR_VERSION=4\n")
41
Tao Bao15a146a2018-02-21 16:06:59 -080042 # META/postinstall_config.txt
43 target_files_zip.writestr(
44 POSTINSTALL_CONFIG,
45 '\n'.join([
46 "RUN_POSTINSTALL_system=true",
47 "POSTINSTALL_PATH_system=system/bin/otapreopt_script",
48 "FILESYSTEM_TYPE_system=ext4",
49 "POSTINSTALL_OPTIONAL_system=true",
50 ]))
51
Tao Bao5277d102018-04-17 23:47:21 -070052 ab_partitions = [
53 ('IMAGES', 'boot'),
54 ('IMAGES', 'system'),
55 ('IMAGES', 'vendor'),
56 ('RADIO', 'bootloader'),
57 ('RADIO', 'modem'),
58 ]
Tao Baof7140c02018-01-30 17:09:24 -080059 # META/ab_partitions.txt
Tao Baof7140c02018-01-30 17:09:24 -080060 target_files_zip.writestr(
61 'META/ab_partitions.txt',
Tao Bao5277d102018-04-17 23:47:21 -070062 '\n'.join([partition[1] for partition in ab_partitions]))
Tao Baof7140c02018-01-30 17:09:24 -080063
64 # Create dummy images for each of them.
Tao Bao5277d102018-04-17 23:47:21 -070065 for path, partition in ab_partitions:
66 target_files_zip.writestr(
67 '{}/{}.img'.format(path, partition),
68 os.urandom(len(partition)))
Tao Baof7140c02018-01-30 17:09:24 -080069
Tao Bao5277d102018-04-17 23:47:21 -070070 # system_other shouldn't appear in META/ab_partitions.txt.
Tao Baof7140c02018-01-30 17:09:24 -080071 if secondary:
72 target_files_zip.writestr('IMAGES/system_other.img',
73 os.urandom(len("system_other")))
74
75 return target_files
76
77
Tao Bao65b94e92018-10-11 21:57:26 -070078class LoadOemDictsTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -080079
80 def test_NoneDict(self):
81 self.assertIsNone(_LoadOemDicts(None))
82
83 def test_SingleDict(self):
84 dict_file = common.MakeTempFile()
85 with open(dict_file, 'w') as dict_fp:
86 dict_fp.write('abc=1\ndef=2\nxyz=foo\na.b.c=bar\n')
87
88 oem_dicts = _LoadOemDicts([dict_file])
89 self.assertEqual(1, len(oem_dicts))
90 self.assertEqual('foo', oem_dicts[0]['xyz'])
91 self.assertEqual('bar', oem_dicts[0]['a.b.c'])
92
93 def test_MultipleDicts(self):
94 oem_source = []
95 for i in range(3):
96 dict_file = common.MakeTempFile()
97 with open(dict_file, 'w') as dict_fp:
98 dict_fp.write(
99 'ro.build.index={}\ndef=2\nxyz=foo\na.b.c=bar\n'.format(i))
100 oem_source.append(dict_file)
101
102 oem_dicts = _LoadOemDicts(oem_source)
103 self.assertEqual(3, len(oem_dicts))
104 for i, oem_dict in enumerate(oem_dicts):
105 self.assertEqual('2', oem_dict['def'])
106 self.assertEqual('foo', oem_dict['xyz'])
107 self.assertEqual('bar', oem_dict['a.b.c'])
108 self.assertEqual('{}'.format(i), oem_dict['ro.build.index'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800109
110
Tao Bao65b94e92018-10-11 21:57:26 -0700111class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baodf3a48b2018-01-10 16:30:43 -0800112 TEST_TARGET_INFO_DICT = {
Tianjiefd3883f2020-04-25 19:55:54 -0700113 'build.prop': common.PartitionBuildProps.FromDictionary(
114 'system', {
115 'ro.product.device': 'product-device',
116 'ro.build.fingerprint': 'build-fingerprint-target',
117 'ro.build.version.incremental': 'build-version-incremental-target',
118 'ro.build.version.sdk': '27',
119 'ro.build.version.security_patch': '2017-12-01',
120 'ro.build.date.utc': '1500000000'}
121 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800122 }
123
124 TEST_SOURCE_INFO_DICT = {
Tianjiefd3883f2020-04-25 19:55:54 -0700125 'build.prop': common.PartitionBuildProps.FromDictionary(
126 'system', {
127 'ro.product.device': 'product-device',
128 'ro.build.fingerprint': 'build-fingerprint-source',
129 'ro.build.version.incremental': 'build-version-incremental-source',
130 'ro.build.version.sdk': '25',
131 'ro.build.version.security_patch': '2016-12-01',
132 'ro.build.date.utc': '1400000000'}
133 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800134 }
135
Tao Bao1c320f82019-10-04 23:25:12 -0700136 TEST_INFO_DICT_USES_OEM_PROPS = {
Tianjiefd3883f2020-04-25 19:55:54 -0700137 'build.prop': common.PartitionBuildProps.FromDictionary(
138 'system', {
139 'ro.product.name': 'product-name',
140 'ro.build.thumbprint': 'build-thumbprint',
141 'ro.build.bar': 'build-bar'}
142 ),
143 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
144 'vendor', {
145 'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
146 ),
147 'property1': 'value1',
148 'property2': 4096,
149 'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
Tao Bao1c320f82019-10-04 23:25:12 -0700150 }
151
152 TEST_OEM_DICTS = [
153 {
Tianjiefd3883f2020-04-25 19:55:54 -0700154 'ro.product.brand': 'brand1',
155 'ro.product.device': 'device1',
Tao Bao1c320f82019-10-04 23:25:12 -0700156 },
157 {
Tianjiefd3883f2020-04-25 19:55:54 -0700158 'ro.product.brand': 'brand2',
159 'ro.product.device': 'device2',
Tao Bao1c320f82019-10-04 23:25:12 -0700160 },
161 {
Tianjiefd3883f2020-04-25 19:55:54 -0700162 'ro.product.brand': 'brand3',
163 'ro.product.device': 'device3',
Tao Bao1c320f82019-10-04 23:25:12 -0700164 },
165 ]
166
Tao Baodf3a48b2018-01-10 16:30:43 -0800167 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700168 self.testdata_dir = test_utils.get_testdata_dir()
169 self.assertTrue(os.path.exists(self.testdata_dir))
170
Tao Baodf3a48b2018-01-10 16:30:43 -0800171 # Reset the global options as in ota_from_target_files.py.
172 common.OPTIONS.incremental_source = None
173 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800174 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800175 common.OPTIONS.timestamp = False
176 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700177 common.OPTIONS.no_signing = False
178 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
179 common.OPTIONS.key_passwords = {
180 common.OPTIONS.package_key : None,
181 }
182
183 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800184
185 def test_GetPackageMetadata_abOta_full(self):
186 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
187 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700188 target_info = common.BuildInfo(target_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800189 metadata = GetPackageMetadata(target_info)
190 self.assertDictEqual(
191 {
192 'ota-type' : 'AB',
193 'ota-required-cache' : '0',
194 'post-build' : 'build-fingerprint-target',
195 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800196 'post-sdk-level' : '27',
197 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800198 'post-timestamp' : '1500000000',
199 'pre-device' : 'product-device',
200 },
201 metadata)
202
203 def test_GetPackageMetadata_abOta_incremental(self):
204 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
205 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700206 target_info = common.BuildInfo(target_info_dict, None)
207 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800208 common.OPTIONS.incremental_source = ''
209 metadata = GetPackageMetadata(target_info, source_info)
210 self.assertDictEqual(
211 {
212 'ota-type' : 'AB',
213 'ota-required-cache' : '0',
214 'post-build' : 'build-fingerprint-target',
215 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800216 'post-sdk-level' : '27',
217 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800218 'post-timestamp' : '1500000000',
219 'pre-device' : 'product-device',
220 'pre-build' : 'build-fingerprint-source',
221 'pre-build-incremental' : 'build-version-incremental-source',
222 },
223 metadata)
224
225 def test_GetPackageMetadata_nonAbOta_full(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700226 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800227 metadata = GetPackageMetadata(target_info)
228 self.assertDictEqual(
229 {
230 'ota-type' : 'BLOCK',
231 'post-build' : 'build-fingerprint-target',
232 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800233 'post-sdk-level' : '27',
234 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800235 'post-timestamp' : '1500000000',
236 'pre-device' : 'product-device',
237 },
238 metadata)
239
240 def test_GetPackageMetadata_nonAbOta_incremental(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700241 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
242 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800243 common.OPTIONS.incremental_source = ''
244 metadata = GetPackageMetadata(target_info, source_info)
245 self.assertDictEqual(
246 {
247 'ota-type' : 'BLOCK',
248 'post-build' : 'build-fingerprint-target',
249 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800250 'post-sdk-level' : '27',
251 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800252 'post-timestamp' : '1500000000',
253 'pre-device' : 'product-device',
254 'pre-build' : 'build-fingerprint-source',
255 'pre-build-incremental' : 'build-version-incremental-source',
256 },
257 metadata)
258
259 def test_GetPackageMetadata_wipe(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700260 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800261 common.OPTIONS.wipe_user_data = True
262 metadata = GetPackageMetadata(target_info)
263 self.assertDictEqual(
264 {
265 'ota-type' : 'BLOCK',
266 'ota-wipe' : 'yes',
267 'post-build' : 'build-fingerprint-target',
268 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800269 'post-sdk-level' : '27',
270 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800271 'post-timestamp' : '1500000000',
272 'pre-device' : 'product-device',
273 },
274 metadata)
275
Tao Bao393eeb42019-03-06 16:00:38 -0800276 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700277 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Bao393eeb42019-03-06 16:00:38 -0800278 common.OPTIONS.retrofit_dynamic_partitions = True
279 metadata = GetPackageMetadata(target_info)
280 self.assertDictEqual(
281 {
282 'ota-retrofit-dynamic-partitions' : 'yes',
283 'ota-type' : 'BLOCK',
284 'post-build' : 'build-fingerprint-target',
285 'post-build-incremental' : 'build-version-incremental-target',
286 'post-sdk-level' : '27',
287 'post-security-patch-level' : '2017-12-01',
288 'post-timestamp' : '1500000000',
289 'pre-device' : 'product-device',
290 },
291 metadata)
292
Tao Baodf3a48b2018-01-10 16:30:43 -0800293 @staticmethod
294 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
Tianjiefd3883f2020-04-25 19:55:54 -0700295 (target_info['build.prop'].build_props['ro.build.date.utc'],
296 source_info['build.prop'].build_props['ro.build.date.utc']) = (
297 source_info['build.prop'].build_props['ro.build.date.utc'],
298 target_info['build.prop'].build_props['ro.build.date.utc'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800299
300 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
301 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
302 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
303 self._test_GetPackageMetadata_swapBuildTimestamps(
304 target_info_dict, source_info_dict)
305
Tao Bao1c320f82019-10-04 23:25:12 -0700306 target_info = common.BuildInfo(target_info_dict, None)
307 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800308 common.OPTIONS.incremental_source = ''
309 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
310 source_info)
311
312 def test_GetPackageMetadata_downgrade(self):
313 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
314 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
315 self._test_GetPackageMetadata_swapBuildTimestamps(
316 target_info_dict, source_info_dict)
317
Tao Bao1c320f82019-10-04 23:25:12 -0700318 target_info = common.BuildInfo(target_info_dict, None)
319 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800320 common.OPTIONS.incremental_source = ''
321 common.OPTIONS.downgrade = True
322 common.OPTIONS.wipe_user_data = True
323 metadata = GetPackageMetadata(target_info, source_info)
324 self.assertDictEqual(
325 {
326 'ota-downgrade' : 'yes',
327 'ota-type' : 'BLOCK',
328 'ota-wipe' : 'yes',
329 'post-build' : 'build-fingerprint-target',
330 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800331 'post-sdk-level' : '27',
332 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700333 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800334 'pre-device' : 'product-device',
335 'pre-build' : 'build-fingerprint-source',
336 'pre-build-incremental' : 'build-version-incremental-source',
337 },
338 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800339
Tao Bao82490d32019-04-09 00:12:30 -0700340 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800341 def test_GetTargetFilesZipForSecondaryImages(self):
342 input_file = construct_target_files(secondary=True)
343 target_file = GetTargetFilesZipForSecondaryImages(input_file)
344
345 with zipfile.ZipFile(target_file) as verify_zip:
346 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700347 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800348
349 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800350 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700351 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800352 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800353
Tao Bao3e759462019-09-17 22:43:11 -0700354 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800355 self.assertNotIn('IMAGES/system_other.img', namelist)
356 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700357 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800358
Tao Bao3e759462019-09-17 22:43:11 -0700359 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700360 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
361
Tao Bao82490d32019-04-09 00:12:30 -0700362 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800363 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
364 input_file = construct_target_files(secondary=True)
365 target_file = GetTargetFilesZipForSecondaryImages(
366 input_file, skip_postinstall=True)
367
368 with zipfile.ZipFile(target_file) as verify_zip:
369 namelist = verify_zip.namelist()
370
371 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800372 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700373 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800374
Tao Bao3e759462019-09-17 22:43:11 -0700375 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800376 self.assertNotIn('IMAGES/system_other.img', namelist)
377 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700378 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800379 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
380
Tao Bao82490d32019-04-09 00:12:30 -0700381 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700382 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
383 input_file = construct_target_files(secondary=True)
384 common.ZipDelete(input_file, 'RADIO/bootloader.img')
385 common.ZipDelete(input_file, 'RADIO/modem.img')
386 target_file = GetTargetFilesZipForSecondaryImages(input_file)
387
388 with zipfile.ZipFile(target_file) as verify_zip:
389 namelist = verify_zip.namelist()
390
391 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700392 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700393 self.assertIn(POSTINSTALL_CONFIG, namelist)
394
Tao Bao3e759462019-09-17 22:43:11 -0700395 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700396 self.assertNotIn('IMAGES/system_other.img', namelist)
397 self.assertNotIn('IMAGES/system.map', namelist)
398 self.assertNotIn('RADIO/bootloader.img', namelist)
399 self.assertNotIn('RADIO/modem.img', namelist)
400
Tao Bao82490d32019-04-09 00:12:30 -0700401 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700402 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
403 input_file = construct_target_files(secondary=True)
404 misc_info = '\n'.join([
405 'use_dynamic_partition_size=true',
406 'use_dynamic_partitions=true',
407 'dynamic_partition_list=system vendor product',
408 'super_partition_groups=google_dynamic_partitions',
409 'super_google_dynamic_partitions_group_size=4873781248',
410 'super_google_dynamic_partitions_partition_list=system vendor product',
411 ])
412 dynamic_partitions_info = '\n'.join([
413 'super_partition_groups=google_dynamic_partitions',
414 'super_google_dynamic_partitions_group_size=4873781248',
415 'super_google_dynamic_partitions_partition_list=system vendor product',
416 ])
417
418 with zipfile.ZipFile(input_file, 'a') as append_zip:
419 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
420 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
421 dynamic_partitions_info)
422
423 target_file = GetTargetFilesZipForSecondaryImages(input_file)
424
425 with zipfile.ZipFile(target_file) as verify_zip:
426 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700427 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700428 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700429 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700430
431 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700432 self.assertIn('IMAGES/system.img', namelist)
433 self.assertIn(POSTINSTALL_CONFIG, namelist)
434 self.assertIn('META/misc_info.txt', namelist)
435 self.assertIn('META/dynamic_partitions_info.txt', namelist)
436
Tao Bao3e759462019-09-17 22:43:11 -0700437 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700438 self.assertNotIn('IMAGES/system_other.img', namelist)
439 self.assertNotIn('IMAGES/system.map', namelist)
440
441 # Check the vendor & product are removed from the partitions list.
442 expected_misc_info = misc_info.replace('system vendor product',
443 'system')
444 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
445 'system vendor product', 'system')
446 self.assertEqual(expected_misc_info, updated_misc_info)
447 self.assertEqual(expected_dynamic_partitions_info,
448 updated_dynamic_partitions_info)
449
450 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800451 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
452 input_file = construct_target_files()
453 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
454 with zipfile.ZipFile(target_file) as verify_zip:
455 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
456
Tao Bao82490d32019-04-09 00:12:30 -0700457 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800458 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
459 input_file = construct_target_files()
460 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
461 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
462 with zipfile.ZipFile(target_file) as verify_zip:
463 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
464
Tao Bao3bf8c652018-03-16 12:59:42 -0700465 def _test_FinalizeMetadata(self, large_entry=False):
466 entries = [
467 'required-entry1',
468 'required-entry2',
469 ]
470 zip_file = PropertyFilesTest.construct_zip_package(entries)
471 # Add a large entry of 1 GiB if requested.
472 if large_entry:
473 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
474 zip_fp.writestr(
475 # Using 'zoo' so that the entry stays behind others after signing.
476 'zoo',
477 'A' * 1024 * 1024 * 1024,
478 zipfile.ZIP_STORED)
479
480 metadata = {}
481 output_file = common.MakeTempFile(suffix='.zip')
482 needed_property_files = (
483 TestPropertyFiles(),
484 )
485 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
486 self.assertIn('ota-test-property-files', metadata)
487
Tao Bao82490d32019-04-09 00:12:30 -0700488 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700489 def test_FinalizeMetadata(self):
490 self._test_FinalizeMetadata()
491
Tao Bao82490d32019-04-09 00:12:30 -0700492 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700493 def test_FinalizeMetadata_withNoSigning(self):
494 common.OPTIONS.no_signing = True
495 self._test_FinalizeMetadata()
496
Tao Bao82490d32019-04-09 00:12:30 -0700497 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700498 def test_FinalizeMetadata_largeEntry(self):
499 self._test_FinalizeMetadata(large_entry=True)
500
Tao Bao82490d32019-04-09 00:12:30 -0700501 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700502 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
503 common.OPTIONS.no_signing = True
504 self._test_FinalizeMetadata(large_entry=True)
505
Tao Bao82490d32019-04-09 00:12:30 -0700506 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700507 def test_FinalizeMetadata_insufficientSpace(self):
508 entries = [
509 'required-entry1',
510 'required-entry2',
511 'optional-entry1',
512 'optional-entry2',
513 ]
514 zip_file = PropertyFilesTest.construct_zip_package(entries)
515 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
516 zip_fp.writestr(
517 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
518 # order) after the signing, which will in turn trigger the
519 # InsufficientSpaceException and an automatic retry.
520 'foo-entry1',
521 'A' * 1024 * 1024,
522 zipfile.ZIP_STORED)
523
524 metadata = {}
525 needed_property_files = (
526 TestPropertyFiles(),
527 )
528 output_file = common.MakeTempFile(suffix='.zip')
529 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
530 self.assertIn('ota-test-property-files', metadata)
531
Tao Bao1c320f82019-10-04 23:25:12 -0700532 def test_WriteFingerprintAssertion_without_oem_props(self):
533 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
534 source_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
Tianjiefd3883f2020-04-25 19:55:54 -0700535 source_info_dict['build.prop'].build_props['ro.build.fingerprint'] = (
Tao Bao1c320f82019-10-04 23:25:12 -0700536 'source-build-fingerprint')
537 source_info = common.BuildInfo(source_info_dict, None)
538
539 script_writer = test_utils.MockScriptWriter()
540 WriteFingerprintAssertion(script_writer, target_info, source_info)
541 self.assertEqual(
542 [('AssertSomeFingerprint', 'source-build-fingerprint',
543 'build-fingerprint-target')],
544 script_writer.lines)
545
546 def test_WriteFingerprintAssertion_with_source_oem_props(self):
547 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
548 source_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
549 self.TEST_OEM_DICTS)
550
551 script_writer = test_utils.MockScriptWriter()
552 WriteFingerprintAssertion(script_writer, target_info, source_info)
553 self.assertEqual(
554 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
555 'build-thumbprint')],
556 script_writer.lines)
557
558 def test_WriteFingerprintAssertion_with_target_oem_props(self):
559 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
560 self.TEST_OEM_DICTS)
561 source_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
562
563 script_writer = test_utils.MockScriptWriter()
564 WriteFingerprintAssertion(script_writer, target_info, source_info)
565 self.assertEqual(
566 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
567 'build-thumbprint')],
568 script_writer.lines)
569
570 def test_WriteFingerprintAssertion_with_both_oem_props(self):
571 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
572 self.TEST_OEM_DICTS)
573 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
Tianjiefd3883f2020-04-25 19:55:54 -0700574 source_info_dict['build.prop'].build_props['ro.build.thumbprint'] = (
Tao Bao1c320f82019-10-04 23:25:12 -0700575 'source-build-thumbprint')
576 source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
577
578 script_writer = test_utils.MockScriptWriter()
579 WriteFingerprintAssertion(script_writer, target_info, source_info)
580 self.assertEqual(
581 [('AssertSomeThumbprint', 'build-thumbprint',
582 'source-build-thumbprint')],
583 script_writer.lines)
584
Tao Baoae5e4c32018-03-01 19:30:00 -0800585
Tao Bao69203522018-03-08 16:09:01 -0800586class TestPropertyFiles(PropertyFiles):
587 """A class that extends PropertyFiles for testing purpose."""
588
589 def __init__(self):
590 super(TestPropertyFiles, self).__init__()
591 self.name = 'ota-test-property-files'
592 self.required = (
593 'required-entry1',
594 'required-entry2',
595 )
596 self.optional = (
597 'optional-entry1',
598 'optional-entry2',
599 )
600
601
Tao Bao65b94e92018-10-11 21:57:26 -0700602class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoae5e4c32018-03-01 19:30:00 -0800603
Tao Bao3bf8c652018-03-16 12:59:42 -0700604 def setUp(self):
605 common.OPTIONS.no_signing = False
606
Tao Baof5110492018-03-02 09:47:43 -0800607 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700608 def construct_zip_package(entries):
Tao Baof5110492018-03-02 09:47:43 -0800609 zip_file = common.MakeTempFile(suffix='.zip')
610 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
611 for entry in entries:
612 zip_fp.writestr(
613 entry,
614 entry.replace('.', '-').upper(),
615 zipfile.ZIP_STORED)
616 return zip_file
617
618 @staticmethod
Tao Bao69203522018-03-08 16:09:01 -0800619 def _parse_property_files_string(data):
Tao Baof5110492018-03-02 09:47:43 -0800620 result = {}
621 for token in data.split(','):
622 name, info = token.split(':', 1)
623 result[name] = info
624 return result
625
626 def _verify_entries(self, input_file, tokens, entries):
627 for entry in entries:
628 offset, size = map(int, tokens[entry].split(':'))
629 with open(input_file, 'rb') as input_fp:
630 input_fp.seek(offset)
631 if entry == 'metadata':
632 expected = b'META-INF/COM/ANDROID/METADATA'
633 else:
634 expected = entry.replace('.', '-').upper().encode()
635 self.assertEqual(expected, input_fp.read(size))
636
Tao Bao82490d32019-04-09 00:12:30 -0700637 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800638 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800639 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800640 'required-entry1',
641 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800642 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700643 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800644 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800645 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800646 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800647
Tao Bao69203522018-03-08 16:09:01 -0800648 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800649 self.assertEqual(3, len(tokens))
650 self._verify_entries(zip_file, tokens, entries)
651
Tao Bao69203522018-03-08 16:09:01 -0800652 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800653 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800654 'required-entry1',
655 'required-entry2',
656 'optional-entry1',
657 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800658 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700659 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800660 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800661 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800662 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800663
Tao Bao69203522018-03-08 16:09:01 -0800664 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800665 self.assertEqual(5, len(tokens))
666 self._verify_entries(zip_file, tokens, entries)
667
Tao Bao69203522018-03-08 16:09:01 -0800668 def test_Compute_missingRequiredEntry(self):
669 entries = (
670 'required-entry2',
671 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700672 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800673 property_files = TestPropertyFiles()
674 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
675 self.assertRaises(KeyError, property_files.Compute, zip_fp)
676
Tao Bao82490d32019-04-09 00:12:30 -0700677 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800678 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800679 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800680 'required-entry1',
681 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800682 'META-INF/com/android/metadata',
683 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700684 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800685 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800686 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700687 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800688 zip_fp, reserve_space=False)
689 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800690 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800691
692 self.assertEqual(3, len(tokens))
693 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
694 # streaming metadata.
695 entries[2] = 'metadata'
696 self._verify_entries(zip_file, tokens, entries)
697
Tao Bao82490d32019-04-09 00:12:30 -0700698 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800699 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800700 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800701 'required-entry1',
702 'required-entry2',
703 'optional-entry1',
704 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800705 'META-INF/com/android/metadata',
706 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700707 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800708 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800709 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
710 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700711 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800712 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800713 raw_length = len(raw_metadata)
714
715 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800716 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800717 self.assertEqual(raw_length, len(streaming_metadata))
718
719 # Or pass in insufficient length.
720 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700721 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800722 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800723 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800724 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800725
726 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800727 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800728 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800729 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800730 self.assertEqual(raw_length + 20, len(streaming_metadata))
731 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
732
Tao Baoae5e4c32018-03-01 19:30:00 -0800733 def test_Verify(self):
734 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800735 'required-entry1',
736 'required-entry2',
737 'optional-entry1',
738 'optional-entry2',
739 'META-INF/com/android/metadata',
740 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700741 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800742 property_files = TestPropertyFiles()
743 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
744 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700745 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800746 zip_fp, reserve_space=False)
747
748 # Should pass the test if verification passes.
749 property_files.Verify(zip_fp, raw_metadata)
750
751 # Or raise on verification failure.
752 self.assertRaises(
753 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
754
755
756class StreamingPropertyFilesTest(PropertyFilesTest):
757 """Additional sanity checks specialized for StreamingPropertyFiles."""
758
759 def test_init(self):
760 property_files = StreamingPropertyFiles()
761 self.assertEqual('ota-streaming-property-files', property_files.name)
762 self.assertEqual(
763 (
764 'payload.bin',
765 'payload_properties.txt',
766 ),
767 property_files.required)
768 self.assertEqual(
769 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700770 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800771 'care_map.txt',
772 'compatibility.zip',
773 ),
774 property_files.optional)
775
776 def test_Compute(self):
777 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800778 'payload.bin',
779 'payload_properties.txt',
780 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800781 'compatibility.zip',
782 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700783 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800784 property_files = StreamingPropertyFiles()
785 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
786 property_files_string = property_files.Compute(zip_fp)
787
788 tokens = self._parse_property_files_string(property_files_string)
789 self.assertEqual(5, len(tokens))
790 self._verify_entries(zip_file, tokens, entries)
791
792 def test_Finalize(self):
793 entries = [
794 'payload.bin',
795 'payload_properties.txt',
796 'care_map.txt',
797 'compatibility.zip',
798 'META-INF/com/android/metadata',
799 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700800 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800801 property_files = StreamingPropertyFiles()
802 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700803 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800804 zip_fp, reserve_space=False)
805 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
806 tokens = self._parse_property_files_string(streaming_metadata)
807
808 self.assertEqual(5, len(tokens))
809 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
810 # streaming metadata.
811 entries[4] = 'metadata'
812 self._verify_entries(zip_file, tokens, entries)
813
814 def test_Verify(self):
815 entries = (
816 'payload.bin',
817 'payload_properties.txt',
818 'care_map.txt',
819 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -0800820 'META-INF/com/android/metadata',
821 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700822 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -0800823 property_files = StreamingPropertyFiles()
824 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
825 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700826 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800827 zip_fp, reserve_space=False)
828
829 # Should pass the test if verification passes.
830 property_files.Verify(zip_fp, raw_metadata)
831
832 # Or raise on verification failure.
833 self.assertRaises(
834 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
835
Tao Baofabe0832018-01-17 15:52:28 -0800836
Tao Baob6304672018-03-08 16:28:33 -0800837class AbOtaPropertyFilesTest(PropertyFilesTest):
838 """Additional sanity checks specialized for AbOtaPropertyFiles."""
839
840 # The size for payload and metadata signature size.
841 SIGNATURE_SIZE = 256
842
843 def setUp(self):
844 self.testdata_dir = test_utils.get_testdata_dir()
845 self.assertTrue(os.path.exists(self.testdata_dir))
846
847 common.OPTIONS.wipe_user_data = False
848 common.OPTIONS.payload_signer = None
849 common.OPTIONS.payload_signer_args = None
850 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
851 common.OPTIONS.key_passwords = {
852 common.OPTIONS.package_key : None,
853 }
854
855 def test_init(self):
856 property_files = AbOtaPropertyFiles()
857 self.assertEqual('ota-property-files', property_files.name)
858 self.assertEqual(
859 (
860 'payload.bin',
861 'payload_properties.txt',
862 ),
863 property_files.required)
864 self.assertEqual(
865 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700866 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -0800867 'care_map.txt',
868 'compatibility.zip',
869 ),
870 property_files.optional)
871
Tao Bao82490d32019-04-09 00:12:30 -0700872 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800873 def test_GetPayloadMetadataOffsetAndSize(self):
874 target_file = construct_target_files()
875 payload = Payload()
876 payload.Generate(target_file)
877
878 payload_signer = PayloadSigner()
879 payload.Sign(payload_signer)
880
881 output_file = common.MakeTempFile(suffix='.zip')
882 with zipfile.ZipFile(output_file, 'w') as output_zip:
883 payload.WriteToZip(output_zip)
884
885 # Find out the payload metadata offset and size.
886 property_files = AbOtaPropertyFiles()
887 with zipfile.ZipFile(output_file) as input_zip:
888 # pylint: disable=protected-access
889 payload_offset, metadata_total = (
890 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
891
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700892 # The signature proto has the following format (details in
893 # /platform/system/update_engine/update_metadata.proto):
894 # message Signature {
895 # optional uint32 version = 1;
896 # optional bytes data = 2;
897 # optional fixed32 unpadded_signature_size = 3;
898 # }
899 #
900 # According to the protobuf encoding, the tail of the signature message will
901 # be [signature string(256 bytes) + encoding of the fixed32 number 256]. And
902 # 256 is encoded as 'x1d\x00\x01\x00\x00':
903 # [3 (field number) << 3 | 5 (type) + byte reverse of 0x100 (256)].
904 # Details in (https://developers.google.com/protocol-buffers/docs/encoding)
905 signature_tail_length = self.SIGNATURE_SIZE + 5
906 self.assertGreater(metadata_total, signature_tail_length)
Tao Baob6304672018-03-08 16:28:33 -0800907 with open(output_file, 'rb') as verify_fp:
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700908 verify_fp.seek(payload_offset + metadata_total - signature_tail_length)
909 metadata_signature_proto_tail = verify_fp.read(signature_tail_length)
910
911 self.assertEqual(b'\x1d\x00\x01\x00\x00',
912 metadata_signature_proto_tail[-5:])
913 metadata_signature = metadata_signature_proto_tail[:-5]
Tao Baob6304672018-03-08 16:28:33 -0800914
915 # Now we extract the metadata hash via brillo_update_payload script, which
916 # will serve as the oracle result.
917 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
918 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
919 cmd = ['brillo_update_payload', 'hash',
920 '--unsigned_payload', payload.payload_file,
921 '--signature_size', str(self.SIGNATURE_SIZE),
922 '--metadata_hash_file', metadata_sig_file,
923 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -0700924 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -0800925 stdoutdata, _ = proc.communicate()
926 self.assertEqual(
927 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -0700928 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -0800929
930 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
931
932 # Finally we can compare the two signatures.
933 with open(signed_metadata_sig_file, 'rb') as verify_fp:
934 self.assertEqual(verify_fp.read(), metadata_signature)
935
936 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700937 def construct_zip_package_withValidPayload(with_metadata=False):
938 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -0800939 target_file = construct_target_files()
940 payload = Payload()
941 payload.Generate(target_file)
942
943 payload_signer = PayloadSigner()
944 payload.Sign(payload_signer)
945
946 zip_file = common.MakeTempFile(suffix='.zip')
947 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
948 # 'payload.bin',
949 payload.WriteToZip(zip_fp)
950
951 # Other entries.
952 entries = ['care_map.txt', 'compatibility.zip']
953
954 # Put META-INF/com/android/metadata if needed.
955 if with_metadata:
956 entries.append('META-INF/com/android/metadata')
957
958 for entry in entries:
959 zip_fp.writestr(
960 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
961
962 return zip_file
963
Tao Bao82490d32019-04-09 00:12:30 -0700964 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800965 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700966 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -0800967 property_files = AbOtaPropertyFiles()
968 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
969 property_files_string = property_files.Compute(zip_fp)
970
971 tokens = self._parse_property_files_string(property_files_string)
972 # "6" indcludes the four entries above, one metadata entry, and one entry
973 # for payload-metadata.bin.
974 self.assertEqual(6, len(tokens))
975 self._verify_entries(
976 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
977
Tao Bao82490d32019-04-09 00:12:30 -0700978 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800979 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700980 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800981 property_files = AbOtaPropertyFiles()
982 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700983 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800984 zip_fp, reserve_space=False)
985 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
986
987 tokens = self._parse_property_files_string(property_files_string)
988 # "6" indcludes the four entries above, one metadata entry, and one entry
989 # for payload-metadata.bin.
990 self.assertEqual(6, len(tokens))
991 self._verify_entries(
992 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
993
Tao Bao82490d32019-04-09 00:12:30 -0700994 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800995 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700996 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800997 property_files = AbOtaPropertyFiles()
998 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700999 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -08001000 zip_fp, reserve_space=False)
1001
1002 property_files.Verify(zip_fp, raw_metadata)
1003
1004
Tao Baoc0746f42018-02-21 13:17:22 -08001005class NonAbOtaPropertyFilesTest(PropertyFilesTest):
1006 """Additional sanity checks specialized for NonAbOtaPropertyFiles."""
1007
1008 def test_init(self):
1009 property_files = NonAbOtaPropertyFiles()
1010 self.assertEqual('ota-property-files', property_files.name)
1011 self.assertEqual((), property_files.required)
1012 self.assertEqual((), property_files.optional)
1013
1014 def test_Compute(self):
1015 entries = ()
Tao Bao3bf8c652018-03-16 12:59:42 -07001016 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001017 property_files = NonAbOtaPropertyFiles()
1018 with zipfile.ZipFile(zip_file) as zip_fp:
1019 property_files_string = property_files.Compute(zip_fp)
1020
1021 tokens = self._parse_property_files_string(property_files_string)
1022 self.assertEqual(1, len(tokens))
1023 self._verify_entries(zip_file, tokens, entries)
1024
1025 def test_Finalize(self):
1026 entries = [
1027 'META-INF/com/android/metadata',
1028 ]
Tao Bao3bf8c652018-03-16 12:59:42 -07001029 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001030 property_files = NonAbOtaPropertyFiles()
1031 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001032 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001033 zip_fp, reserve_space=False)
1034 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1035 tokens = self._parse_property_files_string(property_files_string)
1036
1037 self.assertEqual(1, len(tokens))
1038 # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
1039 entries[0] = 'metadata'
1040 self._verify_entries(zip_file, tokens, entries)
1041
1042 def test_Verify(self):
1043 entries = (
1044 'META-INF/com/android/metadata',
1045 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001046 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001047 property_files = NonAbOtaPropertyFiles()
1048 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001049 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001050 zip_fp, reserve_space=False)
1051
1052 property_files.Verify(zip_fp, raw_metadata)
1053
1054
Tao Bao65b94e92018-10-11 21:57:26 -07001055class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -08001056
1057 SIGFILE = 'sigfile.bin'
1058 SIGNED_SIGFILE = 'signed-sigfile.bin'
1059
1060 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001061 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -08001062 self.assertTrue(os.path.exists(self.testdata_dir))
1063
1064 common.OPTIONS.payload_signer = None
1065 common.OPTIONS.payload_signer_args = []
1066 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1067 common.OPTIONS.key_passwords = {
1068 common.OPTIONS.package_key : None,
1069 }
1070
Tao Baofabe0832018-01-17 15:52:28 -08001071 def _assertFilesEqual(self, file1, file2):
1072 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
1073 self.assertEqual(fp1.read(), fp2.read())
1074
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001075 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001076 def test_init(self):
1077 payload_signer = PayloadSigner()
1078 self.assertEqual('openssl', payload_signer.signer)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001079 self.assertEqual(256, payload_signer.maximum_signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001080
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001081 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001082 def test_init_withPassword(self):
1083 common.OPTIONS.package_key = os.path.join(
1084 self.testdata_dir, 'testkey_with_passwd')
1085 common.OPTIONS.key_passwords = {
1086 common.OPTIONS.package_key : 'foo',
1087 }
1088 payload_signer = PayloadSigner()
1089 self.assertEqual('openssl', payload_signer.signer)
1090
1091 def test_init_withExternalSigner(self):
1092 common.OPTIONS.payload_signer = 'abc'
1093 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001094 common.OPTIONS.payload_signer_maximum_signature_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -08001095 payload_signer = PayloadSigner()
1096 self.assertEqual('abc', payload_signer.signer)
1097 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001098 self.assertEqual(512, payload_signer.maximum_signature_size)
xunchang376cc7c2019-04-08 23:04:58 -07001099
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001100 @test_utils.SkipIfExternalToolsUnavailable()
1101 def test_GetMaximumSignatureSizeInBytes_512Bytes(self):
xunchang376cc7c2019-04-08 23:04:58 -07001102 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -07001103 # pylint: disable=protected-access
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001104 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1105 self.assertEqual(512, signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001106
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001107 @test_utils.SkipIfExternalToolsUnavailable()
1108 def test_GetMaximumSignatureSizeInBytes_ECKey(self):
1109 signing_key = os.path.join(self.testdata_dir, 'testkey_EC.key')
1110 # pylint: disable=protected-access
1111 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1112 self.assertEqual(72, signature_size)
1113
1114 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001115 def test_Sign(self):
1116 payload_signer = PayloadSigner()
1117 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1118 signed_file = payload_signer.Sign(input_file)
1119
1120 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1121 self._assertFilesEqual(verify_file, signed_file)
1122
1123 def test_Sign_withExternalSigner_openssl(self):
1124 """Uses openssl as the external payload signer."""
1125 common.OPTIONS.payload_signer = 'openssl'
1126 common.OPTIONS.payload_signer_args = [
1127 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
1128 os.path.join(self.testdata_dir, 'testkey.pk8'),
1129 '-pkeyopt', 'digest:sha256']
1130 payload_signer = PayloadSigner()
1131 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1132 signed_file = payload_signer.Sign(input_file)
1133
1134 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1135 self._assertFilesEqual(verify_file, signed_file)
1136
1137 def test_Sign_withExternalSigner_script(self):
1138 """Uses testdata/payload_signer.sh as the external payload signer."""
1139 common.OPTIONS.payload_signer = os.path.join(
1140 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -07001141 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -08001142 common.OPTIONS.payload_signer_args = [
1143 os.path.join(self.testdata_dir, 'testkey.pk8')]
1144 payload_signer = PayloadSigner()
1145 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1146 signed_file = payload_signer.Sign(input_file)
1147
1148 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1149 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001150
1151
Tao Bao65b94e92018-10-11 21:57:26 -07001152class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001153
1154 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001155 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001156 self.assertTrue(os.path.exists(self.testdata_dir))
1157
1158 common.OPTIONS.wipe_user_data = False
1159 common.OPTIONS.payload_signer = None
1160 common.OPTIONS.payload_signer_args = None
1161 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1162 common.OPTIONS.key_passwords = {
1163 common.OPTIONS.package_key : None,
1164 }
1165
Tao Baoc7b403a2018-01-30 18:19:04 -08001166 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001167 def _create_payload_full(secondary=False):
1168 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001169 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001170 payload.Generate(target_file)
1171 return payload
1172
Tao Baof7140c02018-01-30 17:09:24 -08001173 @staticmethod
1174 def _create_payload_incremental():
1175 target_file = construct_target_files()
1176 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001177 payload = Payload()
1178 payload.Generate(target_file, source_file)
1179 return payload
1180
Tao Bao82490d32019-04-09 00:12:30 -07001181 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001182 def test_Generate_full(self):
1183 payload = self._create_payload_full()
1184 self.assertTrue(os.path.exists(payload.payload_file))
1185
Tao Bao82490d32019-04-09 00:12:30 -07001186 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001187 def test_Generate_incremental(self):
1188 payload = self._create_payload_incremental()
1189 self.assertTrue(os.path.exists(payload.payload_file))
1190
Tao Bao82490d32019-04-09 00:12:30 -07001191 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001192 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001193 target_file = construct_target_files()
1194 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001195 payload = Payload()
1196 # This should work the same as calling payload.Generate(target_file,
1197 # source_file).
1198 payload.Generate(
1199 target_file, additional_args=["--source_image", source_file])
1200 self.assertTrue(os.path.exists(payload.payload_file))
1201
Tao Bao82490d32019-04-09 00:12:30 -07001202 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001203 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001204 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001205 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1206 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001207 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001208
Tao Bao82490d32019-04-09 00:12:30 -07001209 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001210 def test_Sign_full(self):
1211 payload = self._create_payload_full()
1212 payload.Sign(PayloadSigner())
1213
1214 output_file = common.MakeTempFile(suffix='.zip')
1215 with zipfile.ZipFile(output_file, 'w') as output_zip:
1216 payload.WriteToZip(output_zip)
1217
1218 import check_ota_package_signature
1219 check_ota_package_signature.VerifyAbOtaPayload(
1220 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1221 output_file)
1222
Tao Bao82490d32019-04-09 00:12:30 -07001223 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001224 def test_Sign_incremental(self):
1225 payload = self._create_payload_incremental()
1226 payload.Sign(PayloadSigner())
1227
1228 output_file = common.MakeTempFile(suffix='.zip')
1229 with zipfile.ZipFile(output_file, 'w') as output_zip:
1230 payload.WriteToZip(output_zip)
1231
1232 import check_ota_package_signature
1233 check_ota_package_signature.VerifyAbOtaPayload(
1234 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1235 output_file)
1236
Tao Bao82490d32019-04-09 00:12:30 -07001237 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001238 def test_Sign_withDataWipe(self):
1239 common.OPTIONS.wipe_user_data = True
1240 payload = self._create_payload_full()
1241 payload.Sign(PayloadSigner())
1242
1243 with open(payload.payload_properties) as properties_fp:
1244 self.assertIn("POWERWASH=1", properties_fp.read())
1245
Tao Bao82490d32019-04-09 00:12:30 -07001246 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001247 def test_Sign_secondary(self):
1248 payload = self._create_payload_full(secondary=True)
1249 payload.Sign(PayloadSigner())
1250
1251 with open(payload.payload_properties) as properties_fp:
1252 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1253
Tao Bao82490d32019-04-09 00:12:30 -07001254 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001255 def test_Sign_badSigner(self):
1256 """Tests that signing failure can be captured."""
1257 payload = self._create_payload_full()
1258 payload_signer = PayloadSigner()
1259 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001260 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001261
Tao Bao82490d32019-04-09 00:12:30 -07001262 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001263 def test_WriteToZip(self):
1264 payload = self._create_payload_full()
1265 payload.Sign(PayloadSigner())
1266
1267 output_file = common.MakeTempFile(suffix='.zip')
1268 with zipfile.ZipFile(output_file, 'w') as output_zip:
1269 payload.WriteToZip(output_zip)
1270
1271 with zipfile.ZipFile(output_file) as verify_zip:
1272 # First make sure we have the essential entries.
1273 namelist = verify_zip.namelist()
1274 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1275 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1276
1277 # Then assert these entries are stored.
1278 for entry_info in verify_zip.infolist():
1279 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1280 Payload.PAYLOAD_PROPERTIES_TXT):
1281 continue
1282 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1283
Tao Bao82490d32019-04-09 00:12:30 -07001284 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001285 def test_WriteToZip_unsignedPayload(self):
1286 """Unsigned payloads should not be allowed to be written to zip."""
1287 payload = self._create_payload_full()
1288
1289 output_file = common.MakeTempFile(suffix='.zip')
1290 with zipfile.ZipFile(output_file, 'w') as output_zip:
1291 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1292
1293 # Also test with incremental payload.
1294 payload = self._create_payload_incremental()
1295
1296 output_file = common.MakeTempFile(suffix='.zip')
1297 with zipfile.ZipFile(output_file, 'w') as output_zip:
1298 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001299
Tao Bao82490d32019-04-09 00:12:30 -07001300 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001301 def test_WriteToZip_secondary(self):
1302 payload = self._create_payload_full(secondary=True)
1303 payload.Sign(PayloadSigner())
1304
1305 output_file = common.MakeTempFile(suffix='.zip')
1306 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001307 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001308
1309 with zipfile.ZipFile(output_file) as verify_zip:
1310 # First make sure we have the essential entries.
1311 namelist = verify_zip.namelist()
1312 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1313 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1314
1315 # Then assert these entries are stored.
1316 for entry_info in verify_zip.infolist():
1317 if entry_info.filename not in (
1318 Payload.SECONDARY_PAYLOAD_BIN,
1319 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1320 continue
1321 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
Tianjie0d2fcd52020-05-06 21:54:21 -07001322
1323
1324class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
1325 MISC_INFO = [
1326 'recovery_api_version=3',
1327 'fstab_version=2',
1328 'recovery_as_boot=true',
1329 ]
1330
1331 BUILD_PROP = [
1332 'ro.build.version.release=version-release',
1333 'ro.build.id=build-id',
1334 'ro.build.version.incremental=version-incremental',
1335 'ro.build.type=build-type',
1336 'ro.build.tags=build-tags',
1337 ]
1338
1339 VENDOR_BUILD_PROP = [
1340 'ro.product.vendor.brand=vendor-product-brand',
1341 'ro.product.vendor.name=vendor-product-name',
1342 'ro.product.vendor.device=vendor-product-device'
1343 ]
1344
1345 def setUp(self):
1346 common.OPTIONS.oem_dicts = None
1347 self.test_dir = common.MakeTempDir()
1348 self.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)})
1349
1350 def writeFiles(self, contents_dict):
1351 for path, content in contents_dict.items():
1352 abs_path = os.path.join(self.test_dir, path)
1353 dir_name = os.path.dirname(abs_path)
1354 if not os.path.exists(dir_name):
1355 os.makedirs(dir_name)
1356 with open(abs_path, 'w') as f:
1357 f.write(content)
1358
1359 @staticmethod
1360 def constructFingerprint(prefix):
1361 return '{}:version-release/build-id/version-incremental:' \
1362 'build-type/build-tags'.format(prefix)
1363
1364 def test_CalculatePossibleFingerprints_no_dynamic_fingerprint(self):
1365 build_prop = copy.deepcopy(self.BUILD_PROP)
1366 build_prop.extend([
1367 'ro.product.brand=product-brand',
1368 'ro.product.name=product-name',
1369 'ro.product.device=product-device',
1370 ])
1371 self.writeFiles({
1372 'SYSTEM/build.prop': '\n'.join(build_prop),
1373 'VENDOR/build.prop': '\n'.join(self.VENDOR_BUILD_PROP),
1374 })
1375 common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
1376
1377 self.assertEqual({
1378 self.constructFingerprint('product-brand/product-name/product-device')
1379 }, CalculateRuntimeFingerprints())
1380
1381 def test_CalculatePossibleFingerprints_single_override(self):
1382 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1383 vendor_build_prop.extend([
1384 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1385 ])
1386 self.writeFiles({
1387 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1388 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1389 'VENDOR/etc/build_std.prop':
1390 'ro.product.vendor.name=vendor-product-std',
1391 'VENDOR/etc/build_pro.prop':
1392 'ro.product.vendor.name=vendor-product-pro',
1393 })
1394 common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
1395 common.OPTIONS.boot_variable_values = {
1396 'ro.boot.sku_name': ['std', 'pro']
1397 }
1398
1399 self.assertEqual({
1400 self.constructFingerprint(
1401 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1402 self.constructFingerprint(
1403 'vendor-product-brand/vendor-product-std/vendor-product-device'),
1404 self.constructFingerprint(
1405 'vendor-product-brand/vendor-product-pro/vendor-product-device'),
1406 }, CalculateRuntimeFingerprints())
1407
1408 def test_CalculatePossibleFingerprints_multiple_overrides(self):
1409 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1410 vendor_build_prop.extend([
1411 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1412 'import /vendor/etc/build_${ro.boot.device_name}.prop',
1413 ])
1414 self.writeFiles({
1415 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1416 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1417 'VENDOR/etc/build_std.prop':
1418 'ro.product.vendor.name=vendor-product-std',
1419 'VENDOR/etc/build_product1.prop':
1420 'ro.product.vendor.device=vendor-device-product1',
1421 'VENDOR/etc/build_pro.prop':
1422 'ro.product.vendor.name=vendor-product-pro',
1423 'VENDOR/etc/build_product2.prop':
1424 'ro.product.vendor.device=vendor-device-product2',
1425 })
1426 common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
1427 common.OPTIONS.boot_variable_values = {
1428 'ro.boot.sku_name': ['std', 'pro'],
1429 'ro.boot.device_name': ['product1', 'product2'],
1430 }
1431
1432 self.assertEqual({
1433 self.constructFingerprint(
1434 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1435 self.constructFingerprint(
1436 'vendor-product-brand/vendor-product-std/vendor-device-product1'),
1437 self.constructFingerprint(
1438 'vendor-product-brand/vendor-product-pro/vendor-device-product1'),
1439 self.constructFingerprint(
1440 'vendor-product-brand/vendor-product-std/vendor-device-product2'),
1441 self.constructFingerprint(
1442 'vendor-product-brand/vendor-product-pro/vendor-device-product2'),
1443 }, CalculateRuntimeFingerprints())