blob: 52aa48703176b38ea442ab36f6c0ffdb59263e0d [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
Kelvin Zhangcff4d762020-07-29 16:37:51 -040024from ota_utils import CalculateRuntimeDevicesAndFingerprints
Tao Bao481bab82017-12-21 11:23:09 -080025from ota_from_target_files import (
Tao Bao1c320f82019-10-04 23:25:12 -070026 _LoadOemDicts, AbOtaPropertyFiles, FinalizeMetadata,
Tao Bao3bf8c652018-03-16 12:59:42 -070027 GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
Kelvin Zhangcff4d762020-07-29 16:37:51 -040028 GetTargetFilesZipWithoutPostinstallConfig,
Tao Bao69203522018-03-08 16:09:01 -080029 Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
Kelvin Zhangcff4d762020-07-29 16:37:51 -040030 StreamingPropertyFiles)
31from non_ab_ota import NonAbOtaPropertyFiles
32from test_utils import PropertyFilesTestCase
Tao Baofabe0832018-01-17 15:52:28 -080033
Tao Baof7140c02018-01-30 17:09:24 -080034def construct_target_files(secondary=False):
35 """Returns a target-files.zip file for generating OTA packages."""
36 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
37 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
38 # META/update_engine_config.txt
39 target_files_zip.writestr(
40 'META/update_engine_config.txt',
41 "PAYLOAD_MAJOR_VERSION=2\nPAYLOAD_MINOR_VERSION=4\n")
42
Tao Bao15a146a2018-02-21 16:06:59 -080043 # META/postinstall_config.txt
44 target_files_zip.writestr(
45 POSTINSTALL_CONFIG,
46 '\n'.join([
47 "RUN_POSTINSTALL_system=true",
48 "POSTINSTALL_PATH_system=system/bin/otapreopt_script",
49 "FILESYSTEM_TYPE_system=ext4",
50 "POSTINSTALL_OPTIONAL_system=true",
51 ]))
52
Tao Bao5277d102018-04-17 23:47:21 -070053 ab_partitions = [
54 ('IMAGES', 'boot'),
55 ('IMAGES', 'system'),
56 ('IMAGES', 'vendor'),
57 ('RADIO', 'bootloader'),
58 ('RADIO', 'modem'),
59 ]
Tao Baof7140c02018-01-30 17:09:24 -080060 # META/ab_partitions.txt
Tao Baof7140c02018-01-30 17:09:24 -080061 target_files_zip.writestr(
62 'META/ab_partitions.txt',
Tao Bao5277d102018-04-17 23:47:21 -070063 '\n'.join([partition[1] for partition in ab_partitions]))
Tao Baof7140c02018-01-30 17:09:24 -080064
Kelvin Zhangc693d952020-07-22 19:21:22 -040065 # Create fake images for each of them.
Tao Bao5277d102018-04-17 23:47:21 -070066 for path, partition in ab_partitions:
67 target_files_zip.writestr(
68 '{}/{}.img'.format(path, partition),
69 os.urandom(len(partition)))
Tao Baof7140c02018-01-30 17:09:24 -080070
Tao Bao5277d102018-04-17 23:47:21 -070071 # system_other shouldn't appear in META/ab_partitions.txt.
Tao Baof7140c02018-01-30 17:09:24 -080072 if secondary:
73 target_files_zip.writestr('IMAGES/system_other.img',
74 os.urandom(len("system_other")))
75
76 return target_files
77
78
Tao Bao65b94e92018-10-11 21:57:26 -070079class LoadOemDictsTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -080080
81 def test_NoneDict(self):
82 self.assertIsNone(_LoadOemDicts(None))
83
84 def test_SingleDict(self):
85 dict_file = common.MakeTempFile()
86 with open(dict_file, 'w') as dict_fp:
87 dict_fp.write('abc=1\ndef=2\nxyz=foo\na.b.c=bar\n')
88
89 oem_dicts = _LoadOemDicts([dict_file])
90 self.assertEqual(1, len(oem_dicts))
91 self.assertEqual('foo', oem_dicts[0]['xyz'])
92 self.assertEqual('bar', oem_dicts[0]['a.b.c'])
93
94 def test_MultipleDicts(self):
95 oem_source = []
96 for i in range(3):
97 dict_file = common.MakeTempFile()
98 with open(dict_file, 'w') as dict_fp:
99 dict_fp.write(
100 'ro.build.index={}\ndef=2\nxyz=foo\na.b.c=bar\n'.format(i))
101 oem_source.append(dict_file)
102
103 oem_dicts = _LoadOemDicts(oem_source)
104 self.assertEqual(3, len(oem_dicts))
105 for i, oem_dict in enumerate(oem_dicts):
106 self.assertEqual('2', oem_dict['def'])
107 self.assertEqual('foo', oem_dict['xyz'])
108 self.assertEqual('bar', oem_dict['a.b.c'])
109 self.assertEqual('{}'.format(i), oem_dict['ro.build.index'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800110
111
Tao Bao65b94e92018-10-11 21:57:26 -0700112class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baodf3a48b2018-01-10 16:30:43 -0800113 TEST_TARGET_INFO_DICT = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000114 'build.prop': common.PartitionBuildProps.FromDictionary(
115 'system', {
116 'ro.product.device': 'product-device',
117 'ro.build.fingerprint': 'build-fingerprint-target',
118 'ro.build.version.incremental': 'build-version-incremental-target',
119 'ro.build.version.sdk': '27',
120 'ro.build.version.security_patch': '2017-12-01',
121 'ro.build.date.utc': '1500000000'}
122 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800123 }
124
125 TEST_SOURCE_INFO_DICT = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000126 'build.prop': common.PartitionBuildProps.FromDictionary(
127 'system', {
128 'ro.product.device': 'product-device',
129 'ro.build.fingerprint': 'build-fingerprint-source',
130 'ro.build.version.incremental': 'build-version-incremental-source',
131 'ro.build.version.sdk': '25',
132 'ro.build.version.security_patch': '2016-12-01',
133 'ro.build.date.utc': '1400000000'}
134 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800135 }
136
Tao Bao1c320f82019-10-04 23:25:12 -0700137 TEST_INFO_DICT_USES_OEM_PROPS = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000138 'build.prop': common.PartitionBuildProps.FromDictionary(
139 'system', {
140 'ro.product.name': 'product-name',
141 'ro.build.thumbprint': 'build-thumbprint',
142 'ro.build.bar': 'build-bar'}
143 ),
144 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
145 'vendor', {
146 'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
147 ),
148 'property1': 'value1',
149 'property2': 4096,
150 'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
Tao Bao1c320f82019-10-04 23:25:12 -0700151 }
152
Tao Bao1c320f82019-10-04 23:25:12 -0700153
Tao Baodf3a48b2018-01-10 16:30:43 -0800154 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700155 self.testdata_dir = test_utils.get_testdata_dir()
156 self.assertTrue(os.path.exists(self.testdata_dir))
157
Tao Baodf3a48b2018-01-10 16:30:43 -0800158 # Reset the global options as in ota_from_target_files.py.
159 common.OPTIONS.incremental_source = None
160 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800161 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800162 common.OPTIONS.timestamp = False
163 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700164 common.OPTIONS.no_signing = False
165 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
166 common.OPTIONS.key_passwords = {
167 common.OPTIONS.package_key : None,
168 }
169
170 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800171
172 def test_GetPackageMetadata_abOta_full(self):
173 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
174 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700175 target_info = common.BuildInfo(target_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800176 metadata = GetPackageMetadata(target_info)
177 self.assertDictEqual(
178 {
179 'ota-type' : 'AB',
180 'ota-required-cache' : '0',
181 'post-build' : 'build-fingerprint-target',
182 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800183 'post-sdk-level' : '27',
184 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800185 'post-timestamp' : '1500000000',
186 'pre-device' : 'product-device',
187 },
188 metadata)
189
190 def test_GetPackageMetadata_abOta_incremental(self):
191 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
192 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700193 target_info = common.BuildInfo(target_info_dict, None)
194 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800195 common.OPTIONS.incremental_source = ''
196 metadata = GetPackageMetadata(target_info, source_info)
197 self.assertDictEqual(
198 {
199 'ota-type' : 'AB',
200 'ota-required-cache' : '0',
201 'post-build' : 'build-fingerprint-target',
202 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800203 'post-sdk-level' : '27',
204 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800205 'post-timestamp' : '1500000000',
206 'pre-device' : 'product-device',
207 'pre-build' : 'build-fingerprint-source',
208 'pre-build-incremental' : 'build-version-incremental-source',
209 },
210 metadata)
211
212 def test_GetPackageMetadata_nonAbOta_full(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700213 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800214 metadata = GetPackageMetadata(target_info)
215 self.assertDictEqual(
216 {
217 'ota-type' : 'BLOCK',
218 'post-build' : 'build-fingerprint-target',
219 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800220 'post-sdk-level' : '27',
221 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800222 'post-timestamp' : '1500000000',
223 'pre-device' : 'product-device',
224 },
225 metadata)
226
227 def test_GetPackageMetadata_nonAbOta_incremental(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700228 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
229 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800230 common.OPTIONS.incremental_source = ''
231 metadata = GetPackageMetadata(target_info, source_info)
232 self.assertDictEqual(
233 {
234 'ota-type' : 'BLOCK',
235 'post-build' : 'build-fingerprint-target',
236 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800237 'post-sdk-level' : '27',
238 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800239 'post-timestamp' : '1500000000',
240 'pre-device' : 'product-device',
241 'pre-build' : 'build-fingerprint-source',
242 'pre-build-incremental' : 'build-version-incremental-source',
243 },
244 metadata)
245
246 def test_GetPackageMetadata_wipe(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700247 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800248 common.OPTIONS.wipe_user_data = True
249 metadata = GetPackageMetadata(target_info)
250 self.assertDictEqual(
251 {
252 'ota-type' : 'BLOCK',
253 'ota-wipe' : 'yes',
254 'post-build' : 'build-fingerprint-target',
255 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800256 'post-sdk-level' : '27',
257 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800258 'post-timestamp' : '1500000000',
259 'pre-device' : 'product-device',
260 },
261 metadata)
262
Tao Bao393eeb42019-03-06 16:00:38 -0800263 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700264 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Bao393eeb42019-03-06 16:00:38 -0800265 common.OPTIONS.retrofit_dynamic_partitions = True
266 metadata = GetPackageMetadata(target_info)
267 self.assertDictEqual(
268 {
269 'ota-retrofit-dynamic-partitions' : 'yes',
270 'ota-type' : 'BLOCK',
271 'post-build' : 'build-fingerprint-target',
272 'post-build-incremental' : 'build-version-incremental-target',
273 'post-sdk-level' : '27',
274 'post-security-patch-level' : '2017-12-01',
275 'post-timestamp' : '1500000000',
276 'pre-device' : 'product-device',
277 },
278 metadata)
279
Tao Baodf3a48b2018-01-10 16:30:43 -0800280 @staticmethod
281 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000282 (target_info['build.prop'].build_props['ro.build.date.utc'],
283 source_info['build.prop'].build_props['ro.build.date.utc']) = (
284 source_info['build.prop'].build_props['ro.build.date.utc'],
285 target_info['build.prop'].build_props['ro.build.date.utc'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800286
287 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
288 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
289 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
290 self._test_GetPackageMetadata_swapBuildTimestamps(
291 target_info_dict, source_info_dict)
292
Tao Bao1c320f82019-10-04 23:25:12 -0700293 target_info = common.BuildInfo(target_info_dict, None)
294 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800295 common.OPTIONS.incremental_source = ''
296 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
297 source_info)
298
299 def test_GetPackageMetadata_downgrade(self):
300 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
301 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
302 self._test_GetPackageMetadata_swapBuildTimestamps(
303 target_info_dict, source_info_dict)
304
Tao Bao1c320f82019-10-04 23:25:12 -0700305 target_info = common.BuildInfo(target_info_dict, None)
306 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800307 common.OPTIONS.incremental_source = ''
308 common.OPTIONS.downgrade = True
309 common.OPTIONS.wipe_user_data = True
310 metadata = GetPackageMetadata(target_info, source_info)
311 self.assertDictEqual(
312 {
313 'ota-downgrade' : 'yes',
314 'ota-type' : 'BLOCK',
315 'ota-wipe' : 'yes',
316 'post-build' : 'build-fingerprint-target',
317 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800318 'post-sdk-level' : '27',
319 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700320 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800321 'pre-device' : 'product-device',
322 'pre-build' : 'build-fingerprint-source',
323 'pre-build-incremental' : 'build-version-incremental-source',
324 },
325 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800326
Tao Bao82490d32019-04-09 00:12:30 -0700327 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800328 def test_GetTargetFilesZipForSecondaryImages(self):
329 input_file = construct_target_files(secondary=True)
330 target_file = GetTargetFilesZipForSecondaryImages(input_file)
331
332 with zipfile.ZipFile(target_file) as verify_zip:
333 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700334 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800335
336 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800337 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700338 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800339 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800340
Tao Bao3e759462019-09-17 22:43:11 -0700341 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800342 self.assertNotIn('IMAGES/system_other.img', namelist)
343 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700344 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800345
Tao Bao3e759462019-09-17 22:43:11 -0700346 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700347 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
348
Tao Bao82490d32019-04-09 00:12:30 -0700349 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800350 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
351 input_file = construct_target_files(secondary=True)
352 target_file = GetTargetFilesZipForSecondaryImages(
353 input_file, skip_postinstall=True)
354
355 with zipfile.ZipFile(target_file) as verify_zip:
356 namelist = verify_zip.namelist()
357
358 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800359 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700360 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800361
Tao Bao3e759462019-09-17 22:43:11 -0700362 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800363 self.assertNotIn('IMAGES/system_other.img', namelist)
364 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700365 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800366 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
367
Tao Bao82490d32019-04-09 00:12:30 -0700368 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700369 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
370 input_file = construct_target_files(secondary=True)
371 common.ZipDelete(input_file, 'RADIO/bootloader.img')
372 common.ZipDelete(input_file, 'RADIO/modem.img')
373 target_file = GetTargetFilesZipForSecondaryImages(input_file)
374
375 with zipfile.ZipFile(target_file) as verify_zip:
376 namelist = verify_zip.namelist()
377
378 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700379 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700380 self.assertIn(POSTINSTALL_CONFIG, namelist)
381
Tao Bao3e759462019-09-17 22:43:11 -0700382 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700383 self.assertNotIn('IMAGES/system_other.img', namelist)
384 self.assertNotIn('IMAGES/system.map', namelist)
385 self.assertNotIn('RADIO/bootloader.img', namelist)
386 self.assertNotIn('RADIO/modem.img', namelist)
387
Tao Bao82490d32019-04-09 00:12:30 -0700388 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700389 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
390 input_file = construct_target_files(secondary=True)
391 misc_info = '\n'.join([
392 'use_dynamic_partition_size=true',
393 'use_dynamic_partitions=true',
394 'dynamic_partition_list=system vendor product',
395 'super_partition_groups=google_dynamic_partitions',
396 'super_google_dynamic_partitions_group_size=4873781248',
397 'super_google_dynamic_partitions_partition_list=system vendor product',
398 ])
399 dynamic_partitions_info = '\n'.join([
400 'super_partition_groups=google_dynamic_partitions',
401 'super_google_dynamic_partitions_group_size=4873781248',
402 'super_google_dynamic_partitions_partition_list=system vendor product',
403 ])
404
405 with zipfile.ZipFile(input_file, 'a') as append_zip:
406 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
407 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
408 dynamic_partitions_info)
409
410 target_file = GetTargetFilesZipForSecondaryImages(input_file)
411
412 with zipfile.ZipFile(target_file) as verify_zip:
413 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700414 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700415 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700416 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700417
418 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700419 self.assertIn('IMAGES/system.img', namelist)
420 self.assertIn(POSTINSTALL_CONFIG, namelist)
421 self.assertIn('META/misc_info.txt', namelist)
422 self.assertIn('META/dynamic_partitions_info.txt', namelist)
423
Tao Bao3e759462019-09-17 22:43:11 -0700424 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700425 self.assertNotIn('IMAGES/system_other.img', namelist)
426 self.assertNotIn('IMAGES/system.map', namelist)
427
428 # Check the vendor & product are removed from the partitions list.
429 expected_misc_info = misc_info.replace('system vendor product',
430 'system')
431 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
432 'system vendor product', 'system')
433 self.assertEqual(expected_misc_info, updated_misc_info)
434 self.assertEqual(expected_dynamic_partitions_info,
435 updated_dynamic_partitions_info)
436
437 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800438 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
439 input_file = construct_target_files()
440 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
441 with zipfile.ZipFile(target_file) as verify_zip:
442 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
443
Tao Bao82490d32019-04-09 00:12:30 -0700444 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800445 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
446 input_file = construct_target_files()
447 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
448 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
449 with zipfile.ZipFile(target_file) as verify_zip:
450 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
451
Tao Bao3bf8c652018-03-16 12:59:42 -0700452 def _test_FinalizeMetadata(self, large_entry=False):
453 entries = [
454 'required-entry1',
455 'required-entry2',
456 ]
457 zip_file = PropertyFilesTest.construct_zip_package(entries)
458 # Add a large entry of 1 GiB if requested.
459 if large_entry:
460 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
461 zip_fp.writestr(
462 # Using 'zoo' so that the entry stays behind others after signing.
463 'zoo',
464 'A' * 1024 * 1024 * 1024,
465 zipfile.ZIP_STORED)
466
467 metadata = {}
468 output_file = common.MakeTempFile(suffix='.zip')
469 needed_property_files = (
470 TestPropertyFiles(),
471 )
472 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
473 self.assertIn('ota-test-property-files', metadata)
474
Tao Bao82490d32019-04-09 00:12:30 -0700475 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700476 def test_FinalizeMetadata(self):
477 self._test_FinalizeMetadata()
478
Tao Bao82490d32019-04-09 00:12:30 -0700479 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700480 def test_FinalizeMetadata_withNoSigning(self):
481 common.OPTIONS.no_signing = True
482 self._test_FinalizeMetadata()
483
Tao Bao82490d32019-04-09 00:12:30 -0700484 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700485 def test_FinalizeMetadata_largeEntry(self):
486 self._test_FinalizeMetadata(large_entry=True)
487
Tao Bao82490d32019-04-09 00:12:30 -0700488 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700489 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
490 common.OPTIONS.no_signing = True
491 self._test_FinalizeMetadata(large_entry=True)
492
Tao Bao82490d32019-04-09 00:12:30 -0700493 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700494 def test_FinalizeMetadata_insufficientSpace(self):
495 entries = [
496 'required-entry1',
497 'required-entry2',
498 'optional-entry1',
499 'optional-entry2',
500 ]
501 zip_file = PropertyFilesTest.construct_zip_package(entries)
502 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
503 zip_fp.writestr(
504 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
505 # order) after the signing, which will in turn trigger the
506 # InsufficientSpaceException and an automatic retry.
507 'foo-entry1',
508 'A' * 1024 * 1024,
509 zipfile.ZIP_STORED)
510
511 metadata = {}
512 needed_property_files = (
513 TestPropertyFiles(),
514 )
515 output_file = common.MakeTempFile(suffix='.zip')
516 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
517 self.assertIn('ota-test-property-files', metadata)
518
Tao Baoae5e4c32018-03-01 19:30:00 -0800519
Tao Bao69203522018-03-08 16:09:01 -0800520class TestPropertyFiles(PropertyFiles):
521 """A class that extends PropertyFiles for testing purpose."""
522
523 def __init__(self):
524 super(TestPropertyFiles, self).__init__()
525 self.name = 'ota-test-property-files'
526 self.required = (
527 'required-entry1',
528 'required-entry2',
529 )
530 self.optional = (
531 'optional-entry1',
532 'optional-entry2',
533 )
534
Kelvin Zhangcff4d762020-07-29 16:37:51 -0400535class PropertyFilesTest(PropertyFilesTestCase):
Tao Bao69203522018-03-08 16:09:01 -0800536
Tao Baof5110492018-03-02 09:47:43 -0800537
Tao Bao82490d32019-04-09 00:12:30 -0700538 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800539 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800540 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800541 'required-entry1',
542 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800543 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700544 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800545 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800546 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800547 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800548
Tao Bao69203522018-03-08 16:09:01 -0800549 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800550 self.assertEqual(3, len(tokens))
551 self._verify_entries(zip_file, tokens, entries)
552
Tao Bao69203522018-03-08 16:09:01 -0800553 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800554 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800555 'required-entry1',
556 'required-entry2',
557 'optional-entry1',
558 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800559 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700560 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800561 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800562 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800563 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800564
Tao Bao69203522018-03-08 16:09:01 -0800565 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800566 self.assertEqual(5, len(tokens))
567 self._verify_entries(zip_file, tokens, entries)
568
Tao Bao69203522018-03-08 16:09:01 -0800569 def test_Compute_missingRequiredEntry(self):
570 entries = (
571 'required-entry2',
572 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700573 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800574 property_files = TestPropertyFiles()
575 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
576 self.assertRaises(KeyError, property_files.Compute, zip_fp)
577
Tao Bao82490d32019-04-09 00:12:30 -0700578 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800579 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800580 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800581 'required-entry1',
582 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800583 'META-INF/com/android/metadata',
584 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700585 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800586 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800587 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700588 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800589 zip_fp, reserve_space=False)
590 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800591 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800592
593 self.assertEqual(3, len(tokens))
594 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
595 # streaming metadata.
596 entries[2] = 'metadata'
597 self._verify_entries(zip_file, tokens, entries)
598
Tao Bao82490d32019-04-09 00:12:30 -0700599 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800600 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800601 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800602 'required-entry1',
603 'required-entry2',
604 'optional-entry1',
605 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800606 'META-INF/com/android/metadata',
607 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700608 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800609 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800610 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
611 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700612 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800613 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800614 raw_length = len(raw_metadata)
615
616 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800617 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800618 self.assertEqual(raw_length, len(streaming_metadata))
619
620 # Or pass in insufficient length.
621 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700622 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800623 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800624 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800625 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800626
627 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800628 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800629 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800630 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800631 self.assertEqual(raw_length + 20, len(streaming_metadata))
632 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
633
Tao Baoae5e4c32018-03-01 19:30:00 -0800634 def test_Verify(self):
635 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800636 'required-entry1',
637 'required-entry2',
638 'optional-entry1',
639 'optional-entry2',
640 'META-INF/com/android/metadata',
641 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700642 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800643 property_files = TestPropertyFiles()
644 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
645 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700646 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800647 zip_fp, reserve_space=False)
648
649 # Should pass the test if verification passes.
650 property_files.Verify(zip_fp, raw_metadata)
651
652 # Or raise on verification failure.
653 self.assertRaises(
654 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
655
656
Kelvin Zhangcff4d762020-07-29 16:37:51 -0400657class StreamingPropertyFilesTest(PropertyFilesTestCase):
Kelvin Zhangc693d952020-07-22 19:21:22 -0400658 """Additional validity checks specialized for StreamingPropertyFiles."""
Tao Bao69203522018-03-08 16:09:01 -0800659
660 def test_init(self):
661 property_files = StreamingPropertyFiles()
662 self.assertEqual('ota-streaming-property-files', property_files.name)
663 self.assertEqual(
664 (
665 'payload.bin',
666 'payload_properties.txt',
667 ),
668 property_files.required)
669 self.assertEqual(
670 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700671 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800672 'care_map.txt',
673 'compatibility.zip',
674 ),
675 property_files.optional)
676
677 def test_Compute(self):
678 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800679 'payload.bin',
680 'payload_properties.txt',
681 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800682 'compatibility.zip',
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 = StreamingPropertyFiles()
686 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
687 property_files_string = property_files.Compute(zip_fp)
688
689 tokens = self._parse_property_files_string(property_files_string)
690 self.assertEqual(5, len(tokens))
691 self._verify_entries(zip_file, tokens, entries)
692
693 def test_Finalize(self):
694 entries = [
695 'payload.bin',
696 'payload_properties.txt',
697 'care_map.txt',
698 'compatibility.zip',
699 'META-INF/com/android/metadata',
700 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700701 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800702 property_files = StreamingPropertyFiles()
703 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700704 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800705 zip_fp, reserve_space=False)
706 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
707 tokens = self._parse_property_files_string(streaming_metadata)
708
709 self.assertEqual(5, len(tokens))
710 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
711 # streaming metadata.
712 entries[4] = 'metadata'
713 self._verify_entries(zip_file, tokens, entries)
714
715 def test_Verify(self):
716 entries = (
717 'payload.bin',
718 'payload_properties.txt',
719 'care_map.txt',
720 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -0800721 'META-INF/com/android/metadata',
722 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700723 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -0800724 property_files = StreamingPropertyFiles()
725 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
726 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700727 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800728 zip_fp, reserve_space=False)
729
730 # Should pass the test if verification passes.
731 property_files.Verify(zip_fp, raw_metadata)
732
733 # Or raise on verification failure.
734 self.assertRaises(
735 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
736
Tao Baofabe0832018-01-17 15:52:28 -0800737
Kelvin Zhangcff4d762020-07-29 16:37:51 -0400738class AbOtaPropertyFilesTest(PropertyFilesTestCase):
Kelvin Zhangc693d952020-07-22 19:21:22 -0400739 """Additional validity checks specialized for AbOtaPropertyFiles."""
Tao Baob6304672018-03-08 16:28:33 -0800740
741 # The size for payload and metadata signature size.
742 SIGNATURE_SIZE = 256
743
744 def setUp(self):
745 self.testdata_dir = test_utils.get_testdata_dir()
746 self.assertTrue(os.path.exists(self.testdata_dir))
747
748 common.OPTIONS.wipe_user_data = False
749 common.OPTIONS.payload_signer = None
750 common.OPTIONS.payload_signer_args = None
751 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
752 common.OPTIONS.key_passwords = {
753 common.OPTIONS.package_key : None,
754 }
755
756 def test_init(self):
757 property_files = AbOtaPropertyFiles()
758 self.assertEqual('ota-property-files', property_files.name)
759 self.assertEqual(
760 (
761 'payload.bin',
762 'payload_properties.txt',
763 ),
764 property_files.required)
765 self.assertEqual(
766 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700767 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -0800768 'care_map.txt',
769 'compatibility.zip',
770 ),
771 property_files.optional)
772
Tao Bao82490d32019-04-09 00:12:30 -0700773 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800774 def test_GetPayloadMetadataOffsetAndSize(self):
775 target_file = construct_target_files()
776 payload = Payload()
777 payload.Generate(target_file)
778
779 payload_signer = PayloadSigner()
780 payload.Sign(payload_signer)
781
782 output_file = common.MakeTempFile(suffix='.zip')
783 with zipfile.ZipFile(output_file, 'w') as output_zip:
784 payload.WriteToZip(output_zip)
785
786 # Find out the payload metadata offset and size.
787 property_files = AbOtaPropertyFiles()
788 with zipfile.ZipFile(output_file) as input_zip:
789 # pylint: disable=protected-access
790 payload_offset, metadata_total = (
791 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
792
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700793 # The signature proto has the following format (details in
794 # /platform/system/update_engine/update_metadata.proto):
795 # message Signature {
796 # optional uint32 version = 1;
797 # optional bytes data = 2;
798 # optional fixed32 unpadded_signature_size = 3;
799 # }
800 #
801 # According to the protobuf encoding, the tail of the signature message will
802 # be [signature string(256 bytes) + encoding of the fixed32 number 256]. And
803 # 256 is encoded as 'x1d\x00\x01\x00\x00':
804 # [3 (field number) << 3 | 5 (type) + byte reverse of 0x100 (256)].
805 # Details in (https://developers.google.com/protocol-buffers/docs/encoding)
806 signature_tail_length = self.SIGNATURE_SIZE + 5
807 self.assertGreater(metadata_total, signature_tail_length)
Tao Baob6304672018-03-08 16:28:33 -0800808 with open(output_file, 'rb') as verify_fp:
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700809 verify_fp.seek(payload_offset + metadata_total - signature_tail_length)
810 metadata_signature_proto_tail = verify_fp.read(signature_tail_length)
811
812 self.assertEqual(b'\x1d\x00\x01\x00\x00',
813 metadata_signature_proto_tail[-5:])
814 metadata_signature = metadata_signature_proto_tail[:-5]
Tao Baob6304672018-03-08 16:28:33 -0800815
816 # Now we extract the metadata hash via brillo_update_payload script, which
817 # will serve as the oracle result.
818 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
819 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
820 cmd = ['brillo_update_payload', 'hash',
821 '--unsigned_payload', payload.payload_file,
822 '--signature_size', str(self.SIGNATURE_SIZE),
823 '--metadata_hash_file', metadata_sig_file,
824 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -0700825 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -0800826 stdoutdata, _ = proc.communicate()
827 self.assertEqual(
828 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -0700829 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -0800830
831 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
832
833 # Finally we can compare the two signatures.
834 with open(signed_metadata_sig_file, 'rb') as verify_fp:
835 self.assertEqual(verify_fp.read(), metadata_signature)
836
837 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700838 def construct_zip_package_withValidPayload(with_metadata=False):
839 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -0800840 target_file = construct_target_files()
841 payload = Payload()
842 payload.Generate(target_file)
843
844 payload_signer = PayloadSigner()
845 payload.Sign(payload_signer)
846
847 zip_file = common.MakeTempFile(suffix='.zip')
848 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
849 # 'payload.bin',
850 payload.WriteToZip(zip_fp)
851
852 # Other entries.
853 entries = ['care_map.txt', 'compatibility.zip']
854
855 # Put META-INF/com/android/metadata if needed.
856 if with_metadata:
857 entries.append('META-INF/com/android/metadata')
858
859 for entry in entries:
860 zip_fp.writestr(
861 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
862
863 return zip_file
864
Tao Bao82490d32019-04-09 00:12:30 -0700865 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800866 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700867 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -0800868 property_files = AbOtaPropertyFiles()
869 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
870 property_files_string = property_files.Compute(zip_fp)
871
872 tokens = self._parse_property_files_string(property_files_string)
873 # "6" indcludes the four entries above, one metadata entry, and one entry
874 # for payload-metadata.bin.
875 self.assertEqual(6, len(tokens))
876 self._verify_entries(
877 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
878
Tao Bao82490d32019-04-09 00:12:30 -0700879 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800880 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700881 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800882 property_files = AbOtaPropertyFiles()
883 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700884 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800885 zip_fp, reserve_space=False)
886 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
887
888 tokens = self._parse_property_files_string(property_files_string)
889 # "6" indcludes the four entries above, one metadata entry, and one entry
890 # for payload-metadata.bin.
891 self.assertEqual(6, len(tokens))
892 self._verify_entries(
893 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
894
Tao Bao82490d32019-04-09 00:12:30 -0700895 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800896 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700897 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800898 property_files = AbOtaPropertyFiles()
899 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700900 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800901 zip_fp, reserve_space=False)
902
903 property_files.Verify(zip_fp, raw_metadata)
904
905
Tao Bao65b94e92018-10-11 21:57:26 -0700906class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -0800907
908 SIGFILE = 'sigfile.bin'
909 SIGNED_SIGFILE = 'signed-sigfile.bin'
910
911 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -0800912 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -0800913 self.assertTrue(os.path.exists(self.testdata_dir))
914
915 common.OPTIONS.payload_signer = None
916 common.OPTIONS.payload_signer_args = []
917 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
918 common.OPTIONS.key_passwords = {
919 common.OPTIONS.package_key : None,
920 }
921
Tao Baofabe0832018-01-17 15:52:28 -0800922 def _assertFilesEqual(self, file1, file2):
923 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
924 self.assertEqual(fp1.read(), fp2.read())
925
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700926 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -0800927 def test_init(self):
928 payload_signer = PayloadSigner()
929 self.assertEqual('openssl', payload_signer.signer)
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700930 self.assertEqual(256, payload_signer.maximum_signature_size)
Tao Baofabe0832018-01-17 15:52:28 -0800931
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700932 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -0800933 def test_init_withPassword(self):
934 common.OPTIONS.package_key = os.path.join(
935 self.testdata_dir, 'testkey_with_passwd')
936 common.OPTIONS.key_passwords = {
937 common.OPTIONS.package_key : 'foo',
938 }
939 payload_signer = PayloadSigner()
940 self.assertEqual('openssl', payload_signer.signer)
941
942 def test_init_withExternalSigner(self):
943 common.OPTIONS.payload_signer = 'abc'
944 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700945 common.OPTIONS.payload_signer_maximum_signature_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -0800946 payload_signer = PayloadSigner()
947 self.assertEqual('abc', payload_signer.signer)
948 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700949 self.assertEqual(512, payload_signer.maximum_signature_size)
xunchang376cc7c2019-04-08 23:04:58 -0700950
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700951 @test_utils.SkipIfExternalToolsUnavailable()
952 def test_GetMaximumSignatureSizeInBytes_512Bytes(self):
xunchang376cc7c2019-04-08 23:04:58 -0700953 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -0700954 # pylint: disable=protected-access
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700955 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
956 self.assertEqual(512, signature_size)
Tao Baofabe0832018-01-17 15:52:28 -0800957
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700958 @test_utils.SkipIfExternalToolsUnavailable()
959 def test_GetMaximumSignatureSizeInBytes_ECKey(self):
960 signing_key = os.path.join(self.testdata_dir, 'testkey_EC.key')
961 # pylint: disable=protected-access
962 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
963 self.assertEqual(72, signature_size)
964
965 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -0800966 def test_Sign(self):
967 payload_signer = PayloadSigner()
968 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
969 signed_file = payload_signer.Sign(input_file)
970
971 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
972 self._assertFilesEqual(verify_file, signed_file)
973
974 def test_Sign_withExternalSigner_openssl(self):
975 """Uses openssl as the external payload signer."""
976 common.OPTIONS.payload_signer = 'openssl'
977 common.OPTIONS.payload_signer_args = [
978 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
979 os.path.join(self.testdata_dir, 'testkey.pk8'),
980 '-pkeyopt', 'digest:sha256']
981 payload_signer = PayloadSigner()
982 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
983 signed_file = payload_signer.Sign(input_file)
984
985 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
986 self._assertFilesEqual(verify_file, signed_file)
987
988 def test_Sign_withExternalSigner_script(self):
989 """Uses testdata/payload_signer.sh as the external payload signer."""
990 common.OPTIONS.payload_signer = os.path.join(
991 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -0700992 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -0800993 common.OPTIONS.payload_signer_args = [
994 os.path.join(self.testdata_dir, 'testkey.pk8')]
995 payload_signer = PayloadSigner()
996 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
997 signed_file = payload_signer.Sign(input_file)
998
999 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1000 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001001
1002
Tao Bao65b94e92018-10-11 21:57:26 -07001003class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001004
1005 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001006 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001007 self.assertTrue(os.path.exists(self.testdata_dir))
1008
1009 common.OPTIONS.wipe_user_data = False
1010 common.OPTIONS.payload_signer = None
1011 common.OPTIONS.payload_signer_args = None
1012 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1013 common.OPTIONS.key_passwords = {
1014 common.OPTIONS.package_key : None,
1015 }
1016
Tao Baoc7b403a2018-01-30 18:19:04 -08001017 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001018 def _create_payload_full(secondary=False):
1019 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001020 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001021 payload.Generate(target_file)
1022 return payload
1023
Tao Baof7140c02018-01-30 17:09:24 -08001024 @staticmethod
1025 def _create_payload_incremental():
1026 target_file = construct_target_files()
1027 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001028 payload = Payload()
1029 payload.Generate(target_file, source_file)
1030 return payload
1031
Tao Bao82490d32019-04-09 00:12:30 -07001032 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001033 def test_Generate_full(self):
1034 payload = self._create_payload_full()
1035 self.assertTrue(os.path.exists(payload.payload_file))
1036
Tao Bao82490d32019-04-09 00:12:30 -07001037 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001038 def test_Generate_incremental(self):
1039 payload = self._create_payload_incremental()
1040 self.assertTrue(os.path.exists(payload.payload_file))
1041
Tao Bao82490d32019-04-09 00:12:30 -07001042 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001043 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001044 target_file = construct_target_files()
1045 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001046 payload = Payload()
1047 # This should work the same as calling payload.Generate(target_file,
1048 # source_file).
1049 payload.Generate(
1050 target_file, additional_args=["--source_image", source_file])
1051 self.assertTrue(os.path.exists(payload.payload_file))
1052
Tao Bao82490d32019-04-09 00:12:30 -07001053 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001054 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001055 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001056 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1057 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001058 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001059
Tao Bao82490d32019-04-09 00:12:30 -07001060 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001061 def test_Sign_full(self):
1062 payload = self._create_payload_full()
1063 payload.Sign(PayloadSigner())
1064
1065 output_file = common.MakeTempFile(suffix='.zip')
1066 with zipfile.ZipFile(output_file, 'w') as output_zip:
1067 payload.WriteToZip(output_zip)
1068
1069 import check_ota_package_signature
1070 check_ota_package_signature.VerifyAbOtaPayload(
1071 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1072 output_file)
1073
Tao Bao82490d32019-04-09 00:12:30 -07001074 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001075 def test_Sign_incremental(self):
1076 payload = self._create_payload_incremental()
1077 payload.Sign(PayloadSigner())
1078
1079 output_file = common.MakeTempFile(suffix='.zip')
1080 with zipfile.ZipFile(output_file, 'w') as output_zip:
1081 payload.WriteToZip(output_zip)
1082
1083 import check_ota_package_signature
1084 check_ota_package_signature.VerifyAbOtaPayload(
1085 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1086 output_file)
1087
Tao Bao82490d32019-04-09 00:12:30 -07001088 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001089 def test_Sign_withDataWipe(self):
1090 common.OPTIONS.wipe_user_data = True
1091 payload = self._create_payload_full()
1092 payload.Sign(PayloadSigner())
1093
1094 with open(payload.payload_properties) as properties_fp:
1095 self.assertIn("POWERWASH=1", properties_fp.read())
1096
Tao Bao82490d32019-04-09 00:12:30 -07001097 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001098 def test_Sign_secondary(self):
1099 payload = self._create_payload_full(secondary=True)
1100 payload.Sign(PayloadSigner())
1101
1102 with open(payload.payload_properties) as properties_fp:
1103 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1104
Tao Bao82490d32019-04-09 00:12:30 -07001105 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001106 def test_Sign_badSigner(self):
1107 """Tests that signing failure can be captured."""
1108 payload = self._create_payload_full()
1109 payload_signer = PayloadSigner()
1110 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001111 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001112
Tao Bao82490d32019-04-09 00:12:30 -07001113 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001114 def test_WriteToZip(self):
1115 payload = self._create_payload_full()
1116 payload.Sign(PayloadSigner())
1117
1118 output_file = common.MakeTempFile(suffix='.zip')
1119 with zipfile.ZipFile(output_file, 'w') as output_zip:
1120 payload.WriteToZip(output_zip)
1121
1122 with zipfile.ZipFile(output_file) as verify_zip:
1123 # First make sure we have the essential entries.
1124 namelist = verify_zip.namelist()
1125 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1126 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1127
1128 # Then assert these entries are stored.
1129 for entry_info in verify_zip.infolist():
1130 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1131 Payload.PAYLOAD_PROPERTIES_TXT):
1132 continue
1133 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1134
Tao Bao82490d32019-04-09 00:12:30 -07001135 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001136 def test_WriteToZip_unsignedPayload(self):
1137 """Unsigned payloads should not be allowed to be written to zip."""
1138 payload = self._create_payload_full()
1139
1140 output_file = common.MakeTempFile(suffix='.zip')
1141 with zipfile.ZipFile(output_file, 'w') as output_zip:
1142 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1143
1144 # Also test with incremental payload.
1145 payload = self._create_payload_incremental()
1146
1147 output_file = common.MakeTempFile(suffix='.zip')
1148 with zipfile.ZipFile(output_file, 'w') as output_zip:
1149 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001150
Tao Bao82490d32019-04-09 00:12:30 -07001151 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001152 def test_WriteToZip_secondary(self):
1153 payload = self._create_payload_full(secondary=True)
1154 payload.Sign(PayloadSigner())
1155
1156 output_file = common.MakeTempFile(suffix='.zip')
1157 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001158 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001159
1160 with zipfile.ZipFile(output_file) as verify_zip:
1161 # First make sure we have the essential entries.
1162 namelist = verify_zip.namelist()
1163 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1164 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1165
1166 # Then assert these entries are stored.
1167 for entry_info in verify_zip.infolist():
1168 if entry_info.filename not in (
1169 Payload.SECONDARY_PAYLOAD_BIN,
1170 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1171 continue
1172 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
Tianjie Xu9afb2212020-05-10 21:48:15 +00001173
1174
1175class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
1176 MISC_INFO = [
1177 'recovery_api_version=3',
1178 'fstab_version=2',
1179 'recovery_as_boot=true',
1180 ]
1181
1182 BUILD_PROP = [
1183 'ro.build.version.release=version-release',
1184 'ro.build.id=build-id',
1185 'ro.build.version.incremental=version-incremental',
1186 'ro.build.type=build-type',
1187 'ro.build.tags=build-tags',
Tianjied6867162020-05-10 14:30:13 -07001188 'ro.build.version.sdk=30',
1189 'ro.build.version.security_patch=2020',
1190 'ro.build.date.utc=12345678'
Tianjie Xu9afb2212020-05-10 21:48:15 +00001191 ]
1192
1193 VENDOR_BUILD_PROP = [
1194 'ro.product.vendor.brand=vendor-product-brand',
1195 'ro.product.vendor.name=vendor-product-name',
1196 'ro.product.vendor.device=vendor-product-device'
1197 ]
1198
1199 def setUp(self):
1200 common.OPTIONS.oem_dicts = None
1201 self.test_dir = common.MakeTempDir()
Tianjied6867162020-05-10 14:30:13 -07001202 self.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)},
1203 self.test_dir)
Tianjie Xu9afb2212020-05-10 21:48:15 +00001204
Tianjied6867162020-05-10 14:30:13 -07001205 def writeFiles(self, contents_dict, out_dir):
Tianjie Xu9afb2212020-05-10 21:48:15 +00001206 for path, content in contents_dict.items():
Tianjied6867162020-05-10 14:30:13 -07001207 abs_path = os.path.join(out_dir, path)
Tianjie Xu9afb2212020-05-10 21:48:15 +00001208 dir_name = os.path.dirname(abs_path)
1209 if not os.path.exists(dir_name):
1210 os.makedirs(dir_name)
1211 with open(abs_path, 'w') as f:
1212 f.write(content)
1213
1214 @staticmethod
1215 def constructFingerprint(prefix):
1216 return '{}:version-release/build-id/version-incremental:' \
1217 'build-type/build-tags'.format(prefix)
1218
1219 def test_CalculatePossibleFingerprints_no_dynamic_fingerprint(self):
1220 build_prop = copy.deepcopy(self.BUILD_PROP)
1221 build_prop.extend([
1222 'ro.product.brand=product-brand',
1223 'ro.product.name=product-name',
1224 'ro.product.device=product-device',
1225 ])
1226 self.writeFiles({
1227 'SYSTEM/build.prop': '\n'.join(build_prop),
1228 'VENDOR/build.prop': '\n'.join(self.VENDOR_BUILD_PROP),
Tianjied6867162020-05-10 14:30:13 -07001229 }, self.test_dir)
Tianjie Xu9afb2212020-05-10 21:48:15 +00001230
Tianjied6867162020-05-10 14:30:13 -07001231 build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
1232 expected = ({'product-device'},
1233 {self.constructFingerprint(
1234 'product-brand/product-name/product-device')})
1235 self.assertEqual(expected,
1236 CalculateRuntimeDevicesAndFingerprints(build_info, {}))
Tianjie Xu9afb2212020-05-10 21:48:15 +00001237
1238 def test_CalculatePossibleFingerprints_single_override(self):
1239 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1240 vendor_build_prop.extend([
1241 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1242 ])
1243 self.writeFiles({
1244 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1245 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1246 'VENDOR/etc/build_std.prop':
1247 'ro.product.vendor.name=vendor-product-std',
1248 'VENDOR/etc/build_pro.prop':
1249 'ro.product.vendor.name=vendor-product-pro',
Tianjied6867162020-05-10 14:30:13 -07001250 }, self.test_dir)
Tianjie Xu9afb2212020-05-10 21:48:15 +00001251
Tianjied6867162020-05-10 14:30:13 -07001252 build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
1253 boot_variable_values = {'ro.boot.sku_name': ['std', 'pro']}
1254
1255 expected = ({'vendor-product-device'}, {
Tianjie Xu9afb2212020-05-10 21:48:15 +00001256 self.constructFingerprint(
1257 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1258 self.constructFingerprint(
1259 'vendor-product-brand/vendor-product-std/vendor-product-device'),
1260 self.constructFingerprint(
1261 'vendor-product-brand/vendor-product-pro/vendor-product-device'),
Tianjied6867162020-05-10 14:30:13 -07001262 })
1263 self.assertEqual(
1264 expected, CalculateRuntimeDevicesAndFingerprints(
1265 build_info, boot_variable_values))
Tianjie Xu9afb2212020-05-10 21:48:15 +00001266
1267 def test_CalculatePossibleFingerprints_multiple_overrides(self):
1268 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1269 vendor_build_prop.extend([
1270 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1271 'import /vendor/etc/build_${ro.boot.device_name}.prop',
1272 ])
1273 self.writeFiles({
1274 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1275 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1276 'VENDOR/etc/build_std.prop':
1277 'ro.product.vendor.name=vendor-product-std',
1278 'VENDOR/etc/build_product1.prop':
1279 'ro.product.vendor.device=vendor-device-product1',
1280 'VENDOR/etc/build_pro.prop':
1281 'ro.product.vendor.name=vendor-product-pro',
1282 'VENDOR/etc/build_product2.prop':
1283 'ro.product.vendor.device=vendor-device-product2',
Tianjied6867162020-05-10 14:30:13 -07001284 }, self.test_dir)
1285
1286 build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
1287 boot_variable_values = {
Tianjie Xu9afb2212020-05-10 21:48:15 +00001288 'ro.boot.sku_name': ['std', 'pro'],
1289 'ro.boot.device_name': ['product1', 'product2'],
1290 }
1291
Tianjied6867162020-05-10 14:30:13 -07001292 expected_devices = {'vendor-product-device', 'vendor-device-product1',
1293 'vendor-device-product2'}
1294 expected_fingerprints = {
Tianjie Xu9afb2212020-05-10 21:48:15 +00001295 self.constructFingerprint(
1296 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1297 self.constructFingerprint(
1298 'vendor-product-brand/vendor-product-std/vendor-device-product1'),
1299 self.constructFingerprint(
1300 'vendor-product-brand/vendor-product-pro/vendor-device-product1'),
1301 self.constructFingerprint(
1302 'vendor-product-brand/vendor-product-std/vendor-device-product2'),
1303 self.constructFingerprint(
Tianjied6867162020-05-10 14:30:13 -07001304 'vendor-product-brand/vendor-product-pro/vendor-device-product2')
1305 }
1306 self.assertEqual((expected_devices, expected_fingerprints),
1307 CalculateRuntimeDevicesAndFingerprints(
1308 build_info, boot_variable_values))
1309
1310 def test_GetPackageMetadata_full_package(self):
1311 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1312 vendor_build_prop.extend([
1313 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1314 ])
1315 self.writeFiles({
1316 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1317 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1318 'VENDOR/etc/build_std.prop':
1319 'ro.product.vendor.name=vendor-product-std',
1320 'VENDOR/etc/build_pro.prop':
1321 'ro.product.vendor.name=vendor-product-pro',
1322 }, self.test_dir)
1323
1324 common.OPTIONS.boot_variable_file = common.MakeTempFile()
1325 with open(common.OPTIONS.boot_variable_file, 'w') as f:
1326 f.write('ro.boot.sku_name=std,pro')
1327
1328 build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
1329 metadata = GetPackageMetadata(build_info)
1330 self.assertEqual('vendor-product-device', metadata['pre-device'])
1331 fingerprints = [
1332 self.constructFingerprint(
1333 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1334 self.constructFingerprint(
1335 'vendor-product-brand/vendor-product-pro/vendor-product-device'),
1336 self.constructFingerprint(
1337 'vendor-product-brand/vendor-product-std/vendor-product-device'),
1338 ]
1339 self.assertEqual('|'.join(fingerprints), metadata['post-build'])
1340
1341 def test_GetPackageMetadata_incremental_package(self):
1342 vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
1343 vendor_build_prop.extend([
1344 'import /vendor/etc/build_${ro.boot.sku_name}.prop',
1345 ])
1346 self.writeFiles({
1347 'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
1348 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1349 'VENDOR/etc/build_std.prop':
1350 'ro.product.vendor.device=vendor-device-std',
1351 'VENDOR/etc/build_pro.prop':
1352 'ro.product.vendor.device=vendor-device-pro',
1353 }, self.test_dir)
1354
1355 common.OPTIONS.boot_variable_file = common.MakeTempFile()
1356 with open(common.OPTIONS.boot_variable_file, 'w') as f:
1357 f.write('ro.boot.sku_name=std,pro')
1358
1359 source_dir = common.MakeTempDir()
1360 source_build_prop = [
1361 'ro.build.version.release=source-version-release',
1362 'ro.build.id=source-build-id',
1363 'ro.build.version.incremental=source-version-incremental',
1364 'ro.build.type=build-type',
1365 'ro.build.tags=build-tags',
1366 'ro.build.version.sdk=29',
1367 'ro.build.version.security_patch=2020',
1368 'ro.build.date.utc=12340000'
1369 ]
1370 self.writeFiles({
1371 'META/misc_info.txt': '\n'.join(self.MISC_INFO),
1372 'SYSTEM/build.prop': '\n'.join(source_build_prop),
1373 'VENDOR/build.prop': '\n'.join(vendor_build_prop),
1374 'VENDOR/etc/build_std.prop':
1375 'ro.product.vendor.device=vendor-device-std',
1376 'VENDOR/etc/build_pro.prop':
1377 'ro.product.vendor.device=vendor-device-pro',
1378 }, source_dir)
1379 common.OPTIONS.incremental_source = source_dir
1380
1381 target_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
1382 source_info = common.BuildInfo(common.LoadInfoDict(source_dir))
1383
1384 metadata = GetPackageMetadata(target_info, source_info)
1385 self.assertEqual(
1386 'vendor-device-pro|vendor-device-std|vendor-product-device',
1387 metadata['pre-device'])
1388 suffix = ':source-version-release/source-build-id/' \
1389 'source-version-incremental:build-type/build-tags'
1390 pre_fingerprints = [
1391 'vendor-product-brand/vendor-product-name/vendor-device-pro'
1392 '{}'.format(suffix),
1393 'vendor-product-brand/vendor-product-name/vendor-device-std'
1394 '{}'.format(suffix),
1395 'vendor-product-brand/vendor-product-name/vendor-product-device'
1396 '{}'.format(suffix),
1397 ]
1398 self.assertEqual('|'.join(pre_fingerprints), metadata['pre-build'])
1399
1400 post_fingerprints = [
1401 self.constructFingerprint(
1402 'vendor-product-brand/vendor-product-name/vendor-device-pro'),
1403 self.constructFingerprint(
1404 'vendor-product-brand/vendor-product-name/vendor-device-std'),
1405 self.constructFingerprint(
1406 'vendor-product-brand/vendor-product-name/vendor-product-device'),
1407 ]
1408 self.assertEqual('|'.join(post_fingerprints), metadata['post-build'])