blob: f7d59daf85ecebb4425ae4b5d87c725bed7a7c00 [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 Bao3bf8c652018-03-16 12:59:42 -070025 _LoadOemDicts, AbOtaPropertyFiles, BuildInfo, FinalizeMetadata,
26 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,
29 StreamingPropertyFiles, WriteFingerprintAssertion)
Tao Baofabe0832018-01-17 15:52:28 -080030
31
Tao Baof7140c02018-01-30 17:09:24 -080032def construct_target_files(secondary=False):
33 """Returns a target-files.zip file for generating OTA packages."""
34 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
35 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
36 # META/update_engine_config.txt
37 target_files_zip.writestr(
38 'META/update_engine_config.txt',
39 "PAYLOAD_MAJOR_VERSION=2\nPAYLOAD_MINOR_VERSION=4\n")
40
Tao Bao15a146a2018-02-21 16:06:59 -080041 # META/postinstall_config.txt
42 target_files_zip.writestr(
43 POSTINSTALL_CONFIG,
44 '\n'.join([
45 "RUN_POSTINSTALL_system=true",
46 "POSTINSTALL_PATH_system=system/bin/otapreopt_script",
47 "FILESYSTEM_TYPE_system=ext4",
48 "POSTINSTALL_OPTIONAL_system=true",
49 ]))
50
Tao Bao5277d102018-04-17 23:47:21 -070051 ab_partitions = [
52 ('IMAGES', 'boot'),
53 ('IMAGES', 'system'),
54 ('IMAGES', 'vendor'),
55 ('RADIO', 'bootloader'),
56 ('RADIO', 'modem'),
57 ]
Tao Baof7140c02018-01-30 17:09:24 -080058 # META/ab_partitions.txt
Tao Baof7140c02018-01-30 17:09:24 -080059 target_files_zip.writestr(
60 'META/ab_partitions.txt',
Tao Bao5277d102018-04-17 23:47:21 -070061 '\n'.join([partition[1] for partition in ab_partitions]))
Tao Baof7140c02018-01-30 17:09:24 -080062
63 # Create dummy images for each of them.
Tao Bao5277d102018-04-17 23:47:21 -070064 for path, partition in ab_partitions:
65 target_files_zip.writestr(
66 '{}/{}.img'.format(path, partition),
67 os.urandom(len(partition)))
Tao Baof7140c02018-01-30 17:09:24 -080068
Tao Bao5277d102018-04-17 23:47:21 -070069 # system_other shouldn't appear in META/ab_partitions.txt.
Tao Baof7140c02018-01-30 17:09:24 -080070 if secondary:
71 target_files_zip.writestr('IMAGES/system_other.img',
72 os.urandom(len("system_other")))
73
74 return target_files
75
76
Tao Bao481bab82017-12-21 11:23:09 -080077class MockScriptWriter(object):
78 """A class that mocks edify_generator.EdifyGenerator.
79
80 It simply pushes the incoming arguments onto script stack, which is to assert
81 the calls to EdifyGenerator functions.
82 """
83
84 def __init__(self):
85 self.script = []
86
87 def Mount(self, *args):
88 self.script.append(('Mount',) + args)
89
90 def AssertDevice(self, *args):
91 self.script.append(('AssertDevice',) + args)
92
93 def AssertOemProperty(self, *args):
94 self.script.append(('AssertOemProperty',) + args)
95
96 def AssertFingerprintOrThumbprint(self, *args):
97 self.script.append(('AssertFingerprintOrThumbprint',) + args)
98
99 def AssertSomeFingerprint(self, *args):
100 self.script.append(('AssertSomeFingerprint',) + args)
101
102 def AssertSomeThumbprint(self, *args):
103 self.script.append(('AssertSomeThumbprint',) + args)
104
105
Tao Bao65b94e92018-10-11 21:57:26 -0700106class BuildInfoTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -0800107
108 TEST_INFO_DICT = {
109 'build.prop' : {
110 'ro.product.device' : 'product-device',
111 'ro.product.name' : 'product-name',
112 'ro.build.fingerprint' : 'build-fingerprint',
113 'ro.build.foo' : 'build-foo',
114 },
115 'vendor.build.prop' : {
116 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
117 },
118 'property1' : 'value1',
119 'property2' : 4096,
120 }
121
122 TEST_INFO_DICT_USES_OEM_PROPS = {
123 'build.prop' : {
124 'ro.product.name' : 'product-name',
125 'ro.build.thumbprint' : 'build-thumbprint',
126 'ro.build.bar' : 'build-bar',
127 },
128 'vendor.build.prop' : {
129 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
130 },
131 'property1' : 'value1',
132 'property2' : 4096,
133 'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
134 }
135
136 TEST_OEM_DICTS = [
137 {
138 'ro.product.brand' : 'brand1',
139 'ro.product.device' : 'device1',
140 },
141 {
142 'ro.product.brand' : 'brand2',
143 'ro.product.device' : 'device2',
144 },
145 {
146 'ro.product.brand' : 'brand3',
147 'ro.product.device' : 'device3',
148 },
149 ]
150
151 def test_init(self):
152 target_info = BuildInfo(self.TEST_INFO_DICT, None)
153 self.assertEqual('product-device', target_info.device)
154 self.assertEqual('build-fingerprint', target_info.fingerprint)
155 self.assertFalse(target_info.is_ab)
156 self.assertIsNone(target_info.oem_props)
157
158 def test_init_with_oem_props(self):
159 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
160 self.TEST_OEM_DICTS)
161 self.assertEqual('device1', target_info.device)
162 self.assertEqual('brand1/product-name/device1:build-thumbprint',
163 target_info.fingerprint)
164
165 # Swap the order in oem_dicts, which would lead to different BuildInfo.
166 oem_dicts = copy.copy(self.TEST_OEM_DICTS)
167 oem_dicts[0], oem_dicts[2] = oem_dicts[2], oem_dicts[0]
168 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS, oem_dicts)
169 self.assertEqual('device3', target_info.device)
170 self.assertEqual('brand3/product-name/device3:build-thumbprint',
171 target_info.fingerprint)
172
173 # Missing oem_dict should be rejected.
174 self.assertRaises(AssertionError, BuildInfo,
175 self.TEST_INFO_DICT_USES_OEM_PROPS, None)
176
Tao Baoc4011cd72019-09-17 00:14:44 -0700177 def test_init_badFingerprint(self):
178 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
179 info_dict['build.prop']['ro.build.fingerprint'] = 'bad fingerprint'
180 self.assertRaises(ValueError, BuildInfo, info_dict, None)
181
182 info_dict['build.prop']['ro.build.fingerprint'] = 'bad\x80fingerprint'
183 self.assertRaises(ValueError, BuildInfo, info_dict, None)
184
Tao Bao481bab82017-12-21 11:23:09 -0800185 def test___getitem__(self):
186 target_info = BuildInfo(self.TEST_INFO_DICT, None)
187 self.assertEqual('value1', target_info['property1'])
188 self.assertEqual(4096, target_info['property2'])
189 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
190
191 def test___getitem__with_oem_props(self):
192 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
193 self.TEST_OEM_DICTS)
194 self.assertEqual('value1', target_info['property1'])
195 self.assertEqual(4096, target_info['property2'])
196 self.assertRaises(KeyError,
197 lambda: target_info['build.prop']['ro.build.foo'])
198
Tao Bao667c7532018-07-06 10:13:59 -0700199 def test___setitem__(self):
200 target_info = BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
201 self.assertEqual('value1', target_info['property1'])
202 target_info['property1'] = 'value2'
203 self.assertEqual('value2', target_info['property1'])
204
205 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
206 target_info['build.prop']['ro.build.foo'] = 'build-bar'
207 self.assertEqual('build-bar', target_info['build.prop']['ro.build.foo'])
208
Tao Bao481bab82017-12-21 11:23:09 -0800209 def test_get(self):
210 target_info = BuildInfo(self.TEST_INFO_DICT, None)
211 self.assertEqual('value1', target_info.get('property1'))
212 self.assertEqual(4096, target_info.get('property2'))
213 self.assertEqual(4096, target_info.get('property2', 1024))
214 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
215 self.assertEqual('build-foo', target_info.get('build.prop')['ro.build.foo'])
216
217 def test_get_with_oem_props(self):
218 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
219 self.TEST_OEM_DICTS)
220 self.assertEqual('value1', target_info.get('property1'))
221 self.assertEqual(4096, target_info.get('property2'))
222 self.assertEqual(4096, target_info.get('property2', 1024))
223 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
224 self.assertIsNone(target_info.get('build.prop').get('ro.build.foo'))
225 self.assertRaises(KeyError,
226 lambda: target_info.get('build.prop')['ro.build.foo'])
227
Tao Bao667c7532018-07-06 10:13:59 -0700228 def test_items(self):
229 target_info = BuildInfo(self.TEST_INFO_DICT, None)
230 items = target_info.items()
231 self.assertIn(('property1', 'value1'), items)
232 self.assertIn(('property2', 4096), items)
233
Tao Bao481bab82017-12-21 11:23:09 -0800234 def test_GetBuildProp(self):
235 target_info = BuildInfo(self.TEST_INFO_DICT, None)
236 self.assertEqual('build-foo', target_info.GetBuildProp('ro.build.foo'))
237 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
238 'ro.build.nonexistent')
239
240 def test_GetBuildProp_with_oem_props(self):
241 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
242 self.TEST_OEM_DICTS)
243 self.assertEqual('build-bar', target_info.GetBuildProp('ro.build.bar'))
244 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
245 'ro.build.nonexistent')
246
247 def test_GetVendorBuildProp(self):
248 target_info = BuildInfo(self.TEST_INFO_DICT, None)
249 self.assertEqual('vendor-build-fingerprint',
250 target_info.GetVendorBuildProp(
251 'ro.vendor.build.fingerprint'))
252 self.assertRaises(common.ExternalError, target_info.GetVendorBuildProp,
253 'ro.build.nonexistent')
254
255 def test_GetVendorBuildProp_with_oem_props(self):
256 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
257 self.TEST_OEM_DICTS)
258 self.assertEqual('vendor-build-fingerprint',
259 target_info.GetVendorBuildProp(
260 'ro.vendor.build.fingerprint'))
261 self.assertRaises(common.ExternalError, target_info.GetVendorBuildProp,
262 'ro.build.nonexistent')
263
Tao Baoea6cbd02018-09-05 13:06:37 -0700264 def test_vendor_fingerprint(self):
265 target_info = BuildInfo(self.TEST_INFO_DICT, None)
266 self.assertEqual('vendor-build-fingerprint',
267 target_info.vendor_fingerprint)
268
269 def test_vendor_fingerprint_blacklisted(self):
270 target_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
271 del target_info_dict['vendor.build.prop']['ro.vendor.build.fingerprint']
272 target_info = BuildInfo(target_info_dict, self.TEST_OEM_DICTS)
273 self.assertIsNone(target_info.vendor_fingerprint)
274
275 def test_vendor_fingerprint_without_vendor_build_prop(self):
276 target_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
277 del target_info_dict['vendor.build.prop']
278 target_info = BuildInfo(target_info_dict, self.TEST_OEM_DICTS)
279 self.assertIsNone(target_info.vendor_fingerprint)
280
Tao Bao481bab82017-12-21 11:23:09 -0800281 def test_WriteMountOemScript(self):
282 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
283 self.TEST_OEM_DICTS)
284 script_writer = MockScriptWriter()
285 target_info.WriteMountOemScript(script_writer)
286 self.assertEqual([('Mount', '/oem', None)], script_writer.script)
287
288 def test_WriteDeviceAssertions(self):
289 target_info = BuildInfo(self.TEST_INFO_DICT, None)
290 script_writer = MockScriptWriter()
291 target_info.WriteDeviceAssertions(script_writer, False)
292 self.assertEqual([('AssertDevice', 'product-device')], script_writer.script)
293
294 def test_WriteDeviceAssertions_with_oem_props(self):
295 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
296 self.TEST_OEM_DICTS)
297 script_writer = MockScriptWriter()
298 target_info.WriteDeviceAssertions(script_writer, False)
299 self.assertEqual(
300 [
301 ('AssertOemProperty', 'ro.product.device',
302 ['device1', 'device2', 'device3'], False),
303 ('AssertOemProperty', 'ro.product.brand',
304 ['brand1', 'brand2', 'brand3'], False),
305 ],
306 script_writer.script)
307
308 def test_WriteFingerprintAssertion_without_oem_props(self):
309 target_info = BuildInfo(self.TEST_INFO_DICT, None)
310 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT)
311 source_info_dict['build.prop']['ro.build.fingerprint'] = (
312 'source-build-fingerprint')
313 source_info = BuildInfo(source_info_dict, None)
314
315 script_writer = MockScriptWriter()
316 WriteFingerprintAssertion(script_writer, target_info, source_info)
317 self.assertEqual(
318 [('AssertSomeFingerprint', 'source-build-fingerprint',
319 'build-fingerprint')],
320 script_writer.script)
321
322 def test_WriteFingerprintAssertion_with_source_oem_props(self):
323 target_info = BuildInfo(self.TEST_INFO_DICT, None)
324 source_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
325 self.TEST_OEM_DICTS)
326
327 script_writer = MockScriptWriter()
328 WriteFingerprintAssertion(script_writer, target_info, source_info)
329 self.assertEqual(
330 [('AssertFingerprintOrThumbprint', 'build-fingerprint',
331 'build-thumbprint')],
332 script_writer.script)
333
334 def test_WriteFingerprintAssertion_with_target_oem_props(self):
335 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
336 self.TEST_OEM_DICTS)
337 source_info = BuildInfo(self.TEST_INFO_DICT, None)
338
339 script_writer = MockScriptWriter()
340 WriteFingerprintAssertion(script_writer, target_info, source_info)
341 self.assertEqual(
342 [('AssertFingerprintOrThumbprint', 'build-fingerprint',
343 'build-thumbprint')],
344 script_writer.script)
345
346 def test_WriteFingerprintAssertion_with_both_oem_props(self):
347 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
348 self.TEST_OEM_DICTS)
349 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
350 source_info_dict['build.prop']['ro.build.thumbprint'] = (
351 'source-build-thumbprint')
352 source_info = BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
353
354 script_writer = MockScriptWriter()
355 WriteFingerprintAssertion(script_writer, target_info, source_info)
356 self.assertEqual(
357 [('AssertSomeThumbprint', 'build-thumbprint',
358 'source-build-thumbprint')],
359 script_writer.script)
360
361
Tao Bao65b94e92018-10-11 21:57:26 -0700362class LoadOemDictsTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -0800363
364 def test_NoneDict(self):
365 self.assertIsNone(_LoadOemDicts(None))
366
367 def test_SingleDict(self):
368 dict_file = common.MakeTempFile()
369 with open(dict_file, 'w') as dict_fp:
370 dict_fp.write('abc=1\ndef=2\nxyz=foo\na.b.c=bar\n')
371
372 oem_dicts = _LoadOemDicts([dict_file])
373 self.assertEqual(1, len(oem_dicts))
374 self.assertEqual('foo', oem_dicts[0]['xyz'])
375 self.assertEqual('bar', oem_dicts[0]['a.b.c'])
376
377 def test_MultipleDicts(self):
378 oem_source = []
379 for i in range(3):
380 dict_file = common.MakeTempFile()
381 with open(dict_file, 'w') as dict_fp:
382 dict_fp.write(
383 'ro.build.index={}\ndef=2\nxyz=foo\na.b.c=bar\n'.format(i))
384 oem_source.append(dict_file)
385
386 oem_dicts = _LoadOemDicts(oem_source)
387 self.assertEqual(3, len(oem_dicts))
388 for i, oem_dict in enumerate(oem_dicts):
389 self.assertEqual('2', oem_dict['def'])
390 self.assertEqual('foo', oem_dict['xyz'])
391 self.assertEqual('bar', oem_dict['a.b.c'])
392 self.assertEqual('{}'.format(i), oem_dict['ro.build.index'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800393
394
Tao Bao65b94e92018-10-11 21:57:26 -0700395class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baodf3a48b2018-01-10 16:30:43 -0800396
397 TEST_TARGET_INFO_DICT = {
398 'build.prop' : {
399 'ro.product.device' : 'product-device',
400 'ro.build.fingerprint' : 'build-fingerprint-target',
401 'ro.build.version.incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800402 'ro.build.version.sdk' : '27',
403 'ro.build.version.security_patch' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800404 'ro.build.date.utc' : '1500000000',
405 },
406 }
407
408 TEST_SOURCE_INFO_DICT = {
409 'build.prop' : {
410 'ro.product.device' : 'product-device',
411 'ro.build.fingerprint' : 'build-fingerprint-source',
412 'ro.build.version.incremental' : 'build-version-incremental-source',
Tao Bao35dc2552018-02-01 13:18:00 -0800413 'ro.build.version.sdk' : '25',
414 'ro.build.version.security_patch' : '2016-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800415 'ro.build.date.utc' : '1400000000',
416 },
417 }
418
419 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700420 self.testdata_dir = test_utils.get_testdata_dir()
421 self.assertTrue(os.path.exists(self.testdata_dir))
422
Tao Baodf3a48b2018-01-10 16:30:43 -0800423 # Reset the global options as in ota_from_target_files.py.
424 common.OPTIONS.incremental_source = None
425 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800426 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800427 common.OPTIONS.timestamp = False
428 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700429 common.OPTIONS.no_signing = False
430 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
431 common.OPTIONS.key_passwords = {
432 common.OPTIONS.package_key : None,
433 }
434
435 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800436
437 def test_GetPackageMetadata_abOta_full(self):
438 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
439 target_info_dict['ab_update'] = 'true'
440 target_info = BuildInfo(target_info_dict, None)
441 metadata = GetPackageMetadata(target_info)
442 self.assertDictEqual(
443 {
444 'ota-type' : 'AB',
445 'ota-required-cache' : '0',
446 'post-build' : 'build-fingerprint-target',
447 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800448 'post-sdk-level' : '27',
449 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800450 'post-timestamp' : '1500000000',
451 'pre-device' : 'product-device',
452 },
453 metadata)
454
455 def test_GetPackageMetadata_abOta_incremental(self):
456 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
457 target_info_dict['ab_update'] = 'true'
458 target_info = BuildInfo(target_info_dict, None)
459 source_info = BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
460 common.OPTIONS.incremental_source = ''
461 metadata = GetPackageMetadata(target_info, source_info)
462 self.assertDictEqual(
463 {
464 'ota-type' : 'AB',
465 'ota-required-cache' : '0',
466 'post-build' : 'build-fingerprint-target',
467 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800468 'post-sdk-level' : '27',
469 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800470 'post-timestamp' : '1500000000',
471 'pre-device' : 'product-device',
472 'pre-build' : 'build-fingerprint-source',
473 'pre-build-incremental' : 'build-version-incremental-source',
474 },
475 metadata)
476
477 def test_GetPackageMetadata_nonAbOta_full(self):
478 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
479 metadata = GetPackageMetadata(target_info)
480 self.assertDictEqual(
481 {
482 'ota-type' : 'BLOCK',
483 'post-build' : 'build-fingerprint-target',
484 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800485 'post-sdk-level' : '27',
486 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800487 'post-timestamp' : '1500000000',
488 'pre-device' : 'product-device',
489 },
490 metadata)
491
492 def test_GetPackageMetadata_nonAbOta_incremental(self):
493 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
494 source_info = BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
495 common.OPTIONS.incremental_source = ''
496 metadata = GetPackageMetadata(target_info, source_info)
497 self.assertDictEqual(
498 {
499 'ota-type' : 'BLOCK',
500 'post-build' : 'build-fingerprint-target',
501 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800502 'post-sdk-level' : '27',
503 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800504 'post-timestamp' : '1500000000',
505 'pre-device' : 'product-device',
506 'pre-build' : 'build-fingerprint-source',
507 'pre-build-incremental' : 'build-version-incremental-source',
508 },
509 metadata)
510
511 def test_GetPackageMetadata_wipe(self):
512 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
513 common.OPTIONS.wipe_user_data = True
514 metadata = GetPackageMetadata(target_info)
515 self.assertDictEqual(
516 {
517 'ota-type' : 'BLOCK',
518 'ota-wipe' : 'yes',
519 'post-build' : 'build-fingerprint-target',
520 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800521 'post-sdk-level' : '27',
522 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800523 'post-timestamp' : '1500000000',
524 'pre-device' : 'product-device',
525 },
526 metadata)
527
Tao Bao393eeb42019-03-06 16:00:38 -0800528 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
529 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
530 common.OPTIONS.retrofit_dynamic_partitions = True
531 metadata = GetPackageMetadata(target_info)
532 self.assertDictEqual(
533 {
534 'ota-retrofit-dynamic-partitions' : 'yes',
535 'ota-type' : 'BLOCK',
536 'post-build' : 'build-fingerprint-target',
537 'post-build-incremental' : 'build-version-incremental-target',
538 'post-sdk-level' : '27',
539 'post-security-patch-level' : '2017-12-01',
540 'post-timestamp' : '1500000000',
541 'pre-device' : 'product-device',
542 },
543 metadata)
544
Tao Baodf3a48b2018-01-10 16:30:43 -0800545 @staticmethod
546 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
547 (target_info['build.prop']['ro.build.date.utc'],
548 source_info['build.prop']['ro.build.date.utc']) = (
549 source_info['build.prop']['ro.build.date.utc'],
550 target_info['build.prop']['ro.build.date.utc'])
551
552 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
553 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
554 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
555 self._test_GetPackageMetadata_swapBuildTimestamps(
556 target_info_dict, source_info_dict)
557
558 target_info = BuildInfo(target_info_dict, None)
559 source_info = BuildInfo(source_info_dict, None)
560 common.OPTIONS.incremental_source = ''
561 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
562 source_info)
563
564 def test_GetPackageMetadata_downgrade(self):
565 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
566 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
567 self._test_GetPackageMetadata_swapBuildTimestamps(
568 target_info_dict, source_info_dict)
569
570 target_info = BuildInfo(target_info_dict, None)
571 source_info = BuildInfo(source_info_dict, None)
572 common.OPTIONS.incremental_source = ''
573 common.OPTIONS.downgrade = True
574 common.OPTIONS.wipe_user_data = True
575 metadata = GetPackageMetadata(target_info, source_info)
576 self.assertDictEqual(
577 {
578 'ota-downgrade' : 'yes',
579 'ota-type' : 'BLOCK',
580 'ota-wipe' : 'yes',
581 'post-build' : 'build-fingerprint-target',
582 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800583 'post-sdk-level' : '27',
584 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700585 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800586 'pre-device' : 'product-device',
587 'pre-build' : 'build-fingerprint-source',
588 'pre-build-incremental' : 'build-version-incremental-source',
589 },
590 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800591
Tao Bao82490d32019-04-09 00:12:30 -0700592 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800593 def test_GetTargetFilesZipForSecondaryImages(self):
594 input_file = construct_target_files(secondary=True)
595 target_file = GetTargetFilesZipForSecondaryImages(input_file)
596
597 with zipfile.ZipFile(target_file) as verify_zip:
598 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700599 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800600
601 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800602 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700603 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800604 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800605
Tao Bao3e759462019-09-17 22:43:11 -0700606 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800607 self.assertNotIn('IMAGES/system_other.img', namelist)
608 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700609 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800610
Tao Bao3e759462019-09-17 22:43:11 -0700611 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700612 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
613
Tao Bao82490d32019-04-09 00:12:30 -0700614 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800615 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
616 input_file = construct_target_files(secondary=True)
617 target_file = GetTargetFilesZipForSecondaryImages(
618 input_file, skip_postinstall=True)
619
620 with zipfile.ZipFile(target_file) as verify_zip:
621 namelist = verify_zip.namelist()
622
623 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800624 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700625 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800626
Tao Bao3e759462019-09-17 22:43:11 -0700627 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800628 self.assertNotIn('IMAGES/system_other.img', namelist)
629 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700630 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800631 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
632
Tao Bao82490d32019-04-09 00:12:30 -0700633 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700634 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
635 input_file = construct_target_files(secondary=True)
636 common.ZipDelete(input_file, 'RADIO/bootloader.img')
637 common.ZipDelete(input_file, 'RADIO/modem.img')
638 target_file = GetTargetFilesZipForSecondaryImages(input_file)
639
640 with zipfile.ZipFile(target_file) as verify_zip:
641 namelist = verify_zip.namelist()
642
643 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700644 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700645 self.assertIn(POSTINSTALL_CONFIG, namelist)
646
Tao Bao3e759462019-09-17 22:43:11 -0700647 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700648 self.assertNotIn('IMAGES/system_other.img', namelist)
649 self.assertNotIn('IMAGES/system.map', namelist)
650 self.assertNotIn('RADIO/bootloader.img', namelist)
651 self.assertNotIn('RADIO/modem.img', namelist)
652
Tao Bao82490d32019-04-09 00:12:30 -0700653 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700654 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
655 input_file = construct_target_files(secondary=True)
656 misc_info = '\n'.join([
657 'use_dynamic_partition_size=true',
658 'use_dynamic_partitions=true',
659 'dynamic_partition_list=system vendor product',
660 'super_partition_groups=google_dynamic_partitions',
661 'super_google_dynamic_partitions_group_size=4873781248',
662 'super_google_dynamic_partitions_partition_list=system vendor product',
663 ])
664 dynamic_partitions_info = '\n'.join([
665 'super_partition_groups=google_dynamic_partitions',
666 'super_google_dynamic_partitions_group_size=4873781248',
667 'super_google_dynamic_partitions_partition_list=system vendor product',
668 ])
669
670 with zipfile.ZipFile(input_file, 'a') as append_zip:
671 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
672 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
673 dynamic_partitions_info)
674
675 target_file = GetTargetFilesZipForSecondaryImages(input_file)
676
677 with zipfile.ZipFile(target_file) as verify_zip:
678 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700679 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700680 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700681 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700682
683 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700684 self.assertIn('IMAGES/system.img', namelist)
685 self.assertIn(POSTINSTALL_CONFIG, namelist)
686 self.assertIn('META/misc_info.txt', namelist)
687 self.assertIn('META/dynamic_partitions_info.txt', namelist)
688
Tao Bao3e759462019-09-17 22:43:11 -0700689 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700690 self.assertNotIn('IMAGES/system_other.img', namelist)
691 self.assertNotIn('IMAGES/system.map', namelist)
692
693 # Check the vendor & product are removed from the partitions list.
694 expected_misc_info = misc_info.replace('system vendor product',
695 'system')
696 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
697 'system vendor product', 'system')
698 self.assertEqual(expected_misc_info, updated_misc_info)
699 self.assertEqual(expected_dynamic_partitions_info,
700 updated_dynamic_partitions_info)
701
702 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800703 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
704 input_file = construct_target_files()
705 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
706 with zipfile.ZipFile(target_file) as verify_zip:
707 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
708
Tao Bao82490d32019-04-09 00:12:30 -0700709 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800710 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
711 input_file = construct_target_files()
712 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
713 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
714 with zipfile.ZipFile(target_file) as verify_zip:
715 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
716
Tao Bao3bf8c652018-03-16 12:59:42 -0700717 def _test_FinalizeMetadata(self, large_entry=False):
718 entries = [
719 'required-entry1',
720 'required-entry2',
721 ]
722 zip_file = PropertyFilesTest.construct_zip_package(entries)
723 # Add a large entry of 1 GiB if requested.
724 if large_entry:
725 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
726 zip_fp.writestr(
727 # Using 'zoo' so that the entry stays behind others after signing.
728 'zoo',
729 'A' * 1024 * 1024 * 1024,
730 zipfile.ZIP_STORED)
731
732 metadata = {}
733 output_file = common.MakeTempFile(suffix='.zip')
734 needed_property_files = (
735 TestPropertyFiles(),
736 )
737 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
738 self.assertIn('ota-test-property-files', metadata)
739
Tao Bao82490d32019-04-09 00:12:30 -0700740 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700741 def test_FinalizeMetadata(self):
742 self._test_FinalizeMetadata()
743
Tao Bao82490d32019-04-09 00:12:30 -0700744 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700745 def test_FinalizeMetadata_withNoSigning(self):
746 common.OPTIONS.no_signing = True
747 self._test_FinalizeMetadata()
748
Tao Bao82490d32019-04-09 00:12:30 -0700749 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700750 def test_FinalizeMetadata_largeEntry(self):
751 self._test_FinalizeMetadata(large_entry=True)
752
Tao Bao82490d32019-04-09 00:12:30 -0700753 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700754 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
755 common.OPTIONS.no_signing = True
756 self._test_FinalizeMetadata(large_entry=True)
757
Tao Bao82490d32019-04-09 00:12:30 -0700758 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700759 def test_FinalizeMetadata_insufficientSpace(self):
760 entries = [
761 'required-entry1',
762 'required-entry2',
763 'optional-entry1',
764 'optional-entry2',
765 ]
766 zip_file = PropertyFilesTest.construct_zip_package(entries)
767 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
768 zip_fp.writestr(
769 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
770 # order) after the signing, which will in turn trigger the
771 # InsufficientSpaceException and an automatic retry.
772 'foo-entry1',
773 'A' * 1024 * 1024,
774 zipfile.ZIP_STORED)
775
776 metadata = {}
777 needed_property_files = (
778 TestPropertyFiles(),
779 )
780 output_file = common.MakeTempFile(suffix='.zip')
781 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
782 self.assertIn('ota-test-property-files', metadata)
783
Tao Baoae5e4c32018-03-01 19:30:00 -0800784
Tao Bao69203522018-03-08 16:09:01 -0800785class TestPropertyFiles(PropertyFiles):
786 """A class that extends PropertyFiles for testing purpose."""
787
788 def __init__(self):
789 super(TestPropertyFiles, self).__init__()
790 self.name = 'ota-test-property-files'
791 self.required = (
792 'required-entry1',
793 'required-entry2',
794 )
795 self.optional = (
796 'optional-entry1',
797 'optional-entry2',
798 )
799
800
Tao Bao65b94e92018-10-11 21:57:26 -0700801class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoae5e4c32018-03-01 19:30:00 -0800802
Tao Bao3bf8c652018-03-16 12:59:42 -0700803 def setUp(self):
804 common.OPTIONS.no_signing = False
805
Tao Baof5110492018-03-02 09:47:43 -0800806 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700807 def construct_zip_package(entries):
Tao Baof5110492018-03-02 09:47:43 -0800808 zip_file = common.MakeTempFile(suffix='.zip')
809 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
810 for entry in entries:
811 zip_fp.writestr(
812 entry,
813 entry.replace('.', '-').upper(),
814 zipfile.ZIP_STORED)
815 return zip_file
816
817 @staticmethod
Tao Bao69203522018-03-08 16:09:01 -0800818 def _parse_property_files_string(data):
Tao Baof5110492018-03-02 09:47:43 -0800819 result = {}
820 for token in data.split(','):
821 name, info = token.split(':', 1)
822 result[name] = info
823 return result
824
825 def _verify_entries(self, input_file, tokens, entries):
826 for entry in entries:
827 offset, size = map(int, tokens[entry].split(':'))
828 with open(input_file, 'rb') as input_fp:
829 input_fp.seek(offset)
830 if entry == 'metadata':
831 expected = b'META-INF/COM/ANDROID/METADATA'
832 else:
833 expected = entry.replace('.', '-').upper().encode()
834 self.assertEqual(expected, input_fp.read(size))
835
Tao Bao82490d32019-04-09 00:12:30 -0700836 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800837 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800838 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800839 'required-entry1',
840 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800841 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700842 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800843 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800844 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800845 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800846
Tao Bao69203522018-03-08 16:09:01 -0800847 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800848 self.assertEqual(3, len(tokens))
849 self._verify_entries(zip_file, tokens, entries)
850
Tao Bao69203522018-03-08 16:09:01 -0800851 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800852 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800853 'required-entry1',
854 'required-entry2',
855 'optional-entry1',
856 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800857 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700858 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800859 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800860 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800861 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800862
Tao Bao69203522018-03-08 16:09:01 -0800863 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800864 self.assertEqual(5, len(tokens))
865 self._verify_entries(zip_file, tokens, entries)
866
Tao Bao69203522018-03-08 16:09:01 -0800867 def test_Compute_missingRequiredEntry(self):
868 entries = (
869 'required-entry2',
870 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700871 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800872 property_files = TestPropertyFiles()
873 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
874 self.assertRaises(KeyError, property_files.Compute, zip_fp)
875
Tao Bao82490d32019-04-09 00:12:30 -0700876 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800877 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800878 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800879 'required-entry1',
880 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800881 'META-INF/com/android/metadata',
882 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700883 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800884 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800885 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700886 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800887 zip_fp, reserve_space=False)
888 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800889 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800890
891 self.assertEqual(3, len(tokens))
892 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
893 # streaming metadata.
894 entries[2] = 'metadata'
895 self._verify_entries(zip_file, tokens, entries)
896
Tao Bao82490d32019-04-09 00:12:30 -0700897 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800898 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800899 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800900 'required-entry1',
901 'required-entry2',
902 'optional-entry1',
903 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800904 'META-INF/com/android/metadata',
905 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700906 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800907 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800908 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
909 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700910 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800911 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800912 raw_length = len(raw_metadata)
913
914 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800915 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800916 self.assertEqual(raw_length, len(streaming_metadata))
917
918 # Or pass in insufficient length.
919 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700920 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800921 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800922 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800923 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800924
925 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800926 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800927 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800928 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800929 self.assertEqual(raw_length + 20, len(streaming_metadata))
930 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
931
Tao Baoae5e4c32018-03-01 19:30:00 -0800932 def test_Verify(self):
933 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800934 'required-entry1',
935 'required-entry2',
936 'optional-entry1',
937 'optional-entry2',
938 'META-INF/com/android/metadata',
939 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700940 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800941 property_files = TestPropertyFiles()
942 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
943 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700944 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800945 zip_fp, reserve_space=False)
946
947 # Should pass the test if verification passes.
948 property_files.Verify(zip_fp, raw_metadata)
949
950 # Or raise on verification failure.
951 self.assertRaises(
952 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
953
954
955class StreamingPropertyFilesTest(PropertyFilesTest):
956 """Additional sanity checks specialized for StreamingPropertyFiles."""
957
958 def test_init(self):
959 property_files = StreamingPropertyFiles()
960 self.assertEqual('ota-streaming-property-files', property_files.name)
961 self.assertEqual(
962 (
963 'payload.bin',
964 'payload_properties.txt',
965 ),
966 property_files.required)
967 self.assertEqual(
968 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700969 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800970 'care_map.txt',
971 'compatibility.zip',
972 ),
973 property_files.optional)
974
975 def test_Compute(self):
976 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800977 'payload.bin',
978 'payload_properties.txt',
979 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800980 'compatibility.zip',
981 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700982 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800983 property_files = StreamingPropertyFiles()
984 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
985 property_files_string = property_files.Compute(zip_fp)
986
987 tokens = self._parse_property_files_string(property_files_string)
988 self.assertEqual(5, len(tokens))
989 self._verify_entries(zip_file, tokens, entries)
990
991 def test_Finalize(self):
992 entries = [
993 'payload.bin',
994 'payload_properties.txt',
995 'care_map.txt',
996 'compatibility.zip',
997 'META-INF/com/android/metadata',
998 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700999 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -08001000 property_files = StreamingPropertyFiles()
1001 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001002 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -08001003 zip_fp, reserve_space=False)
1004 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
1005 tokens = self._parse_property_files_string(streaming_metadata)
1006
1007 self.assertEqual(5, len(tokens))
1008 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
1009 # streaming metadata.
1010 entries[4] = 'metadata'
1011 self._verify_entries(zip_file, tokens, entries)
1012
1013 def test_Verify(self):
1014 entries = (
1015 'payload.bin',
1016 'payload_properties.txt',
1017 'care_map.txt',
1018 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -08001019 'META-INF/com/android/metadata',
1020 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001021 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -08001022 property_files = StreamingPropertyFiles()
1023 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
1024 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001025 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -08001026 zip_fp, reserve_space=False)
1027
1028 # Should pass the test if verification passes.
1029 property_files.Verify(zip_fp, raw_metadata)
1030
1031 # Or raise on verification failure.
1032 self.assertRaises(
1033 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
1034
Tao Baofabe0832018-01-17 15:52:28 -08001035
Tao Baob6304672018-03-08 16:28:33 -08001036class AbOtaPropertyFilesTest(PropertyFilesTest):
1037 """Additional sanity checks specialized for AbOtaPropertyFiles."""
1038
1039 # The size for payload and metadata signature size.
1040 SIGNATURE_SIZE = 256
1041
1042 def setUp(self):
1043 self.testdata_dir = test_utils.get_testdata_dir()
1044 self.assertTrue(os.path.exists(self.testdata_dir))
1045
1046 common.OPTIONS.wipe_user_data = False
1047 common.OPTIONS.payload_signer = None
1048 common.OPTIONS.payload_signer_args = None
1049 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1050 common.OPTIONS.key_passwords = {
1051 common.OPTIONS.package_key : None,
1052 }
1053
1054 def test_init(self):
1055 property_files = AbOtaPropertyFiles()
1056 self.assertEqual('ota-property-files', property_files.name)
1057 self.assertEqual(
1058 (
1059 'payload.bin',
1060 'payload_properties.txt',
1061 ),
1062 property_files.required)
1063 self.assertEqual(
1064 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -07001065 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -08001066 'care_map.txt',
1067 'compatibility.zip',
1068 ),
1069 property_files.optional)
1070
Tao Bao82490d32019-04-09 00:12:30 -07001071 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001072 def test_GetPayloadMetadataOffsetAndSize(self):
1073 target_file = construct_target_files()
1074 payload = Payload()
1075 payload.Generate(target_file)
1076
1077 payload_signer = PayloadSigner()
1078 payload.Sign(payload_signer)
1079
1080 output_file = common.MakeTempFile(suffix='.zip')
1081 with zipfile.ZipFile(output_file, 'w') as output_zip:
1082 payload.WriteToZip(output_zip)
1083
1084 # Find out the payload metadata offset and size.
1085 property_files = AbOtaPropertyFiles()
1086 with zipfile.ZipFile(output_file) as input_zip:
1087 # pylint: disable=protected-access
1088 payload_offset, metadata_total = (
1089 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
1090
1091 # Read in the metadata signature directly.
1092 with open(output_file, 'rb') as verify_fp:
1093 verify_fp.seek(payload_offset + metadata_total - self.SIGNATURE_SIZE)
1094 metadata_signature = verify_fp.read(self.SIGNATURE_SIZE)
1095
1096 # Now we extract the metadata hash via brillo_update_payload script, which
1097 # will serve as the oracle result.
1098 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1099 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1100 cmd = ['brillo_update_payload', 'hash',
1101 '--unsigned_payload', payload.payload_file,
1102 '--signature_size', str(self.SIGNATURE_SIZE),
1103 '--metadata_hash_file', metadata_sig_file,
1104 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -07001105 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -08001106 stdoutdata, _ = proc.communicate()
1107 self.assertEqual(
1108 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -07001109 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -08001110
1111 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
1112
1113 # Finally we can compare the two signatures.
1114 with open(signed_metadata_sig_file, 'rb') as verify_fp:
1115 self.assertEqual(verify_fp.read(), metadata_signature)
1116
1117 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -07001118 def construct_zip_package_withValidPayload(with_metadata=False):
1119 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -08001120 target_file = construct_target_files()
1121 payload = Payload()
1122 payload.Generate(target_file)
1123
1124 payload_signer = PayloadSigner()
1125 payload.Sign(payload_signer)
1126
1127 zip_file = common.MakeTempFile(suffix='.zip')
1128 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
1129 # 'payload.bin',
1130 payload.WriteToZip(zip_fp)
1131
1132 # Other entries.
1133 entries = ['care_map.txt', 'compatibility.zip']
1134
1135 # Put META-INF/com/android/metadata if needed.
1136 if with_metadata:
1137 entries.append('META-INF/com/android/metadata')
1138
1139 for entry in entries:
1140 zip_fp.writestr(
1141 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
1142
1143 return zip_file
1144
Tao Bao82490d32019-04-09 00:12:30 -07001145 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001146 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001147 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -08001148 property_files = AbOtaPropertyFiles()
1149 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
1150 property_files_string = property_files.Compute(zip_fp)
1151
1152 tokens = self._parse_property_files_string(property_files_string)
1153 # "6" indcludes the four entries above, one metadata entry, and one entry
1154 # for payload-metadata.bin.
1155 self.assertEqual(6, len(tokens))
1156 self._verify_entries(
1157 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
1158
Tao Bao82490d32019-04-09 00:12:30 -07001159 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001160 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001161 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -08001162 property_files = AbOtaPropertyFiles()
1163 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001164 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -08001165 zip_fp, reserve_space=False)
1166 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1167
1168 tokens = self._parse_property_files_string(property_files_string)
1169 # "6" indcludes the four entries above, one metadata entry, and one entry
1170 # for payload-metadata.bin.
1171 self.assertEqual(6, len(tokens))
1172 self._verify_entries(
1173 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
1174
Tao Bao82490d32019-04-09 00:12:30 -07001175 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001176 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001177 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -08001178 property_files = AbOtaPropertyFiles()
1179 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001180 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -08001181 zip_fp, reserve_space=False)
1182
1183 property_files.Verify(zip_fp, raw_metadata)
1184
1185
Tao Baoc0746f42018-02-21 13:17:22 -08001186class NonAbOtaPropertyFilesTest(PropertyFilesTest):
1187 """Additional sanity checks specialized for NonAbOtaPropertyFiles."""
1188
1189 def test_init(self):
1190 property_files = NonAbOtaPropertyFiles()
1191 self.assertEqual('ota-property-files', property_files.name)
1192 self.assertEqual((), property_files.required)
1193 self.assertEqual((), property_files.optional)
1194
1195 def test_Compute(self):
1196 entries = ()
Tao Bao3bf8c652018-03-16 12:59:42 -07001197 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001198 property_files = NonAbOtaPropertyFiles()
1199 with zipfile.ZipFile(zip_file) as zip_fp:
1200 property_files_string = property_files.Compute(zip_fp)
1201
1202 tokens = self._parse_property_files_string(property_files_string)
1203 self.assertEqual(1, len(tokens))
1204 self._verify_entries(zip_file, tokens, entries)
1205
1206 def test_Finalize(self):
1207 entries = [
1208 'META-INF/com/android/metadata',
1209 ]
Tao Bao3bf8c652018-03-16 12:59:42 -07001210 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001211 property_files = NonAbOtaPropertyFiles()
1212 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001213 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001214 zip_fp, reserve_space=False)
1215 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1216 tokens = self._parse_property_files_string(property_files_string)
1217
1218 self.assertEqual(1, len(tokens))
1219 # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
1220 entries[0] = 'metadata'
1221 self._verify_entries(zip_file, tokens, entries)
1222
1223 def test_Verify(self):
1224 entries = (
1225 'META-INF/com/android/metadata',
1226 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001227 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001228 property_files = NonAbOtaPropertyFiles()
1229 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001230 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001231 zip_fp, reserve_space=False)
1232
1233 property_files.Verify(zip_fp, raw_metadata)
1234
1235
Tao Bao65b94e92018-10-11 21:57:26 -07001236class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -08001237
1238 SIGFILE = 'sigfile.bin'
1239 SIGNED_SIGFILE = 'signed-sigfile.bin'
1240
1241 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001242 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -08001243 self.assertTrue(os.path.exists(self.testdata_dir))
1244
1245 common.OPTIONS.payload_signer = None
1246 common.OPTIONS.payload_signer_args = []
1247 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1248 common.OPTIONS.key_passwords = {
1249 common.OPTIONS.package_key : None,
1250 }
1251
Tao Baofabe0832018-01-17 15:52:28 -08001252 def _assertFilesEqual(self, file1, file2):
1253 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
1254 self.assertEqual(fp1.read(), fp2.read())
1255
1256 def test_init(self):
1257 payload_signer = PayloadSigner()
1258 self.assertEqual('openssl', payload_signer.signer)
xunchang376cc7c2019-04-08 23:04:58 -07001259 self.assertEqual(256, payload_signer.key_size)
Tao Baofabe0832018-01-17 15:52:28 -08001260
1261 def test_init_withPassword(self):
1262 common.OPTIONS.package_key = os.path.join(
1263 self.testdata_dir, 'testkey_with_passwd')
1264 common.OPTIONS.key_passwords = {
1265 common.OPTIONS.package_key : 'foo',
1266 }
1267 payload_signer = PayloadSigner()
1268 self.assertEqual('openssl', payload_signer.signer)
1269
1270 def test_init_withExternalSigner(self):
1271 common.OPTIONS.payload_signer = 'abc'
1272 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
xunchang376cc7c2019-04-08 23:04:58 -07001273 common.OPTIONS.payload_signer_key_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -08001274 payload_signer = PayloadSigner()
1275 self.assertEqual('abc', payload_signer.signer)
1276 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
xunchang376cc7c2019-04-08 23:04:58 -07001277 self.assertEqual(512, payload_signer.key_size)
1278
1279 def test_GetKeySizeInBytes_512Bytes(self):
1280 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -07001281 # pylint: disable=protected-access
xunchang376cc7c2019-04-08 23:04:58 -07001282 key_size = PayloadSigner._GetKeySizeInBytes(signing_key)
1283 self.assertEqual(512, key_size)
Tao Baofabe0832018-01-17 15:52:28 -08001284
1285 def test_Sign(self):
1286 payload_signer = PayloadSigner()
1287 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1288 signed_file = payload_signer.Sign(input_file)
1289
1290 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1291 self._assertFilesEqual(verify_file, signed_file)
1292
1293 def test_Sign_withExternalSigner_openssl(self):
1294 """Uses openssl as the external payload signer."""
1295 common.OPTIONS.payload_signer = 'openssl'
1296 common.OPTIONS.payload_signer_args = [
1297 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
1298 os.path.join(self.testdata_dir, 'testkey.pk8'),
1299 '-pkeyopt', 'digest:sha256']
1300 payload_signer = PayloadSigner()
1301 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1302 signed_file = payload_signer.Sign(input_file)
1303
1304 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1305 self._assertFilesEqual(verify_file, signed_file)
1306
1307 def test_Sign_withExternalSigner_script(self):
1308 """Uses testdata/payload_signer.sh as the external payload signer."""
1309 common.OPTIONS.payload_signer = os.path.join(
1310 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -07001311 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -08001312 common.OPTIONS.payload_signer_args = [
1313 os.path.join(self.testdata_dir, 'testkey.pk8')]
1314 payload_signer = PayloadSigner()
1315 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1316 signed_file = payload_signer.Sign(input_file)
1317
1318 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1319 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001320
1321
Tao Bao65b94e92018-10-11 21:57:26 -07001322class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001323
1324 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001325 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001326 self.assertTrue(os.path.exists(self.testdata_dir))
1327
1328 common.OPTIONS.wipe_user_data = False
1329 common.OPTIONS.payload_signer = None
1330 common.OPTIONS.payload_signer_args = None
1331 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1332 common.OPTIONS.key_passwords = {
1333 common.OPTIONS.package_key : None,
1334 }
1335
Tao Baoc7b403a2018-01-30 18:19:04 -08001336 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001337 def _create_payload_full(secondary=False):
1338 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001339 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001340 payload.Generate(target_file)
1341 return payload
1342
Tao Baof7140c02018-01-30 17:09:24 -08001343 @staticmethod
1344 def _create_payload_incremental():
1345 target_file = construct_target_files()
1346 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001347 payload = Payload()
1348 payload.Generate(target_file, source_file)
1349 return payload
1350
Tao Bao82490d32019-04-09 00:12:30 -07001351 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001352 def test_Generate_full(self):
1353 payload = self._create_payload_full()
1354 self.assertTrue(os.path.exists(payload.payload_file))
1355
Tao Bao82490d32019-04-09 00:12:30 -07001356 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001357 def test_Generate_incremental(self):
1358 payload = self._create_payload_incremental()
1359 self.assertTrue(os.path.exists(payload.payload_file))
1360
Tao Bao82490d32019-04-09 00:12:30 -07001361 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001362 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001363 target_file = construct_target_files()
1364 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001365 payload = Payload()
1366 # This should work the same as calling payload.Generate(target_file,
1367 # source_file).
1368 payload.Generate(
1369 target_file, additional_args=["--source_image", source_file])
1370 self.assertTrue(os.path.exists(payload.payload_file))
1371
Tao Bao82490d32019-04-09 00:12:30 -07001372 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001373 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001374 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001375 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1376 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001377 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001378
Tao Bao82490d32019-04-09 00:12:30 -07001379 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001380 def test_Sign_full(self):
1381 payload = self._create_payload_full()
1382 payload.Sign(PayloadSigner())
1383
1384 output_file = common.MakeTempFile(suffix='.zip')
1385 with zipfile.ZipFile(output_file, 'w') as output_zip:
1386 payload.WriteToZip(output_zip)
1387
1388 import check_ota_package_signature
1389 check_ota_package_signature.VerifyAbOtaPayload(
1390 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1391 output_file)
1392
Tao Bao82490d32019-04-09 00:12:30 -07001393 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001394 def test_Sign_incremental(self):
1395 payload = self._create_payload_incremental()
1396 payload.Sign(PayloadSigner())
1397
1398 output_file = common.MakeTempFile(suffix='.zip')
1399 with zipfile.ZipFile(output_file, 'w') as output_zip:
1400 payload.WriteToZip(output_zip)
1401
1402 import check_ota_package_signature
1403 check_ota_package_signature.VerifyAbOtaPayload(
1404 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1405 output_file)
1406
Tao Bao82490d32019-04-09 00:12:30 -07001407 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001408 def test_Sign_withDataWipe(self):
1409 common.OPTIONS.wipe_user_data = True
1410 payload = self._create_payload_full()
1411 payload.Sign(PayloadSigner())
1412
1413 with open(payload.payload_properties) as properties_fp:
1414 self.assertIn("POWERWASH=1", properties_fp.read())
1415
Tao Bao82490d32019-04-09 00:12:30 -07001416 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001417 def test_Sign_secondary(self):
1418 payload = self._create_payload_full(secondary=True)
1419 payload.Sign(PayloadSigner())
1420
1421 with open(payload.payload_properties) as properties_fp:
1422 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1423
Tao Bao82490d32019-04-09 00:12:30 -07001424 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001425 def test_Sign_badSigner(self):
1426 """Tests that signing failure can be captured."""
1427 payload = self._create_payload_full()
1428 payload_signer = PayloadSigner()
1429 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001430 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001431
Tao Bao82490d32019-04-09 00:12:30 -07001432 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001433 def test_WriteToZip(self):
1434 payload = self._create_payload_full()
1435 payload.Sign(PayloadSigner())
1436
1437 output_file = common.MakeTempFile(suffix='.zip')
1438 with zipfile.ZipFile(output_file, 'w') as output_zip:
1439 payload.WriteToZip(output_zip)
1440
1441 with zipfile.ZipFile(output_file) as verify_zip:
1442 # First make sure we have the essential entries.
1443 namelist = verify_zip.namelist()
1444 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1445 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1446
1447 # Then assert these entries are stored.
1448 for entry_info in verify_zip.infolist():
1449 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1450 Payload.PAYLOAD_PROPERTIES_TXT):
1451 continue
1452 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1453
Tao Bao82490d32019-04-09 00:12:30 -07001454 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001455 def test_WriteToZip_unsignedPayload(self):
1456 """Unsigned payloads should not be allowed to be written to zip."""
1457 payload = self._create_payload_full()
1458
1459 output_file = common.MakeTempFile(suffix='.zip')
1460 with zipfile.ZipFile(output_file, 'w') as output_zip:
1461 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1462
1463 # Also test with incremental payload.
1464 payload = self._create_payload_incremental()
1465
1466 output_file = common.MakeTempFile(suffix='.zip')
1467 with zipfile.ZipFile(output_file, 'w') as output_zip:
1468 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001469
Tao Bao82490d32019-04-09 00:12:30 -07001470 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001471 def test_WriteToZip_secondary(self):
1472 payload = self._create_payload_full(secondary=True)
1473 payload.Sign(PayloadSigner())
1474
1475 output_file = common.MakeTempFile(suffix='.zip')
1476 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001477 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001478
1479 with zipfile.ZipFile(output_file) as verify_zip:
1480 # First make sure we have the essential entries.
1481 namelist = verify_zip.namelist()
1482 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1483 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1484
1485 # Then assert these entries are stored.
1486 for entry_info in verify_zip.infolist():
1487 if entry_info.filename not in (
1488 Payload.SECONDARY_PAYLOAD_BIN,
1489 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1490 continue
1491 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)