blob: ee28571878b04003e79a5e27916919f863f77b84 [file] [log] [blame]
Dan Albert8e0178d2015-01-27 15:53:15 -08001#
2# Copyright (C) 2015 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#
Tao Baofc7e0e02018-02-13 13:54:02 -080016
Tao Baoa57ab9f2018-08-24 12:08:38 -070017import copy
Dan Albert8e0178d2015-01-27 15:53:15 -080018import os
Tao Bao17e4e612018-02-16 17:12:54 -080019import subprocess
Dan Albert8e0178d2015-01-27 15:53:15 -080020import tempfile
21import time
Tianjie20dd8f22020-04-19 15:51:16 -070022import unittest
Dan Albert8e0178d2015-01-27 15:53:15 -080023import zipfile
Tao Bao31b08072017-11-08 15:50:59 -080024from hashlib import sha1
25
Dan Albert8e0178d2015-01-27 15:53:15 -080026import common
Tao Bao04e1f012018-02-04 12:13:35 -080027import test_utils
Tianjie Xu9c384d22017-06-20 17:00:55 -070028import validate_target_files
Tianjie Xu41976c72019-07-03 13:57:01 -070029from images import EmptyImage, DataImage
Tao Baofc7e0e02018-02-13 13:54:02 -080030from rangelib import RangeSet
Dan Albert8e0178d2015-01-27 15:53:15 -080031
Tao Bao04e1f012018-02-04 12:13:35 -080032
Tao Bao31b08072017-11-08 15:50:59 -080033KiB = 1024
34MiB = 1024 * KiB
35GiB = 1024 * MiB
Dan Albert8e0178d2015-01-27 15:53:15 -080036
Tao Bao1c830bf2017-12-25 10:43:47 -080037
Tao Baof3282b42015-04-01 11:21:55 -070038def get_2gb_string():
Tao Bao31b08072017-11-08 15:50:59 -080039 size = int(2 * GiB + 1)
40 block_size = 4 * KiB
41 step_size = 4 * MiB
42 # Generate a long string with holes, e.g. 'xyz\x00abc\x00...'.
43 for _ in range(0, size, step_size):
44 yield os.urandom(block_size)
Tao Baoc1a1ec32019-06-18 16:29:37 -070045 yield b'\0' * (step_size - block_size)
Tao Baof3282b42015-04-01 11:21:55 -070046
Dan Albert8e0178d2015-01-27 15:53:15 -080047
Tao Bao1c320f82019-10-04 23:25:12 -070048class BuildInfoTest(test_utils.ReleaseToolsTestCase):
49
50 TEST_INFO_DICT = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +000051 'build.prop': common.PartitionBuildProps.FromDictionary(
52 'system', {
53 'ro.product.device': 'product-device',
54 'ro.product.name': 'product-name',
55 'ro.build.fingerprint': 'build-fingerprint',
56 'ro.build.foo': 'build-foo'}
57 ),
58 'system.build.prop': common.PartitionBuildProps.FromDictionary(
59 'system', {
60 'ro.product.system.brand': 'product-brand',
61 'ro.product.system.name': 'product-name',
62 'ro.product.system.device': 'product-device',
63 'ro.system.build.version.release': 'version-release',
64 'ro.system.build.id': 'build-id',
65 'ro.system.build.version.incremental': 'version-incremental',
66 'ro.system.build.type': 'build-type',
67 'ro.system.build.tags': 'build-tags',
68 'ro.system.build.foo': 'build-foo'}
69 ),
70 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
71 'vendor', {
72 'ro.product.vendor.brand': 'vendor-product-brand',
73 'ro.product.vendor.name': 'vendor-product-name',
74 'ro.product.vendor.device': 'vendor-product-device',
75 'ro.vendor.build.version.release': 'vendor-version-release',
76 'ro.vendor.build.id': 'vendor-build-id',
77 'ro.vendor.build.version.incremental':
78 'vendor-version-incremental',
79 'ro.vendor.build.type': 'vendor-build-type',
80 'ro.vendor.build.tags': 'vendor-build-tags'}
81 ),
82 'property1': 'value1',
83 'property2': 4096,
Tao Bao1c320f82019-10-04 23:25:12 -070084 }
85
86 TEST_INFO_DICT_USES_OEM_PROPS = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +000087 'build.prop': common.PartitionBuildProps.FromDictionary(
88 'system', {
89 'ro.product.name': 'product-name',
90 'ro.build.thumbprint': 'build-thumbprint',
91 'ro.build.bar': 'build-bar'}
92 ),
93 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
94 'vendor', {
95 'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
96 ),
97 'property1': 'value1',
98 'property2': 4096,
99 'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
Tao Bao1c320f82019-10-04 23:25:12 -0700100 }
101
102 TEST_OEM_DICTS = [
103 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000104 'ro.product.brand': 'brand1',
105 'ro.product.device': 'device1',
Tao Bao1c320f82019-10-04 23:25:12 -0700106 },
107 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000108 'ro.product.brand': 'brand2',
109 'ro.product.device': 'device2',
Tao Bao1c320f82019-10-04 23:25:12 -0700110 },
111 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000112 'ro.product.brand': 'brand3',
113 'ro.product.device': 'device3',
Tao Bao1c320f82019-10-04 23:25:12 -0700114 },
115 ]
116
Steven Laver8e2086e2020-04-27 16:26:31 -0700117 TEST_INFO_DICT_PROPERTY_SOURCE_ORDER = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000118 'build.prop': common.PartitionBuildProps.FromDictionary(
119 'system', {
120 'ro.build.fingerprint': 'build-fingerprint',
121 'ro.product.property_source_order':
122 'product,odm,vendor,system_ext,system'}
123 ),
124 'system.build.prop': common.PartitionBuildProps.FromDictionary(
125 'system', {
126 'ro.product.system.device': 'system-product-device'}
127 ),
128 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
129 'vendor', {
130 'ro.product.vendor.device': 'vendor-product-device'}
131 ),
Steven Laver8e2086e2020-04-27 16:26:31 -0700132 }
133
134 TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_10 = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000135 'build.prop': common.PartitionBuildProps.FromDictionary(
136 'system', {
137 'ro.build.fingerprint': 'build-fingerprint',
138 'ro.product.property_source_order':
139 'product,product_services,odm,vendor,system',
140 'ro.build.version.release': '10',
141 'ro.build.version.codename': 'REL'}
142 ),
143 'system.build.prop': common.PartitionBuildProps.FromDictionary(
144 'system', {
145 'ro.product.system.device': 'system-product-device'}
146 ),
147 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
148 'vendor', {
149 'ro.product.vendor.device': 'vendor-product-device'}
150 ),
Steven Laver8e2086e2020-04-27 16:26:31 -0700151 }
152
153 TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_9 = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000154 'build.prop': common.PartitionBuildProps.FromDictionary(
155 'system', {
156 'ro.product.device': 'product-device',
157 'ro.build.fingerprint': 'build-fingerprint',
158 'ro.build.version.release': '9',
159 'ro.build.version.codename': 'REL'}
160 ),
161 'system.build.prop': common.PartitionBuildProps.FromDictionary(
162 'system', {
163 'ro.product.system.device': 'system-product-device'}
164 ),
165 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
166 'vendor', {
167 'ro.product.vendor.device': 'vendor-product-device'}
168 ),
Steven Laver8e2086e2020-04-27 16:26:31 -0700169 }
170
Tao Bao1c320f82019-10-04 23:25:12 -0700171 def test_init(self):
172 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
173 self.assertEqual('product-device', target_info.device)
174 self.assertEqual('build-fingerprint', target_info.fingerprint)
175 self.assertFalse(target_info.is_ab)
176 self.assertIsNone(target_info.oem_props)
177
178 def test_init_with_oem_props(self):
179 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
180 self.TEST_OEM_DICTS)
181 self.assertEqual('device1', target_info.device)
182 self.assertEqual('brand1/product-name/device1:build-thumbprint',
183 target_info.fingerprint)
184
185 # Swap the order in oem_dicts, which would lead to different BuildInfo.
186 oem_dicts = copy.copy(self.TEST_OEM_DICTS)
187 oem_dicts[0], oem_dicts[2] = oem_dicts[2], oem_dicts[0]
188 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
189 oem_dicts)
190 self.assertEqual('device3', target_info.device)
191 self.assertEqual('brand3/product-name/device3:build-thumbprint',
192 target_info.fingerprint)
193
Tao Bao1c320f82019-10-04 23:25:12 -0700194 def test_init_badFingerprint(self):
195 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000196 info_dict['build.prop'].build_props[
197 'ro.build.fingerprint'] = 'bad fingerprint'
Tao Bao1c320f82019-10-04 23:25:12 -0700198 self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
199
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000200 info_dict['build.prop'].build_props[
201 'ro.build.fingerprint'] = 'bad\x80fingerprint'
Tao Bao1c320f82019-10-04 23:25:12 -0700202 self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
203
204 def test___getitem__(self):
205 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
206 self.assertEqual('value1', target_info['property1'])
207 self.assertEqual(4096, target_info['property2'])
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000208 self.assertEqual('build-foo',
209 target_info['build.prop'].GetProp('ro.build.foo'))
Tao Bao1c320f82019-10-04 23:25:12 -0700210
211 def test___getitem__with_oem_props(self):
212 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
213 self.TEST_OEM_DICTS)
214 self.assertEqual('value1', target_info['property1'])
215 self.assertEqual(4096, target_info['property2'])
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000216 self.assertIsNone(target_info['build.prop'].GetProp('ro.build.foo'))
Tao Bao1c320f82019-10-04 23:25:12 -0700217
218 def test___setitem__(self):
219 target_info = common.BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
220 self.assertEqual('value1', target_info['property1'])
221 target_info['property1'] = 'value2'
222 self.assertEqual('value2', target_info['property1'])
223
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000224 self.assertEqual('build-foo',
225 target_info['build.prop'].GetProp('ro.build.foo'))
226 target_info['build.prop'].build_props['ro.build.foo'] = 'build-bar'
227 self.assertEqual('build-bar',
228 target_info['build.prop'].GetProp('ro.build.foo'))
Tao Bao1c320f82019-10-04 23:25:12 -0700229
230 def test_get(self):
231 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
232 self.assertEqual('value1', target_info.get('property1'))
233 self.assertEqual(4096, target_info.get('property2'))
234 self.assertEqual(4096, target_info.get('property2', 1024))
235 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000236 self.assertEqual('build-foo',
237 target_info.get('build.prop').GetProp('ro.build.foo'))
Tao Bao1c320f82019-10-04 23:25:12 -0700238
239 def test_get_with_oem_props(self):
240 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
241 self.TEST_OEM_DICTS)
242 self.assertEqual('value1', target_info.get('property1'))
243 self.assertEqual(4096, target_info.get('property2'))
244 self.assertEqual(4096, target_info.get('property2', 1024))
245 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000246 self.assertIsNone(target_info.get('build.prop').GetProp('ro.build.foo'))
Tao Bao1c320f82019-10-04 23:25:12 -0700247
248 def test_items(self):
249 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
250 items = target_info.items()
251 self.assertIn(('property1', 'value1'), items)
252 self.assertIn(('property2', 4096), items)
253
254 def test_GetBuildProp(self):
255 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
256 self.assertEqual('build-foo', target_info.GetBuildProp('ro.build.foo'))
257 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
258 'ro.build.nonexistent')
259
260 def test_GetBuildProp_with_oem_props(self):
261 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
262 self.TEST_OEM_DICTS)
263 self.assertEqual('build-bar', target_info.GetBuildProp('ro.build.bar'))
264 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
265 'ro.build.nonexistent')
266
Daniel Normand5fe8622020-01-08 17:01:11 -0800267 def test_GetPartitionFingerprint(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700268 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
Daniel Normand5fe8622020-01-08 17:01:11 -0800269 self.assertEqual(
270 target_info.GetPartitionFingerprint('vendor'),
271 'vendor-product-brand/vendor-product-name/vendor-product-device'
272 ':vendor-version-release/vendor-build-id/vendor-version-incremental'
273 ':vendor-build-type/vendor-build-tags')
Tao Bao1c320f82019-10-04 23:25:12 -0700274
Daniel Normand5fe8622020-01-08 17:01:11 -0800275 def test_GetPartitionFingerprint_system_other_uses_system(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700276 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
Daniel Normand5fe8622020-01-08 17:01:11 -0800277 self.assertEqual(
278 target_info.GetPartitionFingerprint('system_other'),
279 target_info.GetPartitionFingerprint('system'))
Tao Bao1c320f82019-10-04 23:25:12 -0700280
Daniel Normand5fe8622020-01-08 17:01:11 -0800281 def test_GetPartitionFingerprint_uses_fingerprint_prop_if_available(self):
282 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000283 info_dict['vendor.build.prop'].build_props[
284 'ro.vendor.build.fingerprint'] = 'vendor:fingerprint'
Daniel Normand5fe8622020-01-08 17:01:11 -0800285 target_info = common.BuildInfo(info_dict, None)
286 self.assertEqual(
287 target_info.GetPartitionFingerprint('vendor'),
288 'vendor:fingerprint')
Tao Bao1c320f82019-10-04 23:25:12 -0700289
290 def test_WriteMountOemScript(self):
291 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
292 self.TEST_OEM_DICTS)
293 script_writer = test_utils.MockScriptWriter()
294 target_info.WriteMountOemScript(script_writer)
295 self.assertEqual([('Mount', '/oem', None)], script_writer.lines)
296
297 def test_WriteDeviceAssertions(self):
298 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
299 script_writer = test_utils.MockScriptWriter()
300 target_info.WriteDeviceAssertions(script_writer, False)
301 self.assertEqual([('AssertDevice', 'product-device')], script_writer.lines)
302
303 def test_WriteDeviceAssertions_with_oem_props(self):
304 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
305 self.TEST_OEM_DICTS)
306 script_writer = test_utils.MockScriptWriter()
307 target_info.WriteDeviceAssertions(script_writer, False)
308 self.assertEqual(
309 [
310 ('AssertOemProperty', 'ro.product.device',
311 ['device1', 'device2', 'device3'], False),
312 ('AssertOemProperty', 'ro.product.brand',
313 ['brand1', 'brand2', 'brand3'], False),
314 ],
315 script_writer.lines)
316
Steven Laver8e2086e2020-04-27 16:26:31 -0700317 def test_ResolveRoProductProperty_FromVendor(self):
318 info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
319 info = common.BuildInfo(info_dict, None)
320 self.assertEqual('vendor-product-device',
321 info.GetBuildProp('ro.product.device'))
322
323 def test_ResolveRoProductProperty_FromSystem(self):
324 info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000325 del info_dict['vendor.build.prop'].build_props['ro.product.vendor.device']
Steven Laver8e2086e2020-04-27 16:26:31 -0700326 info = common.BuildInfo(info_dict, None)
327 self.assertEqual('system-product-device',
328 info.GetBuildProp('ro.product.device'))
329
330 def test_ResolveRoProductProperty_InvalidPropertySearchOrder(self):
331 info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000332 info_dict['build.prop'].build_props[
333 'ro.product.property_source_order'] = 'bad-source'
Steven Laver8e2086e2020-04-27 16:26:31 -0700334 with self.assertRaisesRegexp(common.ExternalError,
335 'Invalid ro.product.property_source_order'):
336 info = common.BuildInfo(info_dict, None)
337 info.GetBuildProp('ro.product.device')
338
339 def test_ResolveRoProductProperty_Android10PropertySearchOrder(self):
340 info_dict = copy.deepcopy(
341 self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_10)
342 info = common.BuildInfo(info_dict, None)
343 self.assertEqual('vendor-product-device',
344 info.GetBuildProp('ro.product.device'))
345
346 def test_ResolveRoProductProperty_Android9PropertySearchOrder(self):
347 info_dict = copy.deepcopy(
348 self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_9)
349 info = common.BuildInfo(info_dict, None)
350 self.assertEqual('product-device',
351 info.GetBuildProp('ro.product.device'))
352
Tao Bao1c320f82019-10-04 23:25:12 -0700353
Tao Bao65b94e92018-10-11 21:57:26 -0700354class CommonZipTest(test_utils.ReleaseToolsTestCase):
355
Tao Bao31b08072017-11-08 15:50:59 -0800356 def _verify(self, zip_file, zip_file_name, arcname, expected_hash,
Tao Baof3282b42015-04-01 11:21:55 -0700357 test_file_name=None, expected_stat=None, expected_mode=0o644,
358 expected_compress_type=zipfile.ZIP_STORED):
359 # Verify the stat if present.
360 if test_file_name is not None:
361 new_stat = os.stat(test_file_name)
362 self.assertEqual(int(expected_stat.st_mode), int(new_stat.st_mode))
363 self.assertEqual(int(expected_stat.st_mtime), int(new_stat.st_mtime))
364
365 # Reopen the zip file to verify.
Kelvin Zhang928c2342020-09-22 16:15:57 -0400366 zip_file = zipfile.ZipFile(zip_file_name, "r", allowZip64=True)
Tao Baof3282b42015-04-01 11:21:55 -0700367
368 # Verify the timestamp.
369 info = zip_file.getinfo(arcname)
370 self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0))
371
372 # Verify the file mode.
373 mode = (info.external_attr >> 16) & 0o777
374 self.assertEqual(mode, expected_mode)
375
376 # Verify the compress type.
377 self.assertEqual(info.compress_type, expected_compress_type)
378
379 # Verify the zip contents.
Tao Bao31b08072017-11-08 15:50:59 -0800380 entry = zip_file.open(arcname)
381 sha1_hash = sha1()
Tao Baoc1a1ec32019-06-18 16:29:37 -0700382 for chunk in iter(lambda: entry.read(4 * MiB), b''):
Tao Bao31b08072017-11-08 15:50:59 -0800383 sha1_hash.update(chunk)
384 self.assertEqual(expected_hash, sha1_hash.hexdigest())
Tao Baof3282b42015-04-01 11:21:55 -0700385 self.assertIsNone(zip_file.testzip())
386
Dan Albert8e0178d2015-01-27 15:53:15 -0800387 def _test_ZipWrite(self, contents, extra_zipwrite_args=None):
388 extra_zipwrite_args = dict(extra_zipwrite_args or {})
389
390 test_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -0800391 test_file_name = test_file.name
Tao Baof3282b42015-04-01 11:21:55 -0700392
393 zip_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -0800394 zip_file_name = zip_file.name
395
396 # File names within an archive strip the leading slash.
397 arcname = extra_zipwrite_args.get("arcname", test_file_name)
398 if arcname[0] == "/":
399 arcname = arcname[1:]
400
401 zip_file.close()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400402 zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
Dan Albert8e0178d2015-01-27 15:53:15 -0800403
404 try:
Tao Bao31b08072017-11-08 15:50:59 -0800405 sha1_hash = sha1()
406 for data in contents:
Tao Baoc1a1ec32019-06-18 16:29:37 -0700407 sha1_hash.update(bytes(data))
408 test_file.write(bytes(data))
Dan Albert8e0178d2015-01-27 15:53:15 -0800409 test_file.close()
410
Tao Baof3282b42015-04-01 11:21:55 -0700411 expected_stat = os.stat(test_file_name)
Dan Albert8e0178d2015-01-27 15:53:15 -0800412 expected_mode = extra_zipwrite_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700413 expected_compress_type = extra_zipwrite_args.get("compress_type",
414 zipfile.ZIP_STORED)
Dan Albert8e0178d2015-01-27 15:53:15 -0800415 time.sleep(5) # Make sure the atime/mtime will change measurably.
416
417 common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
Tao Baof3282b42015-04-01 11:21:55 -0700418 common.ZipClose(zip_file)
Dan Albert8e0178d2015-01-27 15:53:15 -0800419
Tao Bao31b08072017-11-08 15:50:59 -0800420 self._verify(zip_file, zip_file_name, arcname, sha1_hash.hexdigest(),
421 test_file_name, expected_stat, expected_mode,
422 expected_compress_type)
Dan Albert8e0178d2015-01-27 15:53:15 -0800423 finally:
424 os.remove(test_file_name)
425 os.remove(zip_file_name)
426
Tao Baof3282b42015-04-01 11:21:55 -0700427 def _test_ZipWriteStr(self, zinfo_or_arcname, contents, extra_args=None):
428 extra_args = dict(extra_args or {})
429
430 zip_file = tempfile.NamedTemporaryFile(delete=False)
431 zip_file_name = zip_file.name
432 zip_file.close()
433
Kelvin Zhang928c2342020-09-22 16:15:57 -0400434 zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
Tao Baof3282b42015-04-01 11:21:55 -0700435
436 try:
437 expected_compress_type = extra_args.get("compress_type",
438 zipfile.ZIP_STORED)
439 time.sleep(5) # Make sure the atime/mtime will change measurably.
440
441 if not isinstance(zinfo_or_arcname, zipfile.ZipInfo):
Tao Bao58c1b962015-05-20 09:32:18 -0700442 arcname = zinfo_or_arcname
443 expected_mode = extra_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700444 else:
Tao Bao58c1b962015-05-20 09:32:18 -0700445 arcname = zinfo_or_arcname.filename
Tao Baoc1a1ec32019-06-18 16:29:37 -0700446 if zinfo_or_arcname.external_attr:
447 zinfo_perms = zinfo_or_arcname.external_attr >> 16
448 else:
449 zinfo_perms = 0o600
450 expected_mode = extra_args.get("perms", zinfo_perms)
Tao Baof3282b42015-04-01 11:21:55 -0700451
Tao Bao58c1b962015-05-20 09:32:18 -0700452 common.ZipWriteStr(zip_file, zinfo_or_arcname, contents, **extra_args)
Tao Baof3282b42015-04-01 11:21:55 -0700453 common.ZipClose(zip_file)
454
Tao Bao31b08072017-11-08 15:50:59 -0800455 self._verify(zip_file, zip_file_name, arcname, sha1(contents).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700456 expected_mode=expected_mode,
Tao Baof3282b42015-04-01 11:21:55 -0700457 expected_compress_type=expected_compress_type)
458 finally:
459 os.remove(zip_file_name)
460
461 def _test_ZipWriteStr_large_file(self, large, small, extra_args=None):
462 extra_args = dict(extra_args or {})
463
464 zip_file = tempfile.NamedTemporaryFile(delete=False)
465 zip_file_name = zip_file.name
466
467 test_file = tempfile.NamedTemporaryFile(delete=False)
468 test_file_name = test_file.name
469
470 arcname_large = test_file_name
471 arcname_small = "bar"
472
473 # File names within an archive strip the leading slash.
474 if arcname_large[0] == "/":
475 arcname_large = arcname_large[1:]
476
477 zip_file.close()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400478 zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
Tao Baof3282b42015-04-01 11:21:55 -0700479
480 try:
Tao Bao31b08072017-11-08 15:50:59 -0800481 sha1_hash = sha1()
482 for data in large:
483 sha1_hash.update(data)
484 test_file.write(data)
Tao Baof3282b42015-04-01 11:21:55 -0700485 test_file.close()
486
487 expected_stat = os.stat(test_file_name)
488 expected_mode = 0o644
489 expected_compress_type = extra_args.get("compress_type",
490 zipfile.ZIP_STORED)
491 time.sleep(5) # Make sure the atime/mtime will change measurably.
492
493 common.ZipWrite(zip_file, test_file_name, **extra_args)
494 common.ZipWriteStr(zip_file, arcname_small, small, **extra_args)
495 common.ZipClose(zip_file)
496
497 # Verify the contents written by ZipWrite().
Tao Bao31b08072017-11-08 15:50:59 -0800498 self._verify(zip_file, zip_file_name, arcname_large,
499 sha1_hash.hexdigest(), test_file_name, expected_stat,
500 expected_mode, expected_compress_type)
Tao Baof3282b42015-04-01 11:21:55 -0700501
502 # Verify the contents written by ZipWriteStr().
Tao Bao31b08072017-11-08 15:50:59 -0800503 self._verify(zip_file, zip_file_name, arcname_small,
504 sha1(small).hexdigest(),
Tao Baof3282b42015-04-01 11:21:55 -0700505 expected_compress_type=expected_compress_type)
506 finally:
507 os.remove(zip_file_name)
508 os.remove(test_file_name)
509
510 def _test_reset_ZIP64_LIMIT(self, func, *args):
511 default_limit = (1 << 31) - 1
512 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
513 func(*args)
514 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
515
Dan Albert8e0178d2015-01-27 15:53:15 -0800516 def test_ZipWrite(self):
517 file_contents = os.urandom(1024)
518 self._test_ZipWrite(file_contents)
519
520 def test_ZipWrite_with_opts(self):
521 file_contents = os.urandom(1024)
522 self._test_ZipWrite(file_contents, {
523 "arcname": "foobar",
524 "perms": 0o777,
525 "compress_type": zipfile.ZIP_DEFLATED,
526 })
Tao Baof3282b42015-04-01 11:21:55 -0700527 self._test_ZipWrite(file_contents, {
528 "arcname": "foobar",
529 "perms": 0o700,
530 "compress_type": zipfile.ZIP_STORED,
531 })
Dan Albert8e0178d2015-01-27 15:53:15 -0800532
533 def test_ZipWrite_large_file(self):
Tao Baof3282b42015-04-01 11:21:55 -0700534 file_contents = get_2gb_string()
Dan Albert8e0178d2015-01-27 15:53:15 -0800535 self._test_ZipWrite(file_contents, {
536 "compress_type": zipfile.ZIP_DEFLATED,
537 })
538
539 def test_ZipWrite_resets_ZIP64_LIMIT(self):
Tao Baof3282b42015-04-01 11:21:55 -0700540 self._test_reset_ZIP64_LIMIT(self._test_ZipWrite, "")
541
542 def test_ZipWriteStr(self):
543 random_string = os.urandom(1024)
544 # Passing arcname
545 self._test_ZipWriteStr("foo", random_string)
546
547 # Passing zinfo
548 zinfo = zipfile.ZipInfo(filename="foo")
549 self._test_ZipWriteStr(zinfo, random_string)
550
551 # Timestamp in the zinfo should be overwritten.
552 zinfo.date_time = (2015, 3, 1, 15, 30, 0)
553 self._test_ZipWriteStr(zinfo, random_string)
554
555 def test_ZipWriteStr_with_opts(self):
556 random_string = os.urandom(1024)
557 # Passing arcname
558 self._test_ZipWriteStr("foo", random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700559 "perms": 0o700,
Tao Baof3282b42015-04-01 11:21:55 -0700560 "compress_type": zipfile.ZIP_DEFLATED,
561 })
Tao Bao58c1b962015-05-20 09:32:18 -0700562 self._test_ZipWriteStr("bar", random_string, {
Tao Baof3282b42015-04-01 11:21:55 -0700563 "compress_type": zipfile.ZIP_STORED,
564 })
565
566 # Passing zinfo
567 zinfo = zipfile.ZipInfo(filename="foo")
568 self._test_ZipWriteStr(zinfo, random_string, {
569 "compress_type": zipfile.ZIP_DEFLATED,
570 })
571 self._test_ZipWriteStr(zinfo, random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700572 "perms": 0o600,
Tao Baof3282b42015-04-01 11:21:55 -0700573 "compress_type": zipfile.ZIP_STORED,
574 })
Tao Baoc1a1ec32019-06-18 16:29:37 -0700575 self._test_ZipWriteStr(zinfo, random_string, {
576 "perms": 0o000,
577 "compress_type": zipfile.ZIP_STORED,
578 })
Tao Baof3282b42015-04-01 11:21:55 -0700579
580 def test_ZipWriteStr_large_file(self):
581 # zipfile.writestr() doesn't work when the str size is over 2GiB even with
582 # the workaround. We will only test the case of writing a string into a
583 # large archive.
584 long_string = get_2gb_string()
585 short_string = os.urandom(1024)
586 self._test_ZipWriteStr_large_file(long_string, short_string, {
587 "compress_type": zipfile.ZIP_DEFLATED,
588 })
589
590 def test_ZipWriteStr_resets_ZIP64_LIMIT(self):
Tao Baoc1a1ec32019-06-18 16:29:37 -0700591 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, 'foo', b'')
Tao Baof3282b42015-04-01 11:21:55 -0700592 zinfo = zipfile.ZipInfo(filename="foo")
Tao Baoc1a1ec32019-06-18 16:29:37 -0700593 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, zinfo, b'')
Tao Bao58c1b962015-05-20 09:32:18 -0700594
595 def test_bug21309935(self):
596 zip_file = tempfile.NamedTemporaryFile(delete=False)
597 zip_file_name = zip_file.name
598 zip_file.close()
599
600 try:
601 random_string = os.urandom(1024)
Kelvin Zhang928c2342020-09-22 16:15:57 -0400602 zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
Tao Bao58c1b962015-05-20 09:32:18 -0700603 # Default perms should be 0o644 when passing the filename.
604 common.ZipWriteStr(zip_file, "foo", random_string)
605 # Honor the specified perms.
606 common.ZipWriteStr(zip_file, "bar", random_string, perms=0o755)
607 # The perms in zinfo should be untouched.
608 zinfo = zipfile.ZipInfo(filename="baz")
609 zinfo.external_attr = 0o740 << 16
610 common.ZipWriteStr(zip_file, zinfo, random_string)
611 # Explicitly specified perms has the priority.
612 zinfo = zipfile.ZipInfo(filename="qux")
613 zinfo.external_attr = 0o700 << 16
614 common.ZipWriteStr(zip_file, zinfo, random_string, perms=0o400)
615 common.ZipClose(zip_file)
616
Tao Bao31b08072017-11-08 15:50:59 -0800617 self._verify(zip_file, zip_file_name, "foo",
618 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700619 expected_mode=0o644)
Tao Bao31b08072017-11-08 15:50:59 -0800620 self._verify(zip_file, zip_file_name, "bar",
621 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700622 expected_mode=0o755)
Tao Bao31b08072017-11-08 15:50:59 -0800623 self._verify(zip_file, zip_file_name, "baz",
624 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700625 expected_mode=0o740)
Tao Bao31b08072017-11-08 15:50:59 -0800626 self._verify(zip_file, zip_file_name, "qux",
627 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700628 expected_mode=0o400)
629 finally:
630 os.remove(zip_file_name)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700631
Tao Bao82490d32019-04-09 00:12:30 -0700632 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao89d7ab22017-12-14 17:05:33 -0800633 def test_ZipDelete(self):
634 zip_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
635 output_zip = zipfile.ZipFile(zip_file.name, 'w',
636 compression=zipfile.ZIP_DEFLATED)
637 with tempfile.NamedTemporaryFile() as entry_file:
638 entry_file.write(os.urandom(1024))
639 common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
640 common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
641 common.ZipWrite(output_zip, entry_file.name, arcname='Test3')
642 common.ZipClose(output_zip)
643 zip_file.close()
644
645 try:
646 common.ZipDelete(zip_file.name, 'Test2')
Kelvin Zhang928c2342020-09-22 16:15:57 -0400647 with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
Tao Bao89d7ab22017-12-14 17:05:33 -0800648 entries = check_zip.namelist()
649 self.assertTrue('Test1' in entries)
650 self.assertFalse('Test2' in entries)
651 self.assertTrue('Test3' in entries)
652
Tao Bao986ee862018-10-04 15:46:16 -0700653 self.assertRaises(
654 common.ExternalError, common.ZipDelete, zip_file.name, 'Test2')
Kelvin Zhang928c2342020-09-22 16:15:57 -0400655 with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
Tao Bao89d7ab22017-12-14 17:05:33 -0800656 entries = check_zip.namelist()
657 self.assertTrue('Test1' in entries)
658 self.assertFalse('Test2' in entries)
659 self.assertTrue('Test3' in entries)
660
661 common.ZipDelete(zip_file.name, ['Test3'])
Kelvin Zhang928c2342020-09-22 16:15:57 -0400662 with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
Tao Bao89d7ab22017-12-14 17:05:33 -0800663 entries = check_zip.namelist()
664 self.assertTrue('Test1' in entries)
665 self.assertFalse('Test2' in entries)
666 self.assertFalse('Test3' in entries)
667
668 common.ZipDelete(zip_file.name, ['Test1', 'Test2'])
Kelvin Zhang928c2342020-09-22 16:15:57 -0400669 with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
Tao Bao89d7ab22017-12-14 17:05:33 -0800670 entries = check_zip.namelist()
671 self.assertFalse('Test1' in entries)
672 self.assertFalse('Test2' in entries)
673 self.assertFalse('Test3' in entries)
674 finally:
675 os.remove(zip_file.name)
676
Tao Bao0ff15de2019-03-20 11:26:06 -0700677 @staticmethod
678 def _test_UnzipTemp_createZipFile():
679 zip_file = common.MakeTempFile(suffix='.zip')
680 output_zip = zipfile.ZipFile(
681 zip_file, 'w', compression=zipfile.ZIP_DEFLATED)
682 contents = os.urandom(1024)
683 with tempfile.NamedTemporaryFile() as entry_file:
684 entry_file.write(contents)
685 common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
686 common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
687 common.ZipWrite(output_zip, entry_file.name, arcname='Foo3')
688 common.ZipWrite(output_zip, entry_file.name, arcname='Bar4')
689 common.ZipWrite(output_zip, entry_file.name, arcname='Dir5/Baz5')
690 common.ZipClose(output_zip)
691 common.ZipClose(output_zip)
692 return zip_file
693
Tao Bao82490d32019-04-09 00:12:30 -0700694 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700695 def test_UnzipTemp(self):
696 zip_file = self._test_UnzipTemp_createZipFile()
697 unzipped_dir = common.UnzipTemp(zip_file)
698 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
699 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
700 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
701 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
702 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
703
Tao Bao82490d32019-04-09 00:12:30 -0700704 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700705 def test_UnzipTemp_withPatterns(self):
706 zip_file = self._test_UnzipTemp_createZipFile()
707
708 unzipped_dir = common.UnzipTemp(zip_file, ['Test1'])
709 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
710 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
711 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
712 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
713 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
714
715 unzipped_dir = common.UnzipTemp(zip_file, ['Test1', 'Foo3'])
716 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
717 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
718 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
719 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
720 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
721
722 unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Foo3*'])
723 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
724 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
725 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
726 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
727 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
728
729 unzipped_dir = common.UnzipTemp(zip_file, ['*Test1', '*Baz*'])
730 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
731 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
732 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
733 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
734 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
735
736 def test_UnzipTemp_withEmptyPatterns(self):
737 zip_file = self._test_UnzipTemp_createZipFile()
738 unzipped_dir = common.UnzipTemp(zip_file, [])
739 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
740 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
741 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
742 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
743 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
744
Tao Bao82490d32019-04-09 00:12:30 -0700745 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700746 def test_UnzipTemp_withPartiallyMatchingPatterns(self):
747 zip_file = self._test_UnzipTemp_createZipFile()
748 unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Nonexistent*'])
749 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
750 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
751 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
752 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
753 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
754
755 def test_UnzipTemp_withNoMatchingPatterns(self):
756 zip_file = self._test_UnzipTemp_createZipFile()
757 unzipped_dir = common.UnzipTemp(zip_file, ['Foo4', 'Nonexistent*'])
758 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
759 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
760 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
761 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
762 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
763
Tao Bao89d7ab22017-12-14 17:05:33 -0800764
Tao Bao65b94e92018-10-11 21:57:26 -0700765class CommonApkUtilsTest(test_utils.ReleaseToolsTestCase):
Tao Bao818ddf52018-01-05 11:17:34 -0800766 """Tests the APK utils related functions."""
767
768 APKCERTS_TXT1 = (
769 'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
770 ' private_key="certs/devkey.pk8"\n'
771 'name="Settings.apk"'
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700772 ' certificate="build/make/target/product/security/platform.x509.pem"'
773 ' private_key="build/make/target/product/security/platform.pk8"\n'
Tao Bao818ddf52018-01-05 11:17:34 -0800774 'name="TV.apk" certificate="PRESIGNED" private_key=""\n'
775 )
776
777 APKCERTS_CERTMAP1 = {
778 'RecoveryLocalizer.apk' : 'certs/devkey',
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700779 'Settings.apk' : 'build/make/target/product/security/platform',
Tao Bao818ddf52018-01-05 11:17:34 -0800780 'TV.apk' : 'PRESIGNED',
781 }
782
783 APKCERTS_TXT2 = (
784 'name="Compressed1.apk" certificate="certs/compressed1.x509.pem"'
785 ' private_key="certs/compressed1.pk8" compressed="gz"\n'
786 'name="Compressed2a.apk" certificate="certs/compressed2.x509.pem"'
787 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
788 'name="Compressed2b.apk" certificate="certs/compressed2.x509.pem"'
789 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
790 'name="Compressed3.apk" certificate="certs/compressed3.x509.pem"'
791 ' private_key="certs/compressed3.pk8" compressed="gz"\n'
792 )
793
794 APKCERTS_CERTMAP2 = {
795 'Compressed1.apk' : 'certs/compressed1',
796 'Compressed2a.apk' : 'certs/compressed2',
797 'Compressed2b.apk' : 'certs/compressed2',
798 'Compressed3.apk' : 'certs/compressed3',
799 }
800
801 APKCERTS_TXT3 = (
802 'name="Compressed4.apk" certificate="certs/compressed4.x509.pem"'
803 ' private_key="certs/compressed4.pk8" compressed="xz"\n'
804 )
805
806 APKCERTS_CERTMAP3 = {
807 'Compressed4.apk' : 'certs/compressed4',
808 }
809
Bill Peckham5c7b0342020-04-03 15:36:23 -0700810 # Test parsing with no optional fields, both optional fields, and only the
811 # partition optional field.
812 APKCERTS_TXT4 = (
813 'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
814 ' private_key="certs/devkey.pk8"\n'
815 'name="Settings.apk"'
816 ' certificate="build/make/target/product/security/platform.x509.pem"'
817 ' private_key="build/make/target/product/security/platform.pk8"'
818 ' compressed="gz" partition="system"\n'
819 'name="TV.apk" certificate="PRESIGNED" private_key=""'
820 ' partition="product"\n'
821 )
822
823 APKCERTS_CERTMAP4 = {
824 'RecoveryLocalizer.apk' : 'certs/devkey',
825 'Settings.apk' : 'build/make/target/product/security/platform',
826 'TV.apk' : 'PRESIGNED',
827 }
828
Tao Bao17e4e612018-02-16 17:12:54 -0800829 def setUp(self):
830 self.testdata_dir = test_utils.get_testdata_dir()
831
Tao Bao818ddf52018-01-05 11:17:34 -0800832 @staticmethod
833 def _write_apkcerts_txt(apkcerts_txt, additional=None):
834 if additional is None:
835 additional = []
836 target_files = common.MakeTempFile(suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -0400837 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800838 target_files_zip.writestr('META/apkcerts.txt', apkcerts_txt)
839 for entry in additional:
840 target_files_zip.writestr(entry, '')
841 return target_files
842
843 def test_ReadApkCerts_NoncompressedApks(self):
844 target_files = self._write_apkcerts_txt(self.APKCERTS_TXT1)
Kelvin Zhang928c2342020-09-22 16:15:57 -0400845 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800846 certmap, ext = common.ReadApkCerts(input_zip)
847
848 self.assertDictEqual(self.APKCERTS_CERTMAP1, certmap)
849 self.assertIsNone(ext)
850
851 def test_ReadApkCerts_CompressedApks(self):
852 # We have "installed" Compressed1.apk.gz only. Note that Compressed3.apk is
853 # not stored in '.gz' format, so it shouldn't be considered as installed.
854 target_files = self._write_apkcerts_txt(
855 self.APKCERTS_TXT2,
856 ['Compressed1.apk.gz', 'Compressed3.apk'])
857
Kelvin Zhang928c2342020-09-22 16:15:57 -0400858 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800859 certmap, ext = common.ReadApkCerts(input_zip)
860
861 self.assertDictEqual(self.APKCERTS_CERTMAP2, certmap)
862 self.assertEqual('.gz', ext)
863
864 # Alternative case with '.xz'.
865 target_files = self._write_apkcerts_txt(
866 self.APKCERTS_TXT3, ['Compressed4.apk.xz'])
867
Kelvin Zhang928c2342020-09-22 16:15:57 -0400868 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800869 certmap, ext = common.ReadApkCerts(input_zip)
870
871 self.assertDictEqual(self.APKCERTS_CERTMAP3, certmap)
872 self.assertEqual('.xz', ext)
873
874 def test_ReadApkCerts_CompressedAndNoncompressedApks(self):
875 target_files = self._write_apkcerts_txt(
876 self.APKCERTS_TXT1 + self.APKCERTS_TXT2,
877 ['Compressed1.apk.gz', 'Compressed3.apk'])
878
Kelvin Zhang928c2342020-09-22 16:15:57 -0400879 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800880 certmap, ext = common.ReadApkCerts(input_zip)
881
882 certmap_merged = self.APKCERTS_CERTMAP1.copy()
883 certmap_merged.update(self.APKCERTS_CERTMAP2)
884 self.assertDictEqual(certmap_merged, certmap)
885 self.assertEqual('.gz', ext)
886
887 def test_ReadApkCerts_MultipleCompressionMethods(self):
888 target_files = self._write_apkcerts_txt(
889 self.APKCERTS_TXT2 + self.APKCERTS_TXT3,
890 ['Compressed1.apk.gz', 'Compressed4.apk.xz'])
891
Kelvin Zhang928c2342020-09-22 16:15:57 -0400892 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800893 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
894
895 def test_ReadApkCerts_MismatchingKeys(self):
896 malformed_apkcerts_txt = (
897 'name="App1.apk" certificate="certs/cert1.x509.pem"'
898 ' private_key="certs/cert2.pk8"\n'
899 )
900 target_files = self._write_apkcerts_txt(malformed_apkcerts_txt)
901
Kelvin Zhang928c2342020-09-22 16:15:57 -0400902 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Bao818ddf52018-01-05 11:17:34 -0800903 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
904
Bill Peckham5c7b0342020-04-03 15:36:23 -0700905 def test_ReadApkCerts_WithWithoutOptionalFields(self):
906 target_files = self._write_apkcerts_txt(self.APKCERTS_TXT4)
Kelvin Zhang928c2342020-09-22 16:15:57 -0400907 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Bill Peckham5c7b0342020-04-03 15:36:23 -0700908 certmap, ext = common.ReadApkCerts(input_zip)
909
910 self.assertDictEqual(self.APKCERTS_CERTMAP4, certmap)
911 self.assertIsNone(ext)
912
Tao Bao04e1f012018-02-04 12:13:35 -0800913 def test_ExtractPublicKey(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800914 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
915 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
Tao Baoda30cfa2017-12-01 16:19:46 -0800916 with open(pubkey) as pubkey_fp:
Tao Bao04e1f012018-02-04 12:13:35 -0800917 self.assertEqual(pubkey_fp.read(), common.ExtractPublicKey(cert))
918
919 def test_ExtractPublicKey_invalidInput(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800920 wrong_input = os.path.join(self.testdata_dir, 'testkey.pk8')
Tao Bao04e1f012018-02-04 12:13:35 -0800921 self.assertRaises(AssertionError, common.ExtractPublicKey, wrong_input)
922
Tao Bao82490d32019-04-09 00:12:30 -0700923 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao2cc0ca12019-03-15 10:44:43 -0700924 def test_ExtractAvbPublicKey(self):
925 privkey = os.path.join(self.testdata_dir, 'testkey.key')
926 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
Tao Bao1ac886e2019-06-26 11:58:22 -0700927 extracted_from_privkey = common.ExtractAvbPublicKey('avbtool', privkey)
928 extracted_from_pubkey = common.ExtractAvbPublicKey('avbtool', pubkey)
929 with open(extracted_from_privkey, 'rb') as privkey_fp, \
930 open(extracted_from_pubkey, 'rb') as pubkey_fp:
Tao Bao2cc0ca12019-03-15 10:44:43 -0700931 self.assertEqual(privkey_fp.read(), pubkey_fp.read())
932
Tao Bao17e4e612018-02-16 17:12:54 -0800933 def test_ParseCertificate(self):
934 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
935
936 cmd = ['openssl', 'x509', '-in', cert, '-outform', 'DER']
Tao Baoda30cfa2017-12-01 16:19:46 -0800937 proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
938 universal_newlines=False)
Tao Bao17e4e612018-02-16 17:12:54 -0800939 expected, _ = proc.communicate()
940 self.assertEqual(0, proc.returncode)
941
942 with open(cert) as cert_fp:
943 actual = common.ParseCertificate(cert_fp.read())
944 self.assertEqual(expected, actual)
945
Tao Bao82490d32019-04-09 00:12:30 -0700946 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700947 def test_GetMinSdkVersion(self):
948 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
949 self.assertEqual('24', common.GetMinSdkVersion(test_app))
950
Tao Bao82490d32019-04-09 00:12:30 -0700951 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700952 def test_GetMinSdkVersion_invalidInput(self):
953 self.assertRaises(
954 common.ExternalError, common.GetMinSdkVersion, 'does-not-exist.apk')
955
Tao Bao82490d32019-04-09 00:12:30 -0700956 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700957 def test_GetMinSdkVersionInt(self):
958 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
959 self.assertEqual(24, common.GetMinSdkVersionInt(test_app, {}))
960
Tao Bao82490d32019-04-09 00:12:30 -0700961 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700962 def test_GetMinSdkVersionInt_invalidInput(self):
963 self.assertRaises(
964 common.ExternalError, common.GetMinSdkVersionInt, 'does-not-exist.apk',
965 {})
966
Tao Bao818ddf52018-01-05 11:17:34 -0800967
Tao Bao65b94e92018-10-11 21:57:26 -0700968class CommonUtilsTest(test_utils.ReleaseToolsTestCase):
Tao Baofc7e0e02018-02-13 13:54:02 -0800969
Tao Bao02a08592018-07-22 12:40:45 -0700970 def setUp(self):
971 self.testdata_dir = test_utils.get_testdata_dir()
972
Tao Bao82490d32019-04-09 00:12:30 -0700973 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800974 def test_GetSparseImage_emptyBlockMapFile(self):
975 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -0400976 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baofc7e0e02018-02-13 13:54:02 -0800977 target_files_zip.write(
978 test_utils.construct_sparse_image([
979 (0xCAC1, 6),
980 (0xCAC3, 3),
981 (0xCAC1, 4)]),
982 arcname='IMAGES/system.img')
983 target_files_zip.writestr('IMAGES/system.map', '')
984 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
985 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
986
Tao Baodba59ee2018-01-09 13:21:02 -0800987 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -0400988 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baodba59ee2018-01-09 13:21:02 -0800989 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800990
991 self.assertDictEqual(
992 {
993 '__COPY': RangeSet("0"),
994 '__NONZERO-0': RangeSet("1-5 9-12"),
995 },
996 sparse_image.file_map)
997
Tao Baob2de7d92019-04-10 10:01:47 -0700998 def test_GetSparseImage_missingImageFile(self):
Tao Baofc7e0e02018-02-13 13:54:02 -0800999 self.assertRaises(
Tao Baob2de7d92019-04-10 10:01:47 -07001000 AssertionError, common.GetSparseImage, 'system2', self.testdata_dir,
1001 None, False)
Tao Baofc7e0e02018-02-13 13:54:02 -08001002 self.assertRaises(
Tao Baob2de7d92019-04-10 10:01:47 -07001003 AssertionError, common.GetSparseImage, 'unknown', self.testdata_dir,
1004 None, False)
Tao Baofc7e0e02018-02-13 13:54:02 -08001005
Tao Bao82490d32019-04-09 00:12:30 -07001006 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -08001007 def test_GetSparseImage_missingBlockMapFile(self):
1008 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001009 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baofc7e0e02018-02-13 13:54:02 -08001010 target_files_zip.write(
1011 test_utils.construct_sparse_image([
1012 (0xCAC1, 6),
1013 (0xCAC3, 3),
1014 (0xCAC1, 4)]),
1015 arcname='IMAGES/system.img')
1016 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
1017 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1018
Tao Baodba59ee2018-01-09 13:21:02 -08001019 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001020 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baodba59ee2018-01-09 13:21:02 -08001021 self.assertRaises(
1022 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1023 False)
Tao Baofc7e0e02018-02-13 13:54:02 -08001024
Tao Bao82490d32019-04-09 00:12:30 -07001025 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -08001026 def test_GetSparseImage_sharedBlocks_notAllowed(self):
1027 """Tests the case of having overlapping blocks but disallowed."""
1028 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001029 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baofc7e0e02018-02-13 13:54:02 -08001030 target_files_zip.write(
1031 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1032 arcname='IMAGES/system.img')
1033 # Block 10 is shared between two files.
1034 target_files_zip.writestr(
1035 'IMAGES/system.map',
1036 '\n'.join([
1037 '/system/file1 1-5 9-10',
1038 '/system/file2 10-12']))
1039 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1040 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1041
Tao Baodba59ee2018-01-09 13:21:02 -08001042 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001043 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baodba59ee2018-01-09 13:21:02 -08001044 self.assertRaises(
1045 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1046 False)
Tao Baofc7e0e02018-02-13 13:54:02 -08001047
Tao Bao82490d32019-04-09 00:12:30 -07001048 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -08001049 def test_GetSparseImage_sharedBlocks_allowed(self):
1050 """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true."""
1051 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001052 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baofc7e0e02018-02-13 13:54:02 -08001053 # Construct an image with a care_map of "0-5 9-12".
1054 target_files_zip.write(
1055 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1056 arcname='IMAGES/system.img')
1057 # Block 10 is shared between two files.
1058 target_files_zip.writestr(
1059 'IMAGES/system.map',
1060 '\n'.join([
1061 '/system/file1 1-5 9-10',
1062 '/system/file2 10-12']))
1063 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1064 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1065
Tao Baodba59ee2018-01-09 13:21:02 -08001066 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001067 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baodba59ee2018-01-09 13:21:02 -08001068 sparse_image = common.GetSparseImage('system', tempdir, input_zip, True)
Tao Baofc7e0e02018-02-13 13:54:02 -08001069
1070 self.assertDictEqual(
1071 {
1072 '__COPY': RangeSet("0"),
1073 '__NONZERO-0': RangeSet("6-8 13-15"),
1074 '/system/file1': RangeSet("1-5 9-10"),
1075 '/system/file2': RangeSet("11-12"),
1076 },
1077 sparse_image.file_map)
1078
1079 # '/system/file2' should be marked with 'uses_shared_blocks', but not with
1080 # 'incomplete'.
1081 self.assertTrue(
1082 sparse_image.file_map['/system/file2'].extra['uses_shared_blocks'])
1083 self.assertNotIn(
1084 'incomplete', sparse_image.file_map['/system/file2'].extra)
1085
Tao Baoa264fef2019-10-06 21:55:20 -07001086 # '/system/file1' will only contain one field -- a copy of the input text.
1087 self.assertEqual(1, len(sparse_image.file_map['/system/file1'].extra))
1088
1089 # Meta entries should not have any extra tag.
Tao Baofc7e0e02018-02-13 13:54:02 -08001090 self.assertFalse(sparse_image.file_map['__COPY'].extra)
1091 self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
Tao Baofc7e0e02018-02-13 13:54:02 -08001092
Tao Bao82490d32019-04-09 00:12:30 -07001093 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -08001094 def test_GetSparseImage_incompleteRanges(self):
1095 """Tests the case of ext4 images with holes."""
1096 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001097 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baofc7e0e02018-02-13 13:54:02 -08001098 target_files_zip.write(
1099 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1100 arcname='IMAGES/system.img')
1101 target_files_zip.writestr(
1102 'IMAGES/system.map',
1103 '\n'.join([
1104 '/system/file1 1-5 9-10',
1105 '/system/file2 11-12']))
1106 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1107 # '/system/file2' has less blocks listed (2) than actual (3).
1108 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1109
Tao Baodba59ee2018-01-09 13:21:02 -08001110 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001111 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baodba59ee2018-01-09 13:21:02 -08001112 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -08001113
Tao Baoa264fef2019-10-06 21:55:20 -07001114 self.assertEqual(
1115 '1-5 9-10',
1116 sparse_image.file_map['/system/file1'].extra['text_str'])
Tao Baofc7e0e02018-02-13 13:54:02 -08001117 self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
1118
Tao Bao82490d32019-04-09 00:12:30 -07001119 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -07001120 def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
1121 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001122 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001123 target_files_zip.write(
1124 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1125 arcname='IMAGES/system.img')
1126 target_files_zip.writestr(
1127 'IMAGES/system.map',
1128 '\n'.join([
1129 '//system/file1 1-5 9-10',
1130 '//system/file2 11-12',
1131 '/system/app/file3 13-15']))
1132 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1133 # '/system/file2' has less blocks listed (2) than actual (3).
1134 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1135 # '/system/app/file3' has less blocks listed (3) than actual (4).
1136 target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))
1137
1138 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001139 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001140 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1141
Tao Baoa264fef2019-10-06 21:55:20 -07001142 self.assertEqual(
1143 '1-5 9-10',
1144 sparse_image.file_map['//system/file1'].extra['text_str'])
Tao Baod3554e62018-07-10 15:31:22 -07001145 self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
1146 self.assertTrue(
1147 sparse_image.file_map['/system/app/file3'].extra['incomplete'])
1148
Tao Bao82490d32019-04-09 00:12:30 -07001149 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -07001150 def test_GetSparseImage_systemRootImage_nonSystemFiles(self):
1151 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001152 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001153 target_files_zip.write(
1154 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1155 arcname='IMAGES/system.img')
1156 target_files_zip.writestr(
1157 'IMAGES/system.map',
1158 '\n'.join([
1159 '//system/file1 1-5 9-10',
1160 '//init.rc 13-15']))
1161 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1162 # '/init.rc' has less blocks listed (3) than actual (4).
1163 target_files_zip.writestr('ROOT/init.rc', os.urandom(4096 * 4))
1164
1165 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001166 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001167 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1168
Tao Baoa264fef2019-10-06 21:55:20 -07001169 self.assertEqual(
1170 '1-5 9-10',
1171 sparse_image.file_map['//system/file1'].extra['text_str'])
Tao Baod3554e62018-07-10 15:31:22 -07001172 self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
1173
Tao Bao82490d32019-04-09 00:12:30 -07001174 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -07001175 def test_GetSparseImage_fileNotFound(self):
1176 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001177 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001178 target_files_zip.write(
1179 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1180 arcname='IMAGES/system.img')
1181 target_files_zip.writestr(
1182 'IMAGES/system.map',
1183 '\n'.join([
1184 '//system/file1 1-5 9-10',
1185 '//system/file2 11-12']))
1186 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1187
1188 tempdir = common.UnzipTemp(target_files)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001189 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
Tao Baod3554e62018-07-10 15:31:22 -07001190 self.assertRaises(
1191 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1192 False)
1193
Tao Bao82490d32019-04-09 00:12:30 -07001194 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001195 def test_GetAvbChainedPartitionArg(self):
1196 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1197 info_dict = {
1198 'avb_avbtool': 'avbtool',
1199 'avb_system_key_path': pubkey,
1200 'avb_system_rollback_index_location': 2,
1201 }
1202 args = common.GetAvbChainedPartitionArg('system', info_dict).split(':')
1203 self.assertEqual(3, len(args))
1204 self.assertEqual('system', args[0])
1205 self.assertEqual('2', args[1])
1206 self.assertTrue(os.path.exists(args[2]))
1207
Tao Bao82490d32019-04-09 00:12:30 -07001208 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001209 def test_GetAvbChainedPartitionArg_withPrivateKey(self):
1210 key = os.path.join(self.testdata_dir, 'testkey.key')
1211 info_dict = {
1212 'avb_avbtool': 'avbtool',
1213 'avb_product_key_path': key,
1214 'avb_product_rollback_index_location': 2,
1215 }
1216 args = common.GetAvbChainedPartitionArg('product', info_dict).split(':')
1217 self.assertEqual(3, len(args))
1218 self.assertEqual('product', args[0])
1219 self.assertEqual('2', args[1])
1220 self.assertTrue(os.path.exists(args[2]))
1221
Tao Bao82490d32019-04-09 00:12:30 -07001222 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001223 def test_GetAvbChainedPartitionArg_withSpecifiedKey(self):
1224 info_dict = {
1225 'avb_avbtool': 'avbtool',
1226 'avb_system_key_path': 'does-not-exist',
1227 'avb_system_rollback_index_location': 2,
1228 }
1229 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1230 args = common.GetAvbChainedPartitionArg(
1231 'system', info_dict, pubkey).split(':')
1232 self.assertEqual(3, len(args))
1233 self.assertEqual('system', args[0])
1234 self.assertEqual('2', args[1])
1235 self.assertTrue(os.path.exists(args[2]))
1236
Tao Bao82490d32019-04-09 00:12:30 -07001237 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001238 def test_GetAvbChainedPartitionArg_invalidKey(self):
1239 pubkey = os.path.join(self.testdata_dir, 'testkey_with_passwd.x509.pem')
1240 info_dict = {
1241 'avb_avbtool': 'avbtool',
1242 'avb_system_key_path': pubkey,
1243 'avb_system_rollback_index_location': 2,
1244 }
1245 self.assertRaises(
Tao Bao986ee862018-10-04 15:46:16 -07001246 common.ExternalError, common.GetAvbChainedPartitionArg, 'system',
1247 info_dict)
Tao Bao02a08592018-07-22 12:40:45 -07001248
Tao Baoa57ab9f2018-08-24 12:08:38 -07001249 INFO_DICT_DEFAULT = {
1250 'recovery_api_version': 3,
1251 'fstab_version': 2,
1252 'system_root_image': 'true',
1253 'no_recovery' : 'true',
1254 'recovery_as_boot': 'true',
1255 }
1256
Daniel Norman4cc9df62019-07-18 10:11:07 -07001257 def test_LoadListFromFile(self):
1258 file_path = os.path.join(self.testdata_dir,
1259 'merge_config_framework_item_list')
1260 contents = common.LoadListFromFile(file_path)
1261 expected_contents = [
1262 'META/apkcerts.txt',
1263 'META/filesystem_config.txt',
1264 'META/root_filesystem_config.txt',
1265 'META/system_manifest.xml',
1266 'META/system_matrix.xml',
1267 'META/update_engine_config.txt',
1268 'PRODUCT/*',
1269 'ROOT/*',
1270 'SYSTEM/*',
1271 ]
1272 self.assertEqual(sorted(contents), sorted(expected_contents))
1273
Tao Baoa57ab9f2018-08-24 12:08:38 -07001274 @staticmethod
1275 def _test_LoadInfoDict_createTargetFiles(info_dict, fstab_path):
1276 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001277 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001278 info_values = ''.join(
Tao Baoda30cfa2017-12-01 16:19:46 -08001279 ['{}={}\n'.format(k, v) for k, v in sorted(info_dict.items())])
Tao Baoa57ab9f2018-08-24 12:08:38 -07001280 common.ZipWriteStr(target_files_zip, 'META/misc_info.txt', info_values)
1281
1282 FSTAB_TEMPLATE = "/dev/block/system {} ext4 ro,barrier=1 defaults"
1283 if info_dict.get('system_root_image') == 'true':
1284 fstab_values = FSTAB_TEMPLATE.format('/')
1285 else:
1286 fstab_values = FSTAB_TEMPLATE.format('/system')
1287 common.ZipWriteStr(target_files_zip, fstab_path, fstab_values)
Tao Bao410ad8b2018-08-24 12:08:38 -07001288
1289 common.ZipWriteStr(
1290 target_files_zip, 'META/file_contexts', 'file-contexts')
Tao Baoa57ab9f2018-08-24 12:08:38 -07001291 return target_files
1292
1293 def test_LoadInfoDict(self):
1294 target_files = self._test_LoadInfoDict_createTargetFiles(
1295 self.INFO_DICT_DEFAULT,
1296 'BOOT/RAMDISK/system/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001297 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001298 loaded_dict = common.LoadInfoDict(target_files_zip)
1299 self.assertEqual(3, loaded_dict['recovery_api_version'])
1300 self.assertEqual(2, loaded_dict['fstab_version'])
1301 self.assertIn('/', loaded_dict['fstab'])
1302 self.assertIn('/system', loaded_dict['fstab'])
1303
1304 def test_LoadInfoDict_legacyRecoveryFstabPath(self):
1305 target_files = self._test_LoadInfoDict_createTargetFiles(
1306 self.INFO_DICT_DEFAULT,
1307 'BOOT/RAMDISK/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001308 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001309 loaded_dict = common.LoadInfoDict(target_files_zip)
1310 self.assertEqual(3, loaded_dict['recovery_api_version'])
1311 self.assertEqual(2, loaded_dict['fstab_version'])
1312 self.assertIn('/', loaded_dict['fstab'])
1313 self.assertIn('/system', loaded_dict['fstab'])
1314
Tao Bao82490d32019-04-09 00:12:30 -07001315 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoa57ab9f2018-08-24 12:08:38 -07001316 def test_LoadInfoDict_dirInput(self):
1317 target_files = self._test_LoadInfoDict_createTargetFiles(
1318 self.INFO_DICT_DEFAULT,
1319 'BOOT/RAMDISK/system/etc/recovery.fstab')
1320 unzipped = common.UnzipTemp(target_files)
1321 loaded_dict = common.LoadInfoDict(unzipped)
1322 self.assertEqual(3, loaded_dict['recovery_api_version'])
1323 self.assertEqual(2, loaded_dict['fstab_version'])
1324 self.assertIn('/', loaded_dict['fstab'])
1325 self.assertIn('/system', loaded_dict['fstab'])
1326
Tao Bao82490d32019-04-09 00:12:30 -07001327 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoa57ab9f2018-08-24 12:08:38 -07001328 def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self):
1329 target_files = self._test_LoadInfoDict_createTargetFiles(
1330 self.INFO_DICT_DEFAULT,
1331 'BOOT/RAMDISK/system/etc/recovery.fstab')
1332 unzipped = common.UnzipTemp(target_files)
1333 loaded_dict = common.LoadInfoDict(unzipped)
1334 self.assertEqual(3, loaded_dict['recovery_api_version'])
1335 self.assertEqual(2, loaded_dict['fstab_version'])
1336 self.assertIn('/', loaded_dict['fstab'])
1337 self.assertIn('/system', loaded_dict['fstab'])
1338
1339 def test_LoadInfoDict_systemRootImageFalse(self):
1340 # Devices not using system-as-root nor recovery-as-boot. Non-A/B devices
1341 # launched prior to P will likely have this config.
1342 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1343 del info_dict['no_recovery']
1344 del info_dict['system_root_image']
1345 del info_dict['recovery_as_boot']
1346 target_files = self._test_LoadInfoDict_createTargetFiles(
1347 info_dict,
1348 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001349 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001350 loaded_dict = common.LoadInfoDict(target_files_zip)
1351 self.assertEqual(3, loaded_dict['recovery_api_version'])
1352 self.assertEqual(2, loaded_dict['fstab_version'])
1353 self.assertNotIn('/', loaded_dict['fstab'])
1354 self.assertIn('/system', loaded_dict['fstab'])
1355
1356 def test_LoadInfoDict_recoveryAsBootFalse(self):
1357 # Devices using system-as-root, but with standalone recovery image. Non-A/B
1358 # devices launched since P will likely have this config.
1359 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1360 del info_dict['no_recovery']
1361 del info_dict['recovery_as_boot']
1362 target_files = self._test_LoadInfoDict_createTargetFiles(
1363 info_dict,
1364 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001365 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001366 loaded_dict = common.LoadInfoDict(target_files_zip)
1367 self.assertEqual(3, loaded_dict['recovery_api_version'])
1368 self.assertEqual(2, loaded_dict['fstab_version'])
1369 self.assertIn('/', loaded_dict['fstab'])
1370 self.assertIn('/system', loaded_dict['fstab'])
1371
1372 def test_LoadInfoDict_noRecoveryTrue(self):
1373 # Device doesn't have a recovery partition at all.
1374 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1375 del info_dict['recovery_as_boot']
1376 target_files = self._test_LoadInfoDict_createTargetFiles(
1377 info_dict,
1378 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001379 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Baoa57ab9f2018-08-24 12:08:38 -07001380 loaded_dict = common.LoadInfoDict(target_files_zip)
1381 self.assertEqual(3, loaded_dict['recovery_api_version'])
1382 self.assertEqual(2, loaded_dict['fstab_version'])
1383 self.assertIsNone(loaded_dict['fstab'])
1384
Tao Bao82490d32019-04-09 00:12:30 -07001385 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao410ad8b2018-08-24 12:08:38 -07001386 def test_LoadInfoDict_missingMetaMiscInfoTxt(self):
1387 target_files = self._test_LoadInfoDict_createTargetFiles(
1388 self.INFO_DICT_DEFAULT,
1389 'BOOT/RAMDISK/system/etc/recovery.fstab')
1390 common.ZipDelete(target_files, 'META/misc_info.txt')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001391 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Bao410ad8b2018-08-24 12:08:38 -07001392 self.assertRaises(ValueError, common.LoadInfoDict, target_files_zip)
1393
Tao Bao82490d32019-04-09 00:12:30 -07001394 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao410ad8b2018-08-24 12:08:38 -07001395 def test_LoadInfoDict_repacking(self):
1396 target_files = self._test_LoadInfoDict_createTargetFiles(
1397 self.INFO_DICT_DEFAULT,
1398 'BOOT/RAMDISK/system/etc/recovery.fstab')
1399 unzipped = common.UnzipTemp(target_files)
1400 loaded_dict = common.LoadInfoDict(unzipped, True)
1401 self.assertEqual(3, loaded_dict['recovery_api_version'])
1402 self.assertEqual(2, loaded_dict['fstab_version'])
1403 self.assertIn('/', loaded_dict['fstab'])
1404 self.assertIn('/system', loaded_dict['fstab'])
1405 self.assertEqual(
1406 os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir'])
1407 self.assertEqual(
1408 os.path.join(unzipped, 'META', 'root_filesystem_config.txt'),
1409 loaded_dict['root_fs_config'])
1410
1411 def test_LoadInfoDict_repackingWithZipFileInput(self):
1412 target_files = self._test_LoadInfoDict_createTargetFiles(
1413 self.INFO_DICT_DEFAULT,
1414 'BOOT/RAMDISK/system/etc/recovery.fstab')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001415 with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
Tao Bao410ad8b2018-08-24 12:08:38 -07001416 self.assertRaises(
1417 AssertionError, common.LoadInfoDict, target_files_zip, True)
1418
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001419 def test_MergeDynamicPartitionInfoDicts_ReturnsMergedDict(self):
1420 framework_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001421 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001422 'super_partition_groups': 'group_a',
1423 'dynamic_partition_list': 'system',
Daniel Norman55417142019-11-25 16:04:36 -08001424 'super_group_a_partition_list': 'system',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001425 }
1426 vendor_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001427 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001428 'super_partition_groups': 'group_a group_b',
1429 'dynamic_partition_list': 'vendor product',
Daniel Normanb0c75912020-09-24 14:30:21 -07001430 'super_block_devices': 'super',
1431 'super_super_device_size': '3000',
Daniel Norman55417142019-11-25 16:04:36 -08001432 'super_group_a_partition_list': 'vendor',
1433 'super_group_a_group_size': '1000',
1434 'super_group_b_partition_list': 'product',
1435 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001436 }
1437 merged_dict = common.MergeDynamicPartitionInfoDicts(
1438 framework_dict=framework_dict,
Daniel Norman55417142019-11-25 16:04:36 -08001439 vendor_dict=vendor_dict)
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001440 expected_merged_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001441 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001442 'super_partition_groups': 'group_a group_b',
Daniel Normanb0c75912020-09-24 14:30:21 -07001443 'dynamic_partition_list': 'product system vendor',
1444 'super_block_devices': 'super',
1445 'super_super_device_size': '3000',
Daniel Norman55417142019-11-25 16:04:36 -08001446 'super_group_a_partition_list': 'system vendor',
1447 'super_group_a_group_size': '1000',
1448 'super_group_b_partition_list': 'product',
1449 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001450 }
1451 self.assertEqual(merged_dict, expected_merged_dict)
1452
1453 def test_MergeDynamicPartitionInfoDicts_IgnoringFrameworkGroupSize(self):
1454 framework_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001455 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001456 'super_partition_groups': 'group_a',
1457 'dynamic_partition_list': 'system',
Daniel Norman55417142019-11-25 16:04:36 -08001458 'super_group_a_partition_list': 'system',
1459 'super_group_a_group_size': '5000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001460 }
1461 vendor_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001462 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001463 'super_partition_groups': 'group_a group_b',
1464 'dynamic_partition_list': 'vendor product',
Daniel Norman55417142019-11-25 16:04:36 -08001465 'super_group_a_partition_list': 'vendor',
1466 'super_group_a_group_size': '1000',
1467 'super_group_b_partition_list': 'product',
1468 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001469 }
1470 merged_dict = common.MergeDynamicPartitionInfoDicts(
1471 framework_dict=framework_dict,
Daniel Norman55417142019-11-25 16:04:36 -08001472 vendor_dict=vendor_dict)
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001473 expected_merged_dict = {
Daniel Normanb0c75912020-09-24 14:30:21 -07001474 'use_dynamic_partitions': 'true',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001475 'super_partition_groups': 'group_a group_b',
Daniel Normanb0c75912020-09-24 14:30:21 -07001476 'dynamic_partition_list': 'product system vendor',
Daniel Norman55417142019-11-25 16:04:36 -08001477 'super_group_a_partition_list': 'system vendor',
1478 'super_group_a_group_size': '1000',
1479 'super_group_b_partition_list': 'product',
1480 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001481 }
1482 self.assertEqual(merged_dict, expected_merged_dict)
1483
Daniel Norman276f0622019-07-26 14:13:51 -07001484 def test_GetAvbPartitionArg(self):
1485 info_dict = {}
1486 cmd = common.GetAvbPartitionArg('system', '/path/to/system.img', info_dict)
1487 self.assertEqual(
1488 ['--include_descriptors_from_image', '/path/to/system.img'], cmd)
1489
1490 @test_utils.SkipIfExternalToolsUnavailable()
1491 def test_AppendVBMetaArgsForPartition_vendorAsChainedPartition(self):
1492 testdata_dir = test_utils.get_testdata_dir()
1493 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1494 info_dict = {
1495 'avb_avbtool': 'avbtool',
1496 'avb_vendor_key_path': pubkey,
1497 'avb_vendor_rollback_index_location': 5,
1498 }
1499 cmd = common.GetAvbPartitionArg('vendor', '/path/to/vendor.img', info_dict)
1500 self.assertEqual(2, len(cmd))
1501 self.assertEqual('--chain_partition', cmd[0])
1502 chained_partition_args = cmd[1].split(':')
1503 self.assertEqual(3, len(chained_partition_args))
1504 self.assertEqual('vendor', chained_partition_args[0])
1505 self.assertEqual('5', chained_partition_args[1])
1506 self.assertTrue(os.path.exists(chained_partition_args[2]))
1507
Tao Bao3612c882019-10-14 17:49:31 -07001508 @test_utils.SkipIfExternalToolsUnavailable()
1509 def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_nonAb(self):
1510 testdata_dir = test_utils.get_testdata_dir()
1511 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1512 info_dict = {
1513 'avb_avbtool': 'avbtool',
1514 'avb_recovery_key_path': pubkey,
1515 'avb_recovery_rollback_index_location': 3,
1516 }
1517 cmd = common.GetAvbPartitionArg(
1518 'recovery', '/path/to/recovery.img', info_dict)
1519 self.assertFalse(cmd)
1520
1521 @test_utils.SkipIfExternalToolsUnavailable()
1522 def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_ab(self):
1523 testdata_dir = test_utils.get_testdata_dir()
1524 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1525 info_dict = {
1526 'ab_update': 'true',
1527 'avb_avbtool': 'avbtool',
1528 'avb_recovery_key_path': pubkey,
1529 'avb_recovery_rollback_index_location': 3,
1530 }
1531 cmd = common.GetAvbPartitionArg(
1532 'recovery', '/path/to/recovery.img', info_dict)
1533 self.assertEqual(2, len(cmd))
1534 self.assertEqual('--chain_partition', cmd[0])
1535 chained_partition_args = cmd[1].split(':')
1536 self.assertEqual(3, len(chained_partition_args))
1537 self.assertEqual('recovery', chained_partition_args[0])
1538 self.assertEqual('3', chained_partition_args[1])
1539 self.assertTrue(os.path.exists(chained_partition_args[2]))
1540
Tianjie20dd8f22020-04-19 15:51:16 -07001541 def test_BuildVBMeta_appendAftlCommandSyntax(self):
1542 testdata_dir = test_utils.get_testdata_dir()
1543 common.OPTIONS.info_dict = {
1544 'ab_update': 'true',
1545 'avb_avbtool': 'avbtool',
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001546 'build.prop': common.PartitionBuildProps.FromDictionary(
1547 'system', {
1548 'ro.build.version.incremental': '6285659',
1549 'ro.product.device': 'coral',
1550 'ro.build.fingerprint':
1551 'google/coral/coral:R/RP1A.200311.002/'
1552 '6285659:userdebug/dev-keys'}
1553 ),
Tianjie20dd8f22020-04-19 15:51:16 -07001554 }
1555 common.OPTIONS.aftl_tool_path = 'aftltool'
1556 common.OPTIONS.aftl_server = 'log.endpoints.aftl-dev.cloud.goog:9000'
1557 common.OPTIONS.aftl_key_path = os.path.join(testdata_dir,
1558 'test_transparency_key.pub')
1559 common.OPTIONS.aftl_manufacturer_key_path = os.path.join(
1560 testdata_dir, 'test_aftl_rsa4096.pem')
1561
1562 vbmeta_image = tempfile.NamedTemporaryFile(delete=False)
1563 cmd = common.ConstructAftlMakeImageCommands(vbmeta_image.name)
1564 expected_cmd = [
1565 'aftltool', 'make_icp_from_vbmeta',
1566 '--vbmeta_image_path', 'place_holder',
1567 '--output', vbmeta_image.name,
1568 '--version_incremental', '6285659',
1569 '--transparency_log_servers',
1570 'log.endpoints.aftl-dev.cloud.goog:9000,{}'.format(
1571 common.OPTIONS.aftl_key_path),
1572 '--manufacturer_key', common.OPTIONS.aftl_manufacturer_key_path,
1573 '--algorithm', 'SHA256_RSA4096',
1574 '--padding', '4096']
1575
1576 # ignore the place holder, i.e. path to a temp file
1577 self.assertEqual(cmd[:3], expected_cmd[:3])
1578 self.assertEqual(cmd[4:], expected_cmd[4:])
1579
1580 @unittest.skip("enable after we have a server for public")
1581 def test_BuildVBMeta_appendAftlContactServer(self):
Tianjie Xueaed60c2020-03-12 00:33:28 -07001582 testdata_dir = test_utils.get_testdata_dir()
1583 common.OPTIONS.info_dict = {
1584 'ab_update': 'true',
1585 'avb_avbtool': 'avbtool',
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001586 'build.prop': common.PartitionBuildProps.FromDictionary(
1587 'system', {
1588 'ro.build.version.incremental': '6285659',
1589 'ro.product.device': 'coral',
1590 'ro.build.fingerprint':
1591 'google/coral/coral:R/RP1A.200311.002/'
1592 '6285659:userdebug/dev-keys'}
1593 )
Tianjie Xueaed60c2020-03-12 00:33:28 -07001594 }
Tianjie0f307452020-04-01 12:20:21 -07001595 common.OPTIONS.aftl_tool_path = "aftltool"
Tianjie Xueaed60c2020-03-12 00:33:28 -07001596 common.OPTIONS.aftl_server = "log.endpoints.aftl-dev.cloud.goog:9000"
1597 common.OPTIONS.aftl_key_path = os.path.join(testdata_dir,
1598 'test_transparency_key.pub')
1599 common.OPTIONS.aftl_manufacturer_key_path = os.path.join(
1600 testdata_dir, 'test_aftl_rsa4096.pem')
1601
1602 input_dir = common.MakeTempDir()
1603 system_image = common.MakeTempFile()
1604 build_image_cmd = ['mkuserimg_mke2fs', input_dir, system_image, 'ext4',
1605 '/system', str(4096 * 100), '-j', '0', '-s']
1606 common.RunAndCheckOutput(build_image_cmd)
1607
1608 add_footer_cmd = ['avbtool', 'add_hashtree_footer',
1609 '--partition_size', str(4096 * 150),
1610 '--partition_name', 'system',
1611 '--image', system_image]
1612 common.RunAndCheckOutput(add_footer_cmd)
1613
1614 vbmeta_image = common.MakeTempFile()
1615 common.BuildVBMeta(vbmeta_image, {'system': system_image}, 'vbmeta',
1616 ['system'])
1617
1618 verify_cmd = ['aftltool', 'verify_image_icp', '--vbmeta_image_path',
1619 vbmeta_image, '--transparency_log_pub_keys',
1620 common.OPTIONS.aftl_key_path]
1621 common.RunAndCheckOutput(verify_cmd)
1622
Tao Baofc7e0e02018-02-13 13:54:02 -08001623
Tao Bao65b94e92018-10-11 21:57:26 -07001624class InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
Tao Bao1c830bf2017-12-25 10:43:47 -08001625 """Checks the format of install-recovery.sh.
Tianjie Xu9c384d22017-06-20 17:00:55 -07001626
Tao Bao1c830bf2017-12-25 10:43:47 -08001627 Its format should match between common.py and validate_target_files.py.
1628 """
Tianjie Xu9c384d22017-06-20 17:00:55 -07001629
1630 def setUp(self):
Tao Bao1c830bf2017-12-25 10:43:47 -08001631 self._tempdir = common.MakeTempDir()
Kelvin Zhangc693d952020-07-22 19:21:22 -04001632 # Create a fake dict that contains the fstab info for boot&recovery.
Tianjie Xu9c384d22017-06-20 17:00:55 -07001633 self._info = {"fstab" : {}}
Kelvin Zhangc693d952020-07-22 19:21:22 -04001634 fake_fstab = [
Tao Bao1c830bf2017-12-25 10:43:47 -08001635 "/dev/soc.0/by-name/boot /boot emmc defaults defaults",
1636 "/dev/soc.0/by-name/recovery /recovery emmc defaults defaults"]
Kelvin Zhangc693d952020-07-22 19:21:22 -04001637 self._info["fstab"] = common.LoadRecoveryFSTab("\n".join, 2, fake_fstab)
Tianjie Xudf055582017-11-07 12:22:58 -08001638 # Construct the gzipped recovery.img and boot.img
1639 self.recovery_data = bytearray([
1640 0x1f, 0x8b, 0x08, 0x00, 0x81, 0x11, 0x02, 0x5a, 0x00, 0x03, 0x2b, 0x4a,
1641 0x4d, 0xce, 0x2f, 0x4b, 0x2d, 0xaa, 0x04, 0x00, 0xc9, 0x93, 0x43, 0xf3,
1642 0x08, 0x00, 0x00, 0x00
1643 ])
1644 # echo -n "boot" | gzip -f | hd
1645 self.boot_data = bytearray([
1646 0x1f, 0x8b, 0x08, 0x00, 0x8c, 0x12, 0x02, 0x5a, 0x00, 0x03, 0x4b, 0xca,
1647 0xcf, 0x2f, 0x01, 0x00, 0xc4, 0xae, 0xed, 0x46, 0x04, 0x00, 0x00, 0x00
1648 ])
Tianjie Xu9c384d22017-06-20 17:00:55 -07001649
1650 def _out_tmp_sink(self, name, data, prefix="SYSTEM"):
1651 loc = os.path.join(self._tempdir, prefix, name)
1652 if not os.path.exists(os.path.dirname(loc)):
1653 os.makedirs(os.path.dirname(loc))
Tao Baoda30cfa2017-12-01 16:19:46 -08001654 with open(loc, "wb") as f:
Tianjie Xu9c384d22017-06-20 17:00:55 -07001655 f.write(data)
1656
1657 def test_full_recovery(self):
Tao Bao31b08072017-11-08 15:50:59 -08001658 recovery_image = common.File("recovery.img", self.recovery_data)
1659 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001660 self._info["full_recovery_image"] = "true"
1661
1662 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1663 recovery_image, boot_image, self._info)
1664 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1665 self._info)
1666
Tao Bao82490d32019-04-09 00:12:30 -07001667 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu9c384d22017-06-20 17:00:55 -07001668 def test_recovery_from_boot(self):
Tao Bao31b08072017-11-08 15:50:59 -08001669 recovery_image = common.File("recovery.img", self.recovery_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001670 self._out_tmp_sink("recovery.img", recovery_image.data, "IMAGES")
Tao Bao31b08072017-11-08 15:50:59 -08001671 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001672 self._out_tmp_sink("boot.img", boot_image.data, "IMAGES")
1673
1674 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1675 recovery_image, boot_image, self._info)
1676 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1677 self._info)
1678 # Validate 'recovery-from-boot' with bonus argument.
Tao Baoda30cfa2017-12-01 16:19:46 -08001679 self._out_tmp_sink("etc/recovery-resource.dat", b"bonus", "SYSTEM")
Tianjie Xu9c384d22017-06-20 17:00:55 -07001680 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1681 recovery_image, boot_image, self._info)
1682 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1683 self._info)
Yifan Hong45433e42019-01-18 13:55:25 -08001684
1685
Yifan Hong45433e42019-01-18 13:55:25 -08001686class MockBlockDifference(object):
Tao Baoda30cfa2017-12-01 16:19:46 -08001687
Yifan Hong45433e42019-01-18 13:55:25 -08001688 def __init__(self, partition, tgt, src=None):
1689 self.partition = partition
1690 self.tgt = tgt
1691 self.src = src
Tao Baoda30cfa2017-12-01 16:19:46 -08001692
Yifan Hong45433e42019-01-18 13:55:25 -08001693 def WriteScript(self, script, _, progress=None,
1694 write_verify_script=False):
1695 if progress:
1696 script.AppendExtra("progress({})".format(progress))
1697 script.AppendExtra("patch({});".format(self.partition))
1698 if write_verify_script:
1699 self.WritePostInstallVerifyScript(script)
Tao Baoda30cfa2017-12-01 16:19:46 -08001700
Yifan Hong45433e42019-01-18 13:55:25 -08001701 def WritePostInstallVerifyScript(self, script):
1702 script.AppendExtra("verify({});".format(self.partition))
1703
1704
1705class FakeSparseImage(object):
Tao Baoda30cfa2017-12-01 16:19:46 -08001706
Yifan Hong45433e42019-01-18 13:55:25 -08001707 def __init__(self, size):
1708 self.blocksize = 4096
1709 self.total_blocks = size // 4096
1710 assert size % 4096 == 0, "{} is not a multiple of 4096".format(size)
1711
1712
1713class DynamicPartitionsDifferenceTest(test_utils.ReleaseToolsTestCase):
Tao Baoda30cfa2017-12-01 16:19:46 -08001714
Yifan Hong45433e42019-01-18 13:55:25 -08001715 @staticmethod
1716 def get_op_list(output_path):
Kelvin Zhang928c2342020-09-22 16:15:57 -04001717 with zipfile.ZipFile(output_path, allowZip64=True) as output_zip:
Tao Baoda30cfa2017-12-01 16:19:46 -08001718 with output_zip.open('dynamic_partitions_op_list') as op_list:
1719 return [line.decode().strip() for line in op_list.readlines()
1720 if not line.startswith(b'#')]
Yifan Hong45433e42019-01-18 13:55:25 -08001721
1722 def setUp(self):
Tao Baoe1148042019-10-07 20:00:34 -07001723 self.script = test_utils.MockScriptWriter()
Yifan Hong45433e42019-01-18 13:55:25 -08001724 self.output_path = common.MakeTempFile(suffix='.zip')
1725
1726 def test_full(self):
1727 target_info = common.LoadDictionaryFromLines("""
1728dynamic_partition_list=system vendor
1729super_partition_groups=group_foo
1730super_group_foo_group_size={group_size}
1731super_group_foo_partition_list=system vendor
1732""".format(group_size=4 * GiB).split("\n"))
1733 block_diffs = [MockBlockDifference("system", FakeSparseImage(3 * GiB)),
1734 MockBlockDifference("vendor", FakeSparseImage(1 * GiB))]
1735
1736 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001737 with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
Yifan Hong45433e42019-01-18 13:55:25 -08001738 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1739
1740 self.assertEqual(str(self.script).strip(), """
1741assert(update_dynamic_partitions(package_extract_file("dynamic_partitions_op_list")));
Yifan Hong45433e42019-01-18 13:55:25 -08001742patch(system);
1743verify(system);
1744unmap_partition("system");
Tao Baof1113e92019-06-18 12:10:14 -07001745patch(vendor);
1746verify(vendor);
1747unmap_partition("vendor");
Yifan Hong45433e42019-01-18 13:55:25 -08001748""".strip())
1749
1750 lines = self.get_op_list(self.output_path)
1751
1752 remove_all_groups = lines.index("remove_all_groups")
1753 add_group = lines.index("add_group group_foo 4294967296")
1754 add_vendor = lines.index("add vendor group_foo")
1755 add_system = lines.index("add system group_foo")
1756 resize_vendor = lines.index("resize vendor 1073741824")
1757 resize_system = lines.index("resize system 3221225472")
1758
1759 self.assertLess(remove_all_groups, add_group,
1760 "Should add groups after removing all groups")
1761 self.assertLess(add_group, min(add_vendor, add_system),
1762 "Should add partitions after adding group")
1763 self.assertLess(add_system, resize_system,
1764 "Should resize system after adding it")
1765 self.assertLess(add_vendor, resize_vendor,
1766 "Should resize vendor after adding it")
1767
1768 def test_inc_groups(self):
1769 source_info = common.LoadDictionaryFromLines("""
1770super_partition_groups=group_foo group_bar group_baz
1771super_group_foo_group_size={group_foo_size}
1772super_group_bar_group_size={group_bar_size}
1773""".format(group_foo_size=4 * GiB, group_bar_size=3 * GiB).split("\n"))
1774 target_info = common.LoadDictionaryFromLines("""
1775super_partition_groups=group_foo group_baz group_qux
1776super_group_foo_group_size={group_foo_size}
1777super_group_baz_group_size={group_baz_size}
1778super_group_qux_group_size={group_qux_size}
1779""".format(group_foo_size=3 * GiB, group_baz_size=4 * GiB,
1780 group_qux_size=1 * GiB).split("\n"))
1781
1782 dp_diff = common.DynamicPartitionsDifference(target_info,
1783 block_diffs=[],
1784 source_info_dict=source_info)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001785 with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
Yifan Hong45433e42019-01-18 13:55:25 -08001786 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1787
1788 lines = self.get_op_list(self.output_path)
1789
1790 removed = lines.index("remove_group group_bar")
1791 shrunk = lines.index("resize_group group_foo 3221225472")
1792 grown = lines.index("resize_group group_baz 4294967296")
1793 added = lines.index("add_group group_qux 1073741824")
1794
Tao Baof1113e92019-06-18 12:10:14 -07001795 self.assertLess(max(removed, shrunk),
1796 min(grown, added),
Yifan Hong45433e42019-01-18 13:55:25 -08001797 "ops that remove / shrink partitions must precede ops that "
1798 "grow / add partitions")
1799
Yifan Hongbb2658d2019-01-25 12:30:58 -08001800 def test_incremental(self):
Yifan Hong45433e42019-01-18 13:55:25 -08001801 source_info = common.LoadDictionaryFromLines("""
Justin Yun6151e3f2019-06-25 15:58:13 +09001802dynamic_partition_list=system vendor product system_ext
Yifan Hong45433e42019-01-18 13:55:25 -08001803super_partition_groups=group_foo
1804super_group_foo_group_size={group_foo_size}
Justin Yun6151e3f2019-06-25 15:58:13 +09001805super_group_foo_partition_list=system vendor product system_ext
Yifan Hong45433e42019-01-18 13:55:25 -08001806""".format(group_foo_size=4 * GiB).split("\n"))
1807 target_info = common.LoadDictionaryFromLines("""
1808dynamic_partition_list=system vendor product odm
1809super_partition_groups=group_foo group_bar
1810super_group_foo_group_size={group_foo_size}
1811super_group_foo_partition_list=system vendor odm
1812super_group_bar_group_size={group_bar_size}
1813super_group_bar_partition_list=product
1814""".format(group_foo_size=3 * GiB, group_bar_size=1 * GiB).split("\n"))
1815
1816 block_diffs = [MockBlockDifference("system", FakeSparseImage(1536 * MiB),
1817 src=FakeSparseImage(1024 * MiB)),
1818 MockBlockDifference("vendor", FakeSparseImage(512 * MiB),
1819 src=FakeSparseImage(1024 * MiB)),
1820 MockBlockDifference("product", FakeSparseImage(1024 * MiB),
1821 src=FakeSparseImage(1024 * MiB)),
Justin Yun6151e3f2019-06-25 15:58:13 +09001822 MockBlockDifference("system_ext", None,
Yifan Hong45433e42019-01-18 13:55:25 -08001823 src=FakeSparseImage(1024 * MiB)),
1824 MockBlockDifference("odm", FakeSparseImage(1024 * MiB),
1825 src=None)]
1826
1827 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1828 source_info_dict=source_info)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001829 with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
Yifan Hong45433e42019-01-18 13:55:25 -08001830 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1831
1832 metadata_idx = self.script.lines.index(
1833 'assert(update_dynamic_partitions(package_extract_file('
1834 '"dynamic_partitions_op_list")));')
1835 self.assertLess(self.script.lines.index('patch(vendor);'), metadata_idx)
1836 self.assertLess(metadata_idx, self.script.lines.index('verify(vendor);'))
1837 for p in ("product", "system", "odm"):
1838 patch_idx = self.script.lines.index("patch({});".format(p))
1839 verify_idx = self.script.lines.index("verify({});".format(p))
1840 self.assertLess(metadata_idx, patch_idx,
1841 "Should patch {} after updating metadata".format(p))
1842 self.assertLess(patch_idx, verify_idx,
1843 "Should verify {} after patching".format(p))
1844
Justin Yun6151e3f2019-06-25 15:58:13 +09001845 self.assertNotIn("patch(system_ext);", self.script.lines)
Yifan Hong45433e42019-01-18 13:55:25 -08001846
1847 lines = self.get_op_list(self.output_path)
1848
Justin Yun6151e3f2019-06-25 15:58:13 +09001849 remove = lines.index("remove system_ext")
Yifan Hong45433e42019-01-18 13:55:25 -08001850 move_product_out = lines.index("move product default")
1851 shrink = lines.index("resize vendor 536870912")
1852 shrink_group = lines.index("resize_group group_foo 3221225472")
1853 add_group_bar = lines.index("add_group group_bar 1073741824")
1854 add_odm = lines.index("add odm group_foo")
1855 grow_existing = lines.index("resize system 1610612736")
1856 grow_added = lines.index("resize odm 1073741824")
1857 move_product_in = lines.index("move product group_bar")
1858
1859 max_idx_move_partition_out_foo = max(remove, move_product_out, shrink)
1860 min_idx_move_partition_in_foo = min(add_odm, grow_existing, grow_added)
1861
1862 self.assertLess(max_idx_move_partition_out_foo, shrink_group,
1863 "Must shrink group after partitions inside group are shrunk"
1864 " / removed")
1865
1866 self.assertLess(add_group_bar, move_product_in,
1867 "Must add partitions to group after group is added")
1868
1869 self.assertLess(max_idx_move_partition_out_foo,
1870 min_idx_move_partition_in_foo,
1871 "Must shrink partitions / remove partitions from group"
1872 "before adding / moving partitions into group")
Yifan Hongbb2658d2019-01-25 12:30:58 -08001873
1874 def test_remove_partition(self):
1875 source_info = common.LoadDictionaryFromLines("""
1876blockimgdiff_versions=3,4
1877use_dynamic_partitions=true
1878dynamic_partition_list=foo
1879super_partition_groups=group_foo
1880super_group_foo_group_size={group_foo_size}
1881super_group_foo_partition_list=foo
1882""".format(group_foo_size=4 * GiB).split("\n"))
1883 target_info = common.LoadDictionaryFromLines("""
1884blockimgdiff_versions=3,4
1885use_dynamic_partitions=true
1886super_partition_groups=group_foo
1887super_group_foo_group_size={group_foo_size}
1888""".format(group_foo_size=4 * GiB).split("\n"))
1889
1890 common.OPTIONS.info_dict = target_info
1891 common.OPTIONS.target_info_dict = target_info
1892 common.OPTIONS.source_info_dict = source_info
1893 common.OPTIONS.cache_size = 4 * 4096
1894
1895 block_diffs = [common.BlockDifference("foo", EmptyImage(),
1896 src=DataImage("source", pad=True))]
1897
1898 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1899 source_info_dict=source_info)
Kelvin Zhang928c2342020-09-22 16:15:57 -04001900 with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
Yifan Hongbb2658d2019-01-25 12:30:58 -08001901 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1902
1903 self.assertNotIn("block_image_update", str(self.script),
Tao Bao2cc0ca12019-03-15 10:44:43 -07001904 "Removed partition should not be patched.")
Yifan Hongbb2658d2019-01-25 12:30:58 -08001905
1906 lines = self.get_op_list(self.output_path)
1907 self.assertEqual(lines, ["remove foo"])
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001908
1909
1910class PartitionBuildPropsTest(test_utils.ReleaseToolsTestCase):
1911 def setUp(self):
Tianjie Xu9afb2212020-05-10 21:48:15 +00001912 self.odm_build_prop = [
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001913 'ro.odm.build.date.utc=1578430045',
1914 'ro.odm.build.fingerprint='
1915 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1916 'ro.product.odm.device=coral',
1917 'import /odm/etc/build_${ro.boot.product.device_name}.prop',
1918 ]
1919
1920 @staticmethod
1921 def _BuildZipFile(entries):
1922 input_file = common.MakeTempFile(prefix='target_files-', suffix='.zip')
Kelvin Zhang928c2342020-09-22 16:15:57 -04001923 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip:
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001924 for name, content in entries.items():
1925 input_zip.writestr(name, content)
1926
1927 return input_file
1928
1929 def test_parseBuildProps_noImportStatement(self):
1930 build_prop = [
Tianjie Xu9afb2212020-05-10 21:48:15 +00001931 'ro.odm.build.date.utc=1578430045',
1932 'ro.odm.build.fingerprint='
1933 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1934 'ro.product.odm.device=coral',
Tianjie Xu0fde41e2020-05-09 05:24:18 +00001935 ]
1936 input_file = self._BuildZipFile({
Tianjie Xu9afb2212020-05-10 21:48:15 +00001937 'ODM/etc/build.prop': '\n'.join(build_prop),
1938 })
1939
Kelvin Zhang928c2342020-09-22 16:15:57 -04001940 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00001941 placeholder_values = {
1942 'ro.boot.product.device_name': ['std', 'pro']
1943 }
1944 partition_props = common.PartitionBuildProps.FromInputFile(
1945 input_zip, 'odm', placeholder_values)
1946
1947 self.assertEqual({
1948 'ro.odm.build.date.utc': '1578430045',
1949 'ro.odm.build.fingerprint':
1950 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1951 'ro.product.odm.device': 'coral',
1952 }, partition_props.build_props)
1953
1954 self.assertEqual(set(), partition_props.prop_overrides)
1955
1956 def test_parseBuildProps_singleImportStatement(self):
1957 build_std_prop = [
1958 'ro.product.odm.device=coral',
1959 'ro.product.odm.name=product1',
1960 ]
1961 build_pro_prop = [
1962 'ro.product.odm.device=coralpro',
1963 'ro.product.odm.name=product2',
1964 ]
1965
1966 input_file = self._BuildZipFile({
1967 'ODM/etc/build.prop': '\n'.join(self.odm_build_prop),
1968 'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
1969 'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
1970 })
1971
Kelvin Zhang928c2342020-09-22 16:15:57 -04001972 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00001973 placeholder_values = {
1974 'ro.boot.product.device_name': 'std'
1975 }
1976 partition_props = common.PartitionBuildProps.FromInputFile(
1977 input_zip, 'odm', placeholder_values)
1978
1979 self.assertEqual({
1980 'ro.odm.build.date.utc': '1578430045',
1981 'ro.odm.build.fingerprint':
1982 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1983 'ro.product.odm.device': 'coral',
1984 'ro.product.odm.name': 'product1',
1985 }, partition_props.build_props)
1986
Kelvin Zhang928c2342020-09-22 16:15:57 -04001987 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00001988 placeholder_values = {
1989 'ro.boot.product.device_name': 'pro'
1990 }
1991 partition_props = common.PartitionBuildProps.FromInputFile(
1992 input_zip, 'odm', placeholder_values)
1993
1994 self.assertEqual({
1995 'ro.odm.build.date.utc': '1578430045',
1996 'ro.odm.build.fingerprint':
1997 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1998 'ro.product.odm.device': 'coralpro',
1999 'ro.product.odm.name': 'product2',
2000 }, partition_props.build_props)
2001
2002 def test_parseBuildProps_noPlaceHolders(self):
2003 build_prop = copy.copy(self.odm_build_prop)
2004 input_file = self._BuildZipFile({
2005 'ODM/etc/build.prop': '\n'.join(build_prop),
Tianjie Xu0fde41e2020-05-09 05:24:18 +00002006 })
2007
Kelvin Zhang928c2342020-09-22 16:15:57 -04002008 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu0fde41e2020-05-09 05:24:18 +00002009 partition_props = common.PartitionBuildProps.FromInputFile(
2010 input_zip, 'odm')
2011
2012 self.assertEqual({
Tianjie Xu9afb2212020-05-10 21:48:15 +00002013 'ro.odm.build.date.utc': '1578430045',
2014 'ro.odm.build.fingerprint':
2015 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2016 'ro.product.odm.device': 'coral',
Tianjie Xu0fde41e2020-05-09 05:24:18 +00002017 }, partition_props.build_props)
2018
Tianjie Xu9afb2212020-05-10 21:48:15 +00002019 self.assertEqual(set(), partition_props.prop_overrides)
2020
2021 def test_parseBuildProps_multipleImportStatements(self):
2022 build_prop = copy.deepcopy(self.odm_build_prop)
2023 build_prop.append(
2024 'import /odm/etc/build_${ro.boot.product.product_name}.prop')
2025
2026 build_std_prop = [
2027 'ro.product.odm.device=coral',
2028 ]
2029 build_pro_prop = [
2030 'ro.product.odm.device=coralpro',
2031 ]
2032
2033 product1_prop = [
2034 'ro.product.odm.name=product1',
2035 'ro.product.not_care=not_care',
2036 ]
2037
2038 product2_prop = [
2039 'ro.product.odm.name=product2',
2040 'ro.product.not_care=not_care',
2041 ]
2042
2043 input_file = self._BuildZipFile({
2044 'ODM/etc/build.prop': '\n'.join(build_prop),
2045 'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2046 'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2047 'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
2048 'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
2049 })
2050
Kelvin Zhang928c2342020-09-22 16:15:57 -04002051 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00002052 placeholder_values = {
2053 'ro.boot.product.device_name': 'std',
2054 'ro.boot.product.product_name': 'product1',
2055 'ro.boot.product.not_care': 'not_care',
2056 }
2057 partition_props = common.PartitionBuildProps.FromInputFile(
2058 input_zip, 'odm', placeholder_values)
2059
2060 self.assertEqual({
2061 'ro.odm.build.date.utc': '1578430045',
2062 'ro.odm.build.fingerprint':
2063 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2064 'ro.product.odm.device': 'coral',
2065 'ro.product.odm.name': 'product1'
2066 }, partition_props.build_props)
2067
Kelvin Zhang928c2342020-09-22 16:15:57 -04002068 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00002069 placeholder_values = {
2070 'ro.boot.product.device_name': 'pro',
2071 'ro.boot.product.product_name': 'product2',
2072 'ro.boot.product.not_care': 'not_care',
2073 }
2074 partition_props = common.PartitionBuildProps.FromInputFile(
2075 input_zip, 'odm', placeholder_values)
2076
2077 self.assertEqual({
2078 'ro.odm.build.date.utc': '1578430045',
2079 'ro.odm.build.fingerprint':
2080 'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2081 'ro.product.odm.device': 'coralpro',
2082 'ro.product.odm.name': 'product2'
2083 }, partition_props.build_props)
2084
2085 def test_parseBuildProps_defineAfterOverride(self):
2086 build_prop = copy.deepcopy(self.odm_build_prop)
2087 build_prop.append('ro.product.odm.device=coral')
2088
2089 build_std_prop = [
2090 'ro.product.odm.device=coral',
2091 ]
2092 build_pro_prop = [
2093 'ro.product.odm.device=coralpro',
2094 ]
2095
2096 input_file = self._BuildZipFile({
2097 'ODM/etc/build.prop': '\n'.join(build_prop),
2098 'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2099 'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2100 })
2101
Kelvin Zhang928c2342020-09-22 16:15:57 -04002102 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00002103 placeholder_values = {
2104 'ro.boot.product.device_name': 'std',
2105 }
2106
2107 self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
2108 input_zip, 'odm', placeholder_values)
2109
2110 def test_parseBuildProps_duplicateOverride(self):
2111 build_prop = copy.deepcopy(self.odm_build_prop)
2112 build_prop.append(
2113 'import /odm/etc/build_${ro.boot.product.product_name}.prop')
2114
2115 build_std_prop = [
2116 'ro.product.odm.device=coral',
2117 'ro.product.odm.name=product1',
2118 ]
2119 build_pro_prop = [
2120 'ro.product.odm.device=coralpro',
2121 ]
2122
2123 product1_prop = [
2124 'ro.product.odm.name=product1',
2125 ]
2126
2127 product2_prop = [
2128 'ro.product.odm.name=product2',
2129 ]
2130
2131 input_file = self._BuildZipFile({
2132 'ODM/etc/build.prop': '\n'.join(build_prop),
2133 'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2134 'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2135 'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
2136 'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
2137 })
2138
Kelvin Zhang928c2342020-09-22 16:15:57 -04002139 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
Tianjie Xu9afb2212020-05-10 21:48:15 +00002140 placeholder_values = {
2141 'ro.boot.product.device_name': 'std',
2142 'ro.boot.product.product_name': 'product1',
2143 }
2144 self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
2145 input_zip, 'odm', placeholder_values)