blob: dd42822bbc6d7960d682b7175ae8f148abc0d574 [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 Bao65b94e92018-10-11 21:57:26 -070077class BuildInfoTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -080078
79 TEST_INFO_DICT = {
80 'build.prop' : {
81 'ro.product.device' : 'product-device',
82 'ro.product.name' : 'product-name',
83 'ro.build.fingerprint' : 'build-fingerprint',
84 'ro.build.foo' : 'build-foo',
85 },
86 'vendor.build.prop' : {
87 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
88 },
89 'property1' : 'value1',
90 'property2' : 4096,
91 }
92
93 TEST_INFO_DICT_USES_OEM_PROPS = {
94 'build.prop' : {
95 'ro.product.name' : 'product-name',
96 'ro.build.thumbprint' : 'build-thumbprint',
97 'ro.build.bar' : 'build-bar',
98 },
99 'vendor.build.prop' : {
100 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
101 },
102 'property1' : 'value1',
103 'property2' : 4096,
104 'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
105 }
106
107 TEST_OEM_DICTS = [
108 {
109 'ro.product.brand' : 'brand1',
110 'ro.product.device' : 'device1',
111 },
112 {
113 'ro.product.brand' : 'brand2',
114 'ro.product.device' : 'device2',
115 },
116 {
117 'ro.product.brand' : 'brand3',
118 'ro.product.device' : 'device3',
119 },
120 ]
121
122 def test_init(self):
123 target_info = BuildInfo(self.TEST_INFO_DICT, None)
124 self.assertEqual('product-device', target_info.device)
125 self.assertEqual('build-fingerprint', target_info.fingerprint)
126 self.assertFalse(target_info.is_ab)
127 self.assertIsNone(target_info.oem_props)
128
129 def test_init_with_oem_props(self):
130 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
131 self.TEST_OEM_DICTS)
132 self.assertEqual('device1', target_info.device)
133 self.assertEqual('brand1/product-name/device1:build-thumbprint',
134 target_info.fingerprint)
135
136 # Swap the order in oem_dicts, which would lead to different BuildInfo.
137 oem_dicts = copy.copy(self.TEST_OEM_DICTS)
138 oem_dicts[0], oem_dicts[2] = oem_dicts[2], oem_dicts[0]
139 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS, oem_dicts)
140 self.assertEqual('device3', target_info.device)
141 self.assertEqual('brand3/product-name/device3:build-thumbprint',
142 target_info.fingerprint)
143
144 # Missing oem_dict should be rejected.
145 self.assertRaises(AssertionError, BuildInfo,
146 self.TEST_INFO_DICT_USES_OEM_PROPS, None)
147
Tao Baoc4011cd72019-09-17 00:14:44 -0700148 def test_init_badFingerprint(self):
149 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
150 info_dict['build.prop']['ro.build.fingerprint'] = 'bad fingerprint'
151 self.assertRaises(ValueError, BuildInfo, info_dict, None)
152
153 info_dict['build.prop']['ro.build.fingerprint'] = 'bad\x80fingerprint'
154 self.assertRaises(ValueError, BuildInfo, info_dict, None)
155
Tao Bao481bab82017-12-21 11:23:09 -0800156 def test___getitem__(self):
157 target_info = BuildInfo(self.TEST_INFO_DICT, None)
158 self.assertEqual('value1', target_info['property1'])
159 self.assertEqual(4096, target_info['property2'])
160 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
161
162 def test___getitem__with_oem_props(self):
163 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
164 self.TEST_OEM_DICTS)
165 self.assertEqual('value1', target_info['property1'])
166 self.assertEqual(4096, target_info['property2'])
167 self.assertRaises(KeyError,
168 lambda: target_info['build.prop']['ro.build.foo'])
169
Tao Bao667c7532018-07-06 10:13:59 -0700170 def test___setitem__(self):
171 target_info = BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
172 self.assertEqual('value1', target_info['property1'])
173 target_info['property1'] = 'value2'
174 self.assertEqual('value2', target_info['property1'])
175
176 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
177 target_info['build.prop']['ro.build.foo'] = 'build-bar'
178 self.assertEqual('build-bar', target_info['build.prop']['ro.build.foo'])
179
Tao Bao481bab82017-12-21 11:23:09 -0800180 def test_get(self):
181 target_info = BuildInfo(self.TEST_INFO_DICT, None)
182 self.assertEqual('value1', target_info.get('property1'))
183 self.assertEqual(4096, target_info.get('property2'))
184 self.assertEqual(4096, target_info.get('property2', 1024))
185 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
186 self.assertEqual('build-foo', target_info.get('build.prop')['ro.build.foo'])
187
188 def test_get_with_oem_props(self):
189 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
190 self.TEST_OEM_DICTS)
191 self.assertEqual('value1', target_info.get('property1'))
192 self.assertEqual(4096, target_info.get('property2'))
193 self.assertEqual(4096, target_info.get('property2', 1024))
194 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
195 self.assertIsNone(target_info.get('build.prop').get('ro.build.foo'))
196 self.assertRaises(KeyError,
197 lambda: target_info.get('build.prop')['ro.build.foo'])
198
Tao Bao667c7532018-07-06 10:13:59 -0700199 def test_items(self):
200 target_info = BuildInfo(self.TEST_INFO_DICT, None)
201 items = target_info.items()
202 self.assertIn(('property1', 'value1'), items)
203 self.assertIn(('property2', 4096), items)
204
Tao Bao481bab82017-12-21 11:23:09 -0800205 def test_GetBuildProp(self):
206 target_info = BuildInfo(self.TEST_INFO_DICT, None)
207 self.assertEqual('build-foo', target_info.GetBuildProp('ro.build.foo'))
208 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
209 'ro.build.nonexistent')
210
211 def test_GetBuildProp_with_oem_props(self):
212 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
213 self.TEST_OEM_DICTS)
214 self.assertEqual('build-bar', target_info.GetBuildProp('ro.build.bar'))
215 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
216 'ro.build.nonexistent')
217
218 def test_GetVendorBuildProp(self):
219 target_info = BuildInfo(self.TEST_INFO_DICT, None)
220 self.assertEqual('vendor-build-fingerprint',
221 target_info.GetVendorBuildProp(
222 'ro.vendor.build.fingerprint'))
223 self.assertRaises(common.ExternalError, target_info.GetVendorBuildProp,
224 'ro.build.nonexistent')
225
226 def test_GetVendorBuildProp_with_oem_props(self):
227 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
228 self.TEST_OEM_DICTS)
229 self.assertEqual('vendor-build-fingerprint',
230 target_info.GetVendorBuildProp(
231 'ro.vendor.build.fingerprint'))
232 self.assertRaises(common.ExternalError, target_info.GetVendorBuildProp,
233 'ro.build.nonexistent')
234
Tao Baoea6cbd02018-09-05 13:06:37 -0700235 def test_vendor_fingerprint(self):
236 target_info = BuildInfo(self.TEST_INFO_DICT, None)
237 self.assertEqual('vendor-build-fingerprint',
238 target_info.vendor_fingerprint)
239
240 def test_vendor_fingerprint_blacklisted(self):
241 target_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
242 del target_info_dict['vendor.build.prop']['ro.vendor.build.fingerprint']
243 target_info = BuildInfo(target_info_dict, self.TEST_OEM_DICTS)
244 self.assertIsNone(target_info.vendor_fingerprint)
245
246 def test_vendor_fingerprint_without_vendor_build_prop(self):
247 target_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
248 del target_info_dict['vendor.build.prop']
249 target_info = BuildInfo(target_info_dict, self.TEST_OEM_DICTS)
250 self.assertIsNone(target_info.vendor_fingerprint)
251
Tao Bao481bab82017-12-21 11:23:09 -0800252 def test_WriteMountOemScript(self):
253 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
254 self.TEST_OEM_DICTS)
Tao Baoe1148042019-10-07 20:00:34 -0700255 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800256 target_info.WriteMountOemScript(script_writer)
Tao Baoe1148042019-10-07 20:00:34 -0700257 self.assertEqual([('Mount', '/oem', None)], script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800258
259 def test_WriteDeviceAssertions(self):
260 target_info = BuildInfo(self.TEST_INFO_DICT, None)
Tao Baoe1148042019-10-07 20:00:34 -0700261 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800262 target_info.WriteDeviceAssertions(script_writer, False)
Tao Baoe1148042019-10-07 20:00:34 -0700263 self.assertEqual([('AssertDevice', 'product-device')], script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800264
265 def test_WriteDeviceAssertions_with_oem_props(self):
266 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
267 self.TEST_OEM_DICTS)
Tao Baoe1148042019-10-07 20:00:34 -0700268 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800269 target_info.WriteDeviceAssertions(script_writer, False)
270 self.assertEqual(
271 [
272 ('AssertOemProperty', 'ro.product.device',
273 ['device1', 'device2', 'device3'], False),
274 ('AssertOemProperty', 'ro.product.brand',
275 ['brand1', 'brand2', 'brand3'], False),
276 ],
Tao Baoe1148042019-10-07 20:00:34 -0700277 script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800278
279 def test_WriteFingerprintAssertion_without_oem_props(self):
280 target_info = BuildInfo(self.TEST_INFO_DICT, None)
281 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT)
282 source_info_dict['build.prop']['ro.build.fingerprint'] = (
283 'source-build-fingerprint')
284 source_info = BuildInfo(source_info_dict, None)
285
Tao Baoe1148042019-10-07 20:00:34 -0700286 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800287 WriteFingerprintAssertion(script_writer, target_info, source_info)
288 self.assertEqual(
289 [('AssertSomeFingerprint', 'source-build-fingerprint',
290 'build-fingerprint')],
Tao Baoe1148042019-10-07 20:00:34 -0700291 script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800292
293 def test_WriteFingerprintAssertion_with_source_oem_props(self):
294 target_info = BuildInfo(self.TEST_INFO_DICT, None)
295 source_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
296 self.TEST_OEM_DICTS)
297
Tao Baoe1148042019-10-07 20:00:34 -0700298 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800299 WriteFingerprintAssertion(script_writer, target_info, source_info)
300 self.assertEqual(
301 [('AssertFingerprintOrThumbprint', 'build-fingerprint',
302 'build-thumbprint')],
Tao Baoe1148042019-10-07 20:00:34 -0700303 script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800304
305 def test_WriteFingerprintAssertion_with_target_oem_props(self):
306 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
307 self.TEST_OEM_DICTS)
308 source_info = BuildInfo(self.TEST_INFO_DICT, None)
309
Tao Baoe1148042019-10-07 20:00:34 -0700310 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800311 WriteFingerprintAssertion(script_writer, target_info, source_info)
312 self.assertEqual(
313 [('AssertFingerprintOrThumbprint', 'build-fingerprint',
314 'build-thumbprint')],
Tao Baoe1148042019-10-07 20:00:34 -0700315 script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800316
317 def test_WriteFingerprintAssertion_with_both_oem_props(self):
318 target_info = BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
319 self.TEST_OEM_DICTS)
320 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
321 source_info_dict['build.prop']['ro.build.thumbprint'] = (
322 'source-build-thumbprint')
323 source_info = BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
324
Tao Baoe1148042019-10-07 20:00:34 -0700325 script_writer = test_utils.MockScriptWriter()
Tao Bao481bab82017-12-21 11:23:09 -0800326 WriteFingerprintAssertion(script_writer, target_info, source_info)
327 self.assertEqual(
328 [('AssertSomeThumbprint', 'build-thumbprint',
329 'source-build-thumbprint')],
Tao Baoe1148042019-10-07 20:00:34 -0700330 script_writer.lines)
Tao Bao481bab82017-12-21 11:23:09 -0800331
332
Tao Bao65b94e92018-10-11 21:57:26 -0700333class LoadOemDictsTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -0800334
335 def test_NoneDict(self):
336 self.assertIsNone(_LoadOemDicts(None))
337
338 def test_SingleDict(self):
339 dict_file = common.MakeTempFile()
340 with open(dict_file, 'w') as dict_fp:
341 dict_fp.write('abc=1\ndef=2\nxyz=foo\na.b.c=bar\n')
342
343 oem_dicts = _LoadOemDicts([dict_file])
344 self.assertEqual(1, len(oem_dicts))
345 self.assertEqual('foo', oem_dicts[0]['xyz'])
346 self.assertEqual('bar', oem_dicts[0]['a.b.c'])
347
348 def test_MultipleDicts(self):
349 oem_source = []
350 for i in range(3):
351 dict_file = common.MakeTempFile()
352 with open(dict_file, 'w') as dict_fp:
353 dict_fp.write(
354 'ro.build.index={}\ndef=2\nxyz=foo\na.b.c=bar\n'.format(i))
355 oem_source.append(dict_file)
356
357 oem_dicts = _LoadOemDicts(oem_source)
358 self.assertEqual(3, len(oem_dicts))
359 for i, oem_dict in enumerate(oem_dicts):
360 self.assertEqual('2', oem_dict['def'])
361 self.assertEqual('foo', oem_dict['xyz'])
362 self.assertEqual('bar', oem_dict['a.b.c'])
363 self.assertEqual('{}'.format(i), oem_dict['ro.build.index'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800364
365
Tao Bao65b94e92018-10-11 21:57:26 -0700366class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baodf3a48b2018-01-10 16:30:43 -0800367
368 TEST_TARGET_INFO_DICT = {
369 'build.prop' : {
370 'ro.product.device' : 'product-device',
371 'ro.build.fingerprint' : 'build-fingerprint-target',
372 'ro.build.version.incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800373 'ro.build.version.sdk' : '27',
374 'ro.build.version.security_patch' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800375 'ro.build.date.utc' : '1500000000',
376 },
377 }
378
379 TEST_SOURCE_INFO_DICT = {
380 'build.prop' : {
381 'ro.product.device' : 'product-device',
382 'ro.build.fingerprint' : 'build-fingerprint-source',
383 'ro.build.version.incremental' : 'build-version-incremental-source',
Tao Bao35dc2552018-02-01 13:18:00 -0800384 'ro.build.version.sdk' : '25',
385 'ro.build.version.security_patch' : '2016-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800386 'ro.build.date.utc' : '1400000000',
387 },
388 }
389
390 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700391 self.testdata_dir = test_utils.get_testdata_dir()
392 self.assertTrue(os.path.exists(self.testdata_dir))
393
Tao Baodf3a48b2018-01-10 16:30:43 -0800394 # Reset the global options as in ota_from_target_files.py.
395 common.OPTIONS.incremental_source = None
396 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800397 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800398 common.OPTIONS.timestamp = False
399 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700400 common.OPTIONS.no_signing = False
401 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
402 common.OPTIONS.key_passwords = {
403 common.OPTIONS.package_key : None,
404 }
405
406 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800407
408 def test_GetPackageMetadata_abOta_full(self):
409 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
410 target_info_dict['ab_update'] = 'true'
411 target_info = BuildInfo(target_info_dict, None)
412 metadata = GetPackageMetadata(target_info)
413 self.assertDictEqual(
414 {
415 'ota-type' : 'AB',
416 'ota-required-cache' : '0',
417 'post-build' : 'build-fingerprint-target',
418 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800419 'post-sdk-level' : '27',
420 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800421 'post-timestamp' : '1500000000',
422 'pre-device' : 'product-device',
423 },
424 metadata)
425
426 def test_GetPackageMetadata_abOta_incremental(self):
427 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
428 target_info_dict['ab_update'] = 'true'
429 target_info = BuildInfo(target_info_dict, None)
430 source_info = BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
431 common.OPTIONS.incremental_source = ''
432 metadata = GetPackageMetadata(target_info, source_info)
433 self.assertDictEqual(
434 {
435 'ota-type' : 'AB',
436 'ota-required-cache' : '0',
437 'post-build' : 'build-fingerprint-target',
438 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800439 'post-sdk-level' : '27',
440 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800441 'post-timestamp' : '1500000000',
442 'pre-device' : 'product-device',
443 'pre-build' : 'build-fingerprint-source',
444 'pre-build-incremental' : 'build-version-incremental-source',
445 },
446 metadata)
447
448 def test_GetPackageMetadata_nonAbOta_full(self):
449 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
450 metadata = GetPackageMetadata(target_info)
451 self.assertDictEqual(
452 {
453 'ota-type' : 'BLOCK',
454 'post-build' : 'build-fingerprint-target',
455 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800456 'post-sdk-level' : '27',
457 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800458 'post-timestamp' : '1500000000',
459 'pre-device' : 'product-device',
460 },
461 metadata)
462
463 def test_GetPackageMetadata_nonAbOta_incremental(self):
464 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
465 source_info = BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
466 common.OPTIONS.incremental_source = ''
467 metadata = GetPackageMetadata(target_info, source_info)
468 self.assertDictEqual(
469 {
470 'ota-type' : 'BLOCK',
471 'post-build' : 'build-fingerprint-target',
472 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800473 'post-sdk-level' : '27',
474 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800475 'post-timestamp' : '1500000000',
476 'pre-device' : 'product-device',
477 'pre-build' : 'build-fingerprint-source',
478 'pre-build-incremental' : 'build-version-incremental-source',
479 },
480 metadata)
481
482 def test_GetPackageMetadata_wipe(self):
483 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
484 common.OPTIONS.wipe_user_data = True
485 metadata = GetPackageMetadata(target_info)
486 self.assertDictEqual(
487 {
488 'ota-type' : 'BLOCK',
489 'ota-wipe' : 'yes',
490 'post-build' : 'build-fingerprint-target',
491 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800492 'post-sdk-level' : '27',
493 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800494 'post-timestamp' : '1500000000',
495 'pre-device' : 'product-device',
496 },
497 metadata)
498
Tao Bao393eeb42019-03-06 16:00:38 -0800499 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
500 target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
501 common.OPTIONS.retrofit_dynamic_partitions = True
502 metadata = GetPackageMetadata(target_info)
503 self.assertDictEqual(
504 {
505 'ota-retrofit-dynamic-partitions' : 'yes',
506 'ota-type' : 'BLOCK',
507 'post-build' : 'build-fingerprint-target',
508 'post-build-incremental' : 'build-version-incremental-target',
509 'post-sdk-level' : '27',
510 'post-security-patch-level' : '2017-12-01',
511 'post-timestamp' : '1500000000',
512 'pre-device' : 'product-device',
513 },
514 metadata)
515
Tao Baodf3a48b2018-01-10 16:30:43 -0800516 @staticmethod
517 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
518 (target_info['build.prop']['ro.build.date.utc'],
519 source_info['build.prop']['ro.build.date.utc']) = (
520 source_info['build.prop']['ro.build.date.utc'],
521 target_info['build.prop']['ro.build.date.utc'])
522
523 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
524 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
525 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
526 self._test_GetPackageMetadata_swapBuildTimestamps(
527 target_info_dict, source_info_dict)
528
529 target_info = BuildInfo(target_info_dict, None)
530 source_info = BuildInfo(source_info_dict, None)
531 common.OPTIONS.incremental_source = ''
532 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
533 source_info)
534
535 def test_GetPackageMetadata_downgrade(self):
536 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
537 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
538 self._test_GetPackageMetadata_swapBuildTimestamps(
539 target_info_dict, source_info_dict)
540
541 target_info = BuildInfo(target_info_dict, None)
542 source_info = BuildInfo(source_info_dict, None)
543 common.OPTIONS.incremental_source = ''
544 common.OPTIONS.downgrade = True
545 common.OPTIONS.wipe_user_data = True
546 metadata = GetPackageMetadata(target_info, source_info)
547 self.assertDictEqual(
548 {
549 'ota-downgrade' : 'yes',
550 'ota-type' : 'BLOCK',
551 'ota-wipe' : 'yes',
552 'post-build' : 'build-fingerprint-target',
553 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800554 'post-sdk-level' : '27',
555 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700556 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800557 'pre-device' : 'product-device',
558 'pre-build' : 'build-fingerprint-source',
559 'pre-build-incremental' : 'build-version-incremental-source',
560 },
561 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800562
Tao Bao82490d32019-04-09 00:12:30 -0700563 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800564 def test_GetTargetFilesZipForSecondaryImages(self):
565 input_file = construct_target_files(secondary=True)
566 target_file = GetTargetFilesZipForSecondaryImages(input_file)
567
568 with zipfile.ZipFile(target_file) as verify_zip:
569 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700570 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800571
572 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800573 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700574 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800575 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800576
Tao Bao3e759462019-09-17 22:43:11 -0700577 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800578 self.assertNotIn('IMAGES/system_other.img', namelist)
579 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700580 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800581
Tao Bao3e759462019-09-17 22:43:11 -0700582 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700583 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
584
Tao Bao82490d32019-04-09 00:12:30 -0700585 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800586 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
587 input_file = construct_target_files(secondary=True)
588 target_file = GetTargetFilesZipForSecondaryImages(
589 input_file, skip_postinstall=True)
590
591 with zipfile.ZipFile(target_file) as verify_zip:
592 namelist = verify_zip.namelist()
593
594 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800595 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700596 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800597
Tao Bao3e759462019-09-17 22:43:11 -0700598 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800599 self.assertNotIn('IMAGES/system_other.img', namelist)
600 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700601 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800602 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
603
Tao Bao82490d32019-04-09 00:12:30 -0700604 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700605 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
606 input_file = construct_target_files(secondary=True)
607 common.ZipDelete(input_file, 'RADIO/bootloader.img')
608 common.ZipDelete(input_file, 'RADIO/modem.img')
609 target_file = GetTargetFilesZipForSecondaryImages(input_file)
610
611 with zipfile.ZipFile(target_file) as verify_zip:
612 namelist = verify_zip.namelist()
613
614 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700615 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700616 self.assertIn(POSTINSTALL_CONFIG, namelist)
617
Tao Bao3e759462019-09-17 22:43:11 -0700618 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700619 self.assertNotIn('IMAGES/system_other.img', namelist)
620 self.assertNotIn('IMAGES/system.map', namelist)
621 self.assertNotIn('RADIO/bootloader.img', namelist)
622 self.assertNotIn('RADIO/modem.img', namelist)
623
Tao Bao82490d32019-04-09 00:12:30 -0700624 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700625 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
626 input_file = construct_target_files(secondary=True)
627 misc_info = '\n'.join([
628 'use_dynamic_partition_size=true',
629 'use_dynamic_partitions=true',
630 'dynamic_partition_list=system vendor product',
631 'super_partition_groups=google_dynamic_partitions',
632 'super_google_dynamic_partitions_group_size=4873781248',
633 'super_google_dynamic_partitions_partition_list=system vendor product',
634 ])
635 dynamic_partitions_info = '\n'.join([
636 'super_partition_groups=google_dynamic_partitions',
637 'super_google_dynamic_partitions_group_size=4873781248',
638 'super_google_dynamic_partitions_partition_list=system vendor product',
639 ])
640
641 with zipfile.ZipFile(input_file, 'a') as append_zip:
642 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
643 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
644 dynamic_partitions_info)
645
646 target_file = GetTargetFilesZipForSecondaryImages(input_file)
647
648 with zipfile.ZipFile(target_file) as verify_zip:
649 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700650 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700651 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700652 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700653
654 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700655 self.assertIn('IMAGES/system.img', namelist)
656 self.assertIn(POSTINSTALL_CONFIG, namelist)
657 self.assertIn('META/misc_info.txt', namelist)
658 self.assertIn('META/dynamic_partitions_info.txt', namelist)
659
Tao Bao3e759462019-09-17 22:43:11 -0700660 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700661 self.assertNotIn('IMAGES/system_other.img', namelist)
662 self.assertNotIn('IMAGES/system.map', namelist)
663
664 # Check the vendor & product are removed from the partitions list.
665 expected_misc_info = misc_info.replace('system vendor product',
666 'system')
667 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
668 'system vendor product', 'system')
669 self.assertEqual(expected_misc_info, updated_misc_info)
670 self.assertEqual(expected_dynamic_partitions_info,
671 updated_dynamic_partitions_info)
672
673 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800674 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
675 input_file = construct_target_files()
676 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
677 with zipfile.ZipFile(target_file) as verify_zip:
678 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
679
Tao Bao82490d32019-04-09 00:12:30 -0700680 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800681 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
682 input_file = construct_target_files()
683 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
684 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
685 with zipfile.ZipFile(target_file) as verify_zip:
686 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
687
Tao Bao3bf8c652018-03-16 12:59:42 -0700688 def _test_FinalizeMetadata(self, large_entry=False):
689 entries = [
690 'required-entry1',
691 'required-entry2',
692 ]
693 zip_file = PropertyFilesTest.construct_zip_package(entries)
694 # Add a large entry of 1 GiB if requested.
695 if large_entry:
696 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
697 zip_fp.writestr(
698 # Using 'zoo' so that the entry stays behind others after signing.
699 'zoo',
700 'A' * 1024 * 1024 * 1024,
701 zipfile.ZIP_STORED)
702
703 metadata = {}
704 output_file = common.MakeTempFile(suffix='.zip')
705 needed_property_files = (
706 TestPropertyFiles(),
707 )
708 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
709 self.assertIn('ota-test-property-files', metadata)
710
Tao Bao82490d32019-04-09 00:12:30 -0700711 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700712 def test_FinalizeMetadata(self):
713 self._test_FinalizeMetadata()
714
Tao Bao82490d32019-04-09 00:12:30 -0700715 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700716 def test_FinalizeMetadata_withNoSigning(self):
717 common.OPTIONS.no_signing = True
718 self._test_FinalizeMetadata()
719
Tao Bao82490d32019-04-09 00:12:30 -0700720 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700721 def test_FinalizeMetadata_largeEntry(self):
722 self._test_FinalizeMetadata(large_entry=True)
723
Tao Bao82490d32019-04-09 00:12:30 -0700724 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700725 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
726 common.OPTIONS.no_signing = True
727 self._test_FinalizeMetadata(large_entry=True)
728
Tao Bao82490d32019-04-09 00:12:30 -0700729 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700730 def test_FinalizeMetadata_insufficientSpace(self):
731 entries = [
732 'required-entry1',
733 'required-entry2',
734 'optional-entry1',
735 'optional-entry2',
736 ]
737 zip_file = PropertyFilesTest.construct_zip_package(entries)
738 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
739 zip_fp.writestr(
740 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
741 # order) after the signing, which will in turn trigger the
742 # InsufficientSpaceException and an automatic retry.
743 'foo-entry1',
744 'A' * 1024 * 1024,
745 zipfile.ZIP_STORED)
746
747 metadata = {}
748 needed_property_files = (
749 TestPropertyFiles(),
750 )
751 output_file = common.MakeTempFile(suffix='.zip')
752 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
753 self.assertIn('ota-test-property-files', metadata)
754
Tao Baoae5e4c32018-03-01 19:30:00 -0800755
Tao Bao69203522018-03-08 16:09:01 -0800756class TestPropertyFiles(PropertyFiles):
757 """A class that extends PropertyFiles for testing purpose."""
758
759 def __init__(self):
760 super(TestPropertyFiles, self).__init__()
761 self.name = 'ota-test-property-files'
762 self.required = (
763 'required-entry1',
764 'required-entry2',
765 )
766 self.optional = (
767 'optional-entry1',
768 'optional-entry2',
769 )
770
771
Tao Bao65b94e92018-10-11 21:57:26 -0700772class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoae5e4c32018-03-01 19:30:00 -0800773
Tao Bao3bf8c652018-03-16 12:59:42 -0700774 def setUp(self):
775 common.OPTIONS.no_signing = False
776
Tao Baof5110492018-03-02 09:47:43 -0800777 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700778 def construct_zip_package(entries):
Tao Baof5110492018-03-02 09:47:43 -0800779 zip_file = common.MakeTempFile(suffix='.zip')
780 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
781 for entry in entries:
782 zip_fp.writestr(
783 entry,
784 entry.replace('.', '-').upper(),
785 zipfile.ZIP_STORED)
786 return zip_file
787
788 @staticmethod
Tao Bao69203522018-03-08 16:09:01 -0800789 def _parse_property_files_string(data):
Tao Baof5110492018-03-02 09:47:43 -0800790 result = {}
791 for token in data.split(','):
792 name, info = token.split(':', 1)
793 result[name] = info
794 return result
795
796 def _verify_entries(self, input_file, tokens, entries):
797 for entry in entries:
798 offset, size = map(int, tokens[entry].split(':'))
799 with open(input_file, 'rb') as input_fp:
800 input_fp.seek(offset)
801 if entry == 'metadata':
802 expected = b'META-INF/COM/ANDROID/METADATA'
803 else:
804 expected = entry.replace('.', '-').upper().encode()
805 self.assertEqual(expected, input_fp.read(size))
806
Tao Bao82490d32019-04-09 00:12:30 -0700807 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800808 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800809 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800810 'required-entry1',
811 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800812 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700813 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800814 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800815 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800816 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800817
Tao Bao69203522018-03-08 16:09:01 -0800818 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800819 self.assertEqual(3, len(tokens))
820 self._verify_entries(zip_file, tokens, entries)
821
Tao Bao69203522018-03-08 16:09:01 -0800822 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800823 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800824 'required-entry1',
825 'required-entry2',
826 'optional-entry1',
827 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800828 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700829 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800830 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800831 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800832 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800833
Tao Bao69203522018-03-08 16:09:01 -0800834 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800835 self.assertEqual(5, len(tokens))
836 self._verify_entries(zip_file, tokens, entries)
837
Tao Bao69203522018-03-08 16:09:01 -0800838 def test_Compute_missingRequiredEntry(self):
839 entries = (
840 'required-entry2',
841 )
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()
844 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
845 self.assertRaises(KeyError, property_files.Compute, zip_fp)
846
Tao Bao82490d32019-04-09 00:12:30 -0700847 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800848 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800849 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800850 'required-entry1',
851 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800852 'META-INF/com/android/metadata',
853 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700854 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800855 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800856 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700857 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800858 zip_fp, reserve_space=False)
859 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800860 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800861
862 self.assertEqual(3, len(tokens))
863 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
864 # streaming metadata.
865 entries[2] = 'metadata'
866 self._verify_entries(zip_file, tokens, entries)
867
Tao Bao82490d32019-04-09 00:12:30 -0700868 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800869 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800870 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800871 'required-entry1',
872 'required-entry2',
873 'optional-entry1',
874 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800875 'META-INF/com/android/metadata',
876 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700877 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800878 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800879 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
880 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700881 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800882 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800883 raw_length = len(raw_metadata)
884
885 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800886 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800887 self.assertEqual(raw_length, len(streaming_metadata))
888
889 # Or pass in insufficient length.
890 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700891 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800892 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800893 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800894 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800895
896 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800897 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800898 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800899 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800900 self.assertEqual(raw_length + 20, len(streaming_metadata))
901 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
902
Tao Baoae5e4c32018-03-01 19:30:00 -0800903 def test_Verify(self):
904 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800905 'required-entry1',
906 'required-entry2',
907 'optional-entry1',
908 'optional-entry2',
909 'META-INF/com/android/metadata',
910 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700911 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800912 property_files = TestPropertyFiles()
913 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
914 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700915 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800916 zip_fp, reserve_space=False)
917
918 # Should pass the test if verification passes.
919 property_files.Verify(zip_fp, raw_metadata)
920
921 # Or raise on verification failure.
922 self.assertRaises(
923 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
924
925
926class StreamingPropertyFilesTest(PropertyFilesTest):
927 """Additional sanity checks specialized for StreamingPropertyFiles."""
928
929 def test_init(self):
930 property_files = StreamingPropertyFiles()
931 self.assertEqual('ota-streaming-property-files', property_files.name)
932 self.assertEqual(
933 (
934 'payload.bin',
935 'payload_properties.txt',
936 ),
937 property_files.required)
938 self.assertEqual(
939 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700940 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800941 'care_map.txt',
942 'compatibility.zip',
943 ),
944 property_files.optional)
945
946 def test_Compute(self):
947 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800948 'payload.bin',
949 'payload_properties.txt',
950 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800951 'compatibility.zip',
952 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700953 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800954 property_files = StreamingPropertyFiles()
955 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
956 property_files_string = property_files.Compute(zip_fp)
957
958 tokens = self._parse_property_files_string(property_files_string)
959 self.assertEqual(5, len(tokens))
960 self._verify_entries(zip_file, tokens, entries)
961
962 def test_Finalize(self):
963 entries = [
964 'payload.bin',
965 'payload_properties.txt',
966 'care_map.txt',
967 'compatibility.zip',
968 'META-INF/com/android/metadata',
969 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700970 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800971 property_files = StreamingPropertyFiles()
972 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700973 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800974 zip_fp, reserve_space=False)
975 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
976 tokens = self._parse_property_files_string(streaming_metadata)
977
978 self.assertEqual(5, len(tokens))
979 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
980 # streaming metadata.
981 entries[4] = 'metadata'
982 self._verify_entries(zip_file, tokens, entries)
983
984 def test_Verify(self):
985 entries = (
986 'payload.bin',
987 'payload_properties.txt',
988 'care_map.txt',
989 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -0800990 'META-INF/com/android/metadata',
991 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700992 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -0800993 property_files = StreamingPropertyFiles()
994 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
995 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700996 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800997 zip_fp, reserve_space=False)
998
999 # Should pass the test if verification passes.
1000 property_files.Verify(zip_fp, raw_metadata)
1001
1002 # Or raise on verification failure.
1003 self.assertRaises(
1004 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
1005
Tao Baofabe0832018-01-17 15:52:28 -08001006
Tao Baob6304672018-03-08 16:28:33 -08001007class AbOtaPropertyFilesTest(PropertyFilesTest):
1008 """Additional sanity checks specialized for AbOtaPropertyFiles."""
1009
1010 # The size for payload and metadata signature size.
1011 SIGNATURE_SIZE = 256
1012
1013 def setUp(self):
1014 self.testdata_dir = test_utils.get_testdata_dir()
1015 self.assertTrue(os.path.exists(self.testdata_dir))
1016
1017 common.OPTIONS.wipe_user_data = False
1018 common.OPTIONS.payload_signer = None
1019 common.OPTIONS.payload_signer_args = None
1020 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1021 common.OPTIONS.key_passwords = {
1022 common.OPTIONS.package_key : None,
1023 }
1024
1025 def test_init(self):
1026 property_files = AbOtaPropertyFiles()
1027 self.assertEqual('ota-property-files', property_files.name)
1028 self.assertEqual(
1029 (
1030 'payload.bin',
1031 'payload_properties.txt',
1032 ),
1033 property_files.required)
1034 self.assertEqual(
1035 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -07001036 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -08001037 'care_map.txt',
1038 'compatibility.zip',
1039 ),
1040 property_files.optional)
1041
Tao Bao82490d32019-04-09 00:12:30 -07001042 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001043 def test_GetPayloadMetadataOffsetAndSize(self):
1044 target_file = construct_target_files()
1045 payload = Payload()
1046 payload.Generate(target_file)
1047
1048 payload_signer = PayloadSigner()
1049 payload.Sign(payload_signer)
1050
1051 output_file = common.MakeTempFile(suffix='.zip')
1052 with zipfile.ZipFile(output_file, 'w') as output_zip:
1053 payload.WriteToZip(output_zip)
1054
1055 # Find out the payload metadata offset and size.
1056 property_files = AbOtaPropertyFiles()
1057 with zipfile.ZipFile(output_file) as input_zip:
1058 # pylint: disable=protected-access
1059 payload_offset, metadata_total = (
1060 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
1061
1062 # Read in the metadata signature directly.
1063 with open(output_file, 'rb') as verify_fp:
1064 verify_fp.seek(payload_offset + metadata_total - self.SIGNATURE_SIZE)
1065 metadata_signature = verify_fp.read(self.SIGNATURE_SIZE)
1066
1067 # Now we extract the metadata hash via brillo_update_payload script, which
1068 # will serve as the oracle result.
1069 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1070 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1071 cmd = ['brillo_update_payload', 'hash',
1072 '--unsigned_payload', payload.payload_file,
1073 '--signature_size', str(self.SIGNATURE_SIZE),
1074 '--metadata_hash_file', metadata_sig_file,
1075 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -07001076 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -08001077 stdoutdata, _ = proc.communicate()
1078 self.assertEqual(
1079 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -07001080 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -08001081
1082 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
1083
1084 # Finally we can compare the two signatures.
1085 with open(signed_metadata_sig_file, 'rb') as verify_fp:
1086 self.assertEqual(verify_fp.read(), metadata_signature)
1087
1088 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -07001089 def construct_zip_package_withValidPayload(with_metadata=False):
1090 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -08001091 target_file = construct_target_files()
1092 payload = Payload()
1093 payload.Generate(target_file)
1094
1095 payload_signer = PayloadSigner()
1096 payload.Sign(payload_signer)
1097
1098 zip_file = common.MakeTempFile(suffix='.zip')
1099 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
1100 # 'payload.bin',
1101 payload.WriteToZip(zip_fp)
1102
1103 # Other entries.
1104 entries = ['care_map.txt', 'compatibility.zip']
1105
1106 # Put META-INF/com/android/metadata if needed.
1107 if with_metadata:
1108 entries.append('META-INF/com/android/metadata')
1109
1110 for entry in entries:
1111 zip_fp.writestr(
1112 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
1113
1114 return zip_file
1115
Tao Bao82490d32019-04-09 00:12:30 -07001116 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001117 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001118 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -08001119 property_files = AbOtaPropertyFiles()
1120 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
1121 property_files_string = property_files.Compute(zip_fp)
1122
1123 tokens = self._parse_property_files_string(property_files_string)
1124 # "6" indcludes the four entries above, one metadata entry, and one entry
1125 # for payload-metadata.bin.
1126 self.assertEqual(6, len(tokens))
1127 self._verify_entries(
1128 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
1129
Tao Bao82490d32019-04-09 00:12:30 -07001130 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001131 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001132 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -08001133 property_files = AbOtaPropertyFiles()
1134 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001135 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -08001136 zip_fp, reserve_space=False)
1137 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1138
1139 tokens = self._parse_property_files_string(property_files_string)
1140 # "6" indcludes the four entries above, one metadata entry, and one entry
1141 # for payload-metadata.bin.
1142 self.assertEqual(6, len(tokens))
1143 self._verify_entries(
1144 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
1145
Tao Bao82490d32019-04-09 00:12:30 -07001146 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -08001147 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -07001148 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -08001149 property_files = AbOtaPropertyFiles()
1150 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001151 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -08001152 zip_fp, reserve_space=False)
1153
1154 property_files.Verify(zip_fp, raw_metadata)
1155
1156
Tao Baoc0746f42018-02-21 13:17:22 -08001157class NonAbOtaPropertyFilesTest(PropertyFilesTest):
1158 """Additional sanity checks specialized for NonAbOtaPropertyFiles."""
1159
1160 def test_init(self):
1161 property_files = NonAbOtaPropertyFiles()
1162 self.assertEqual('ota-property-files', property_files.name)
1163 self.assertEqual((), property_files.required)
1164 self.assertEqual((), property_files.optional)
1165
1166 def test_Compute(self):
1167 entries = ()
Tao Bao3bf8c652018-03-16 12:59:42 -07001168 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001169 property_files = NonAbOtaPropertyFiles()
1170 with zipfile.ZipFile(zip_file) as zip_fp:
1171 property_files_string = property_files.Compute(zip_fp)
1172
1173 tokens = self._parse_property_files_string(property_files_string)
1174 self.assertEqual(1, len(tokens))
1175 self._verify_entries(zip_file, tokens, entries)
1176
1177 def test_Finalize(self):
1178 entries = [
1179 'META-INF/com/android/metadata',
1180 ]
Tao Bao3bf8c652018-03-16 12:59:42 -07001181 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001182 property_files = NonAbOtaPropertyFiles()
1183 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001184 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001185 zip_fp, reserve_space=False)
1186 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1187 tokens = self._parse_property_files_string(property_files_string)
1188
1189 self.assertEqual(1, len(tokens))
1190 # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
1191 entries[0] = 'metadata'
1192 self._verify_entries(zip_file, tokens, entries)
1193
1194 def test_Verify(self):
1195 entries = (
1196 'META-INF/com/android/metadata',
1197 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001198 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001199 property_files = NonAbOtaPropertyFiles()
1200 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001201 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001202 zip_fp, reserve_space=False)
1203
1204 property_files.Verify(zip_fp, raw_metadata)
1205
1206
Tao Bao65b94e92018-10-11 21:57:26 -07001207class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -08001208
1209 SIGFILE = 'sigfile.bin'
1210 SIGNED_SIGFILE = 'signed-sigfile.bin'
1211
1212 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001213 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -08001214 self.assertTrue(os.path.exists(self.testdata_dir))
1215
1216 common.OPTIONS.payload_signer = None
1217 common.OPTIONS.payload_signer_args = []
1218 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1219 common.OPTIONS.key_passwords = {
1220 common.OPTIONS.package_key : None,
1221 }
1222
Tao Baofabe0832018-01-17 15:52:28 -08001223 def _assertFilesEqual(self, file1, file2):
1224 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
1225 self.assertEqual(fp1.read(), fp2.read())
1226
1227 def test_init(self):
1228 payload_signer = PayloadSigner()
1229 self.assertEqual('openssl', payload_signer.signer)
xunchang376cc7c2019-04-08 23:04:58 -07001230 self.assertEqual(256, payload_signer.key_size)
Tao Baofabe0832018-01-17 15:52:28 -08001231
1232 def test_init_withPassword(self):
1233 common.OPTIONS.package_key = os.path.join(
1234 self.testdata_dir, 'testkey_with_passwd')
1235 common.OPTIONS.key_passwords = {
1236 common.OPTIONS.package_key : 'foo',
1237 }
1238 payload_signer = PayloadSigner()
1239 self.assertEqual('openssl', payload_signer.signer)
1240
1241 def test_init_withExternalSigner(self):
1242 common.OPTIONS.payload_signer = 'abc'
1243 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
xunchang376cc7c2019-04-08 23:04:58 -07001244 common.OPTIONS.payload_signer_key_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -08001245 payload_signer = PayloadSigner()
1246 self.assertEqual('abc', payload_signer.signer)
1247 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
xunchang376cc7c2019-04-08 23:04:58 -07001248 self.assertEqual(512, payload_signer.key_size)
1249
1250 def test_GetKeySizeInBytes_512Bytes(self):
1251 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -07001252 # pylint: disable=protected-access
xunchang376cc7c2019-04-08 23:04:58 -07001253 key_size = PayloadSigner._GetKeySizeInBytes(signing_key)
1254 self.assertEqual(512, key_size)
Tao Baofabe0832018-01-17 15:52:28 -08001255
1256 def test_Sign(self):
1257 payload_signer = PayloadSigner()
1258 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1259 signed_file = payload_signer.Sign(input_file)
1260
1261 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1262 self._assertFilesEqual(verify_file, signed_file)
1263
1264 def test_Sign_withExternalSigner_openssl(self):
1265 """Uses openssl as the external payload signer."""
1266 common.OPTIONS.payload_signer = 'openssl'
1267 common.OPTIONS.payload_signer_args = [
1268 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
1269 os.path.join(self.testdata_dir, 'testkey.pk8'),
1270 '-pkeyopt', 'digest:sha256']
1271 payload_signer = PayloadSigner()
1272 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1273 signed_file = payload_signer.Sign(input_file)
1274
1275 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1276 self._assertFilesEqual(verify_file, signed_file)
1277
1278 def test_Sign_withExternalSigner_script(self):
1279 """Uses testdata/payload_signer.sh as the external payload signer."""
1280 common.OPTIONS.payload_signer = os.path.join(
1281 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -07001282 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -08001283 common.OPTIONS.payload_signer_args = [
1284 os.path.join(self.testdata_dir, 'testkey.pk8')]
1285 payload_signer = PayloadSigner()
1286 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1287 signed_file = payload_signer.Sign(input_file)
1288
1289 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1290 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001291
1292
Tao Bao65b94e92018-10-11 21:57:26 -07001293class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001294
1295 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001296 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001297 self.assertTrue(os.path.exists(self.testdata_dir))
1298
1299 common.OPTIONS.wipe_user_data = False
1300 common.OPTIONS.payload_signer = None
1301 common.OPTIONS.payload_signer_args = None
1302 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1303 common.OPTIONS.key_passwords = {
1304 common.OPTIONS.package_key : None,
1305 }
1306
Tao Baoc7b403a2018-01-30 18:19:04 -08001307 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001308 def _create_payload_full(secondary=False):
1309 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001310 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001311 payload.Generate(target_file)
1312 return payload
1313
Tao Baof7140c02018-01-30 17:09:24 -08001314 @staticmethod
1315 def _create_payload_incremental():
1316 target_file = construct_target_files()
1317 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001318 payload = Payload()
1319 payload.Generate(target_file, source_file)
1320 return payload
1321
Tao Bao82490d32019-04-09 00:12:30 -07001322 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001323 def test_Generate_full(self):
1324 payload = self._create_payload_full()
1325 self.assertTrue(os.path.exists(payload.payload_file))
1326
Tao Bao82490d32019-04-09 00:12:30 -07001327 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001328 def test_Generate_incremental(self):
1329 payload = self._create_payload_incremental()
1330 self.assertTrue(os.path.exists(payload.payload_file))
1331
Tao Bao82490d32019-04-09 00:12:30 -07001332 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001333 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001334 target_file = construct_target_files()
1335 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001336 payload = Payload()
1337 # This should work the same as calling payload.Generate(target_file,
1338 # source_file).
1339 payload.Generate(
1340 target_file, additional_args=["--source_image", source_file])
1341 self.assertTrue(os.path.exists(payload.payload_file))
1342
Tao Bao82490d32019-04-09 00:12:30 -07001343 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001344 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001345 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001346 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1347 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001348 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001349
Tao Bao82490d32019-04-09 00:12:30 -07001350 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001351 def test_Sign_full(self):
1352 payload = self._create_payload_full()
1353 payload.Sign(PayloadSigner())
1354
1355 output_file = common.MakeTempFile(suffix='.zip')
1356 with zipfile.ZipFile(output_file, 'w') as output_zip:
1357 payload.WriteToZip(output_zip)
1358
1359 import check_ota_package_signature
1360 check_ota_package_signature.VerifyAbOtaPayload(
1361 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1362 output_file)
1363
Tao Bao82490d32019-04-09 00:12:30 -07001364 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001365 def test_Sign_incremental(self):
1366 payload = self._create_payload_incremental()
1367 payload.Sign(PayloadSigner())
1368
1369 output_file = common.MakeTempFile(suffix='.zip')
1370 with zipfile.ZipFile(output_file, 'w') as output_zip:
1371 payload.WriteToZip(output_zip)
1372
1373 import check_ota_package_signature
1374 check_ota_package_signature.VerifyAbOtaPayload(
1375 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1376 output_file)
1377
Tao Bao82490d32019-04-09 00:12:30 -07001378 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001379 def test_Sign_withDataWipe(self):
1380 common.OPTIONS.wipe_user_data = True
1381 payload = self._create_payload_full()
1382 payload.Sign(PayloadSigner())
1383
1384 with open(payload.payload_properties) as properties_fp:
1385 self.assertIn("POWERWASH=1", properties_fp.read())
1386
Tao Bao82490d32019-04-09 00:12:30 -07001387 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001388 def test_Sign_secondary(self):
1389 payload = self._create_payload_full(secondary=True)
1390 payload.Sign(PayloadSigner())
1391
1392 with open(payload.payload_properties) as properties_fp:
1393 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1394
Tao Bao82490d32019-04-09 00:12:30 -07001395 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001396 def test_Sign_badSigner(self):
1397 """Tests that signing failure can be captured."""
1398 payload = self._create_payload_full()
1399 payload_signer = PayloadSigner()
1400 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001401 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001402
Tao Bao82490d32019-04-09 00:12:30 -07001403 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001404 def test_WriteToZip(self):
1405 payload = self._create_payload_full()
1406 payload.Sign(PayloadSigner())
1407
1408 output_file = common.MakeTempFile(suffix='.zip')
1409 with zipfile.ZipFile(output_file, 'w') as output_zip:
1410 payload.WriteToZip(output_zip)
1411
1412 with zipfile.ZipFile(output_file) as verify_zip:
1413 # First make sure we have the essential entries.
1414 namelist = verify_zip.namelist()
1415 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1416 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1417
1418 # Then assert these entries are stored.
1419 for entry_info in verify_zip.infolist():
1420 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1421 Payload.PAYLOAD_PROPERTIES_TXT):
1422 continue
1423 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1424
Tao Bao82490d32019-04-09 00:12:30 -07001425 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001426 def test_WriteToZip_unsignedPayload(self):
1427 """Unsigned payloads should not be allowed to be written to zip."""
1428 payload = self._create_payload_full()
1429
1430 output_file = common.MakeTempFile(suffix='.zip')
1431 with zipfile.ZipFile(output_file, 'w') as output_zip:
1432 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1433
1434 # Also test with incremental payload.
1435 payload = self._create_payload_incremental()
1436
1437 output_file = common.MakeTempFile(suffix='.zip')
1438 with zipfile.ZipFile(output_file, 'w') as output_zip:
1439 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001440
Tao Bao82490d32019-04-09 00:12:30 -07001441 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001442 def test_WriteToZip_secondary(self):
1443 payload = self._create_payload_full(secondary=True)
1444 payload.Sign(PayloadSigner())
1445
1446 output_file = common.MakeTempFile(suffix='.zip')
1447 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001448 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001449
1450 with zipfile.ZipFile(output_file) as verify_zip:
1451 # First make sure we have the essential entries.
1452 namelist = verify_zip.namelist()
1453 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1454 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1455
1456 # Then assert these entries are stored.
1457 for entry_info in verify_zip.infolist():
1458 if entry_info.filename not in (
1459 Payload.SECONDARY_PAYLOAD_BIN,
1460 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1461 continue
1462 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)