blob: da9216369ee057757aa0f2ded6fa3a01b1b408f6 [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
Dan Albert8e0178d2015-01-27 15:53:15 -080022import zipfile
Tao Bao31b08072017-11-08 15:50:59 -080023from hashlib import sha1
24
Dan Albert8e0178d2015-01-27 15:53:15 -080025import common
Tao Bao04e1f012018-02-04 12:13:35 -080026import test_utils
Tianjie Xu9c384d22017-06-20 17:00:55 -070027import validate_target_files
Tianjie Xu41976c72019-07-03 13:57:01 -070028from images import EmptyImage, DataImage
Tao Baofc7e0e02018-02-13 13:54:02 -080029from rangelib import RangeSet
Dan Albert8e0178d2015-01-27 15:53:15 -080030
Tao Bao04e1f012018-02-04 12:13:35 -080031
Tao Bao31b08072017-11-08 15:50:59 -080032KiB = 1024
33MiB = 1024 * KiB
34GiB = 1024 * MiB
Dan Albert8e0178d2015-01-27 15:53:15 -080035
Tao Bao1c830bf2017-12-25 10:43:47 -080036
Tao Baof3282b42015-04-01 11:21:55 -070037def get_2gb_string():
Tao Bao31b08072017-11-08 15:50:59 -080038 size = int(2 * GiB + 1)
39 block_size = 4 * KiB
40 step_size = 4 * MiB
41 # Generate a long string with holes, e.g. 'xyz\x00abc\x00...'.
42 for _ in range(0, size, step_size):
43 yield os.urandom(block_size)
Tao Baoc1a1ec32019-06-18 16:29:37 -070044 yield b'\0' * (step_size - block_size)
Tao Baof3282b42015-04-01 11:21:55 -070045
Dan Albert8e0178d2015-01-27 15:53:15 -080046
Tao Bao1c320f82019-10-04 23:25:12 -070047class BuildInfoTest(test_utils.ReleaseToolsTestCase):
48
49 TEST_INFO_DICT = {
50 'build.prop' : {
51 'ro.product.device' : 'product-device',
52 'ro.product.name' : 'product-name',
53 'ro.build.fingerprint' : 'build-fingerprint',
54 'ro.build.foo' : 'build-foo',
55 },
Daniel Normand5fe8622020-01-08 17:01:11 -080056 'system.build.prop' : {
57 'ro.product.system.brand' : 'product-brand',
58 'ro.product.system.name' : 'product-name',
59 'ro.product.system.device' : 'product-device',
60 'ro.system.build.version.release' : 'version-release',
61 'ro.system.build.id' : 'build-id',
62 'ro.system.build.version.incremental' : 'version-incremental',
63 'ro.system.build.type' : 'build-type',
64 'ro.system.build.tags' : 'build-tags',
65 'ro.system.build.foo' : 'build-foo',
66 },
Tao Bao1c320f82019-10-04 23:25:12 -070067 'vendor.build.prop' : {
Daniel Normand5fe8622020-01-08 17:01:11 -080068 'ro.product.vendor.brand' : 'vendor-product-brand',
69 'ro.product.vendor.name' : 'vendor-product-name',
70 'ro.product.vendor.device' : 'vendor-product-device',
71 'ro.vendor.build.version.release' : 'vendor-version-release',
72 'ro.vendor.build.id' : 'vendor-build-id',
73 'ro.vendor.build.version.incremental' : 'vendor-version-incremental',
74 'ro.vendor.build.type' : 'vendor-build-type',
75 'ro.vendor.build.tags' : 'vendor-build-tags',
Tao Bao1c320f82019-10-04 23:25:12 -070076 },
77 'property1' : 'value1',
78 'property2' : 4096,
79 }
80
81 TEST_INFO_DICT_USES_OEM_PROPS = {
82 'build.prop' : {
83 'ro.product.name' : 'product-name',
84 'ro.build.thumbprint' : 'build-thumbprint',
85 'ro.build.bar' : 'build-bar',
86 },
87 'vendor.build.prop' : {
88 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
89 },
90 'property1' : 'value1',
91 'property2' : 4096,
92 'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
93 }
94
95 TEST_OEM_DICTS = [
96 {
97 'ro.product.brand' : 'brand1',
98 'ro.product.device' : 'device1',
99 },
100 {
101 'ro.product.brand' : 'brand2',
102 'ro.product.device' : 'device2',
103 },
104 {
105 'ro.product.brand' : 'brand3',
106 'ro.product.device' : 'device3',
107 },
108 ]
109
110 def test_init(self):
111 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
112 self.assertEqual('product-device', target_info.device)
113 self.assertEqual('build-fingerprint', target_info.fingerprint)
114 self.assertFalse(target_info.is_ab)
115 self.assertIsNone(target_info.oem_props)
116
117 def test_init_with_oem_props(self):
118 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
119 self.TEST_OEM_DICTS)
120 self.assertEqual('device1', target_info.device)
121 self.assertEqual('brand1/product-name/device1:build-thumbprint',
122 target_info.fingerprint)
123
124 # Swap the order in oem_dicts, which would lead to different BuildInfo.
125 oem_dicts = copy.copy(self.TEST_OEM_DICTS)
126 oem_dicts[0], oem_dicts[2] = oem_dicts[2], oem_dicts[0]
127 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
128 oem_dicts)
129 self.assertEqual('device3', target_info.device)
130 self.assertEqual('brand3/product-name/device3:build-thumbprint',
131 target_info.fingerprint)
132
133 # Missing oem_dict should be rejected.
134 self.assertRaises(AssertionError, common.BuildInfo,
135 self.TEST_INFO_DICT_USES_OEM_PROPS, None)
136
137 def test_init_badFingerprint(self):
138 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
139 info_dict['build.prop']['ro.build.fingerprint'] = 'bad fingerprint'
140 self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
141
142 info_dict['build.prop']['ro.build.fingerprint'] = 'bad\x80fingerprint'
143 self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
144
145 def test___getitem__(self):
146 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
147 self.assertEqual('value1', target_info['property1'])
148 self.assertEqual(4096, target_info['property2'])
149 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
150
151 def test___getitem__with_oem_props(self):
152 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
153 self.TEST_OEM_DICTS)
154 self.assertEqual('value1', target_info['property1'])
155 self.assertEqual(4096, target_info['property2'])
156 self.assertRaises(KeyError,
157 lambda: target_info['build.prop']['ro.build.foo'])
158
159 def test___setitem__(self):
160 target_info = common.BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
161 self.assertEqual('value1', target_info['property1'])
162 target_info['property1'] = 'value2'
163 self.assertEqual('value2', target_info['property1'])
164
165 self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
166 target_info['build.prop']['ro.build.foo'] = 'build-bar'
167 self.assertEqual('build-bar', target_info['build.prop']['ro.build.foo'])
168
169 def test_get(self):
170 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
171 self.assertEqual('value1', target_info.get('property1'))
172 self.assertEqual(4096, target_info.get('property2'))
173 self.assertEqual(4096, target_info.get('property2', 1024))
174 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
175 self.assertEqual('build-foo', target_info.get('build.prop')['ro.build.foo'])
176
177 def test_get_with_oem_props(self):
178 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
179 self.TEST_OEM_DICTS)
180 self.assertEqual('value1', target_info.get('property1'))
181 self.assertEqual(4096, target_info.get('property2'))
182 self.assertEqual(4096, target_info.get('property2', 1024))
183 self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
184 self.assertIsNone(target_info.get('build.prop').get('ro.build.foo'))
185 self.assertRaises(KeyError,
186 lambda: target_info.get('build.prop')['ro.build.foo'])
187
188 def test_items(self):
189 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
190 items = target_info.items()
191 self.assertIn(('property1', 'value1'), items)
192 self.assertIn(('property2', 4096), items)
193
194 def test_GetBuildProp(self):
195 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
196 self.assertEqual('build-foo', target_info.GetBuildProp('ro.build.foo'))
197 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
198 'ro.build.nonexistent')
199
200 def test_GetBuildProp_with_oem_props(self):
201 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
202 self.TEST_OEM_DICTS)
203 self.assertEqual('build-bar', target_info.GetBuildProp('ro.build.bar'))
204 self.assertRaises(common.ExternalError, target_info.GetBuildProp,
205 'ro.build.nonexistent')
206
Daniel Normand5fe8622020-01-08 17:01:11 -0800207 def test_GetPartitionFingerprint(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700208 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
Daniel Normand5fe8622020-01-08 17:01:11 -0800209 self.assertEqual(
210 target_info.GetPartitionFingerprint('vendor'),
211 'vendor-product-brand/vendor-product-name/vendor-product-device'
212 ':vendor-version-release/vendor-build-id/vendor-version-incremental'
213 ':vendor-build-type/vendor-build-tags')
Tao Bao1c320f82019-10-04 23:25:12 -0700214
Daniel Normand5fe8622020-01-08 17:01:11 -0800215 def test_GetPartitionFingerprint_system_other_uses_system(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700216 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
Daniel Normand5fe8622020-01-08 17:01:11 -0800217 self.assertEqual(
218 target_info.GetPartitionFingerprint('system_other'),
219 target_info.GetPartitionFingerprint('system'))
Tao Bao1c320f82019-10-04 23:25:12 -0700220
Daniel Normand5fe8622020-01-08 17:01:11 -0800221 def test_GetPartitionFingerprint_uses_fingerprint_prop_if_available(self):
222 info_dict = copy.deepcopy(self.TEST_INFO_DICT)
223 info_dict['vendor.build.prop']['ro.vendor.build.fingerprint'] = 'vendor:fingerprint'
224 target_info = common.BuildInfo(info_dict, None)
225 self.assertEqual(
226 target_info.GetPartitionFingerprint('vendor'),
227 'vendor:fingerprint')
Tao Bao1c320f82019-10-04 23:25:12 -0700228
229 def test_WriteMountOemScript(self):
230 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
231 self.TEST_OEM_DICTS)
232 script_writer = test_utils.MockScriptWriter()
233 target_info.WriteMountOemScript(script_writer)
234 self.assertEqual([('Mount', '/oem', None)], script_writer.lines)
235
236 def test_WriteDeviceAssertions(self):
237 target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
238 script_writer = test_utils.MockScriptWriter()
239 target_info.WriteDeviceAssertions(script_writer, False)
240 self.assertEqual([('AssertDevice', 'product-device')], script_writer.lines)
241
242 def test_WriteDeviceAssertions_with_oem_props(self):
243 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
244 self.TEST_OEM_DICTS)
245 script_writer = test_utils.MockScriptWriter()
246 target_info.WriteDeviceAssertions(script_writer, False)
247 self.assertEqual(
248 [
249 ('AssertOemProperty', 'ro.product.device',
250 ['device1', 'device2', 'device3'], False),
251 ('AssertOemProperty', 'ro.product.brand',
252 ['brand1', 'brand2', 'brand3'], False),
253 ],
254 script_writer.lines)
255
256
Tao Bao65b94e92018-10-11 21:57:26 -0700257class CommonZipTest(test_utils.ReleaseToolsTestCase):
258
Tao Bao31b08072017-11-08 15:50:59 -0800259 def _verify(self, zip_file, zip_file_name, arcname, expected_hash,
Tao Baof3282b42015-04-01 11:21:55 -0700260 test_file_name=None, expected_stat=None, expected_mode=0o644,
261 expected_compress_type=zipfile.ZIP_STORED):
262 # Verify the stat if present.
263 if test_file_name is not None:
264 new_stat = os.stat(test_file_name)
265 self.assertEqual(int(expected_stat.st_mode), int(new_stat.st_mode))
266 self.assertEqual(int(expected_stat.st_mtime), int(new_stat.st_mtime))
267
268 # Reopen the zip file to verify.
269 zip_file = zipfile.ZipFile(zip_file_name, "r")
270
271 # Verify the timestamp.
272 info = zip_file.getinfo(arcname)
273 self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0))
274
275 # Verify the file mode.
276 mode = (info.external_attr >> 16) & 0o777
277 self.assertEqual(mode, expected_mode)
278
279 # Verify the compress type.
280 self.assertEqual(info.compress_type, expected_compress_type)
281
282 # Verify the zip contents.
Tao Bao31b08072017-11-08 15:50:59 -0800283 entry = zip_file.open(arcname)
284 sha1_hash = sha1()
Tao Baoc1a1ec32019-06-18 16:29:37 -0700285 for chunk in iter(lambda: entry.read(4 * MiB), b''):
Tao Bao31b08072017-11-08 15:50:59 -0800286 sha1_hash.update(chunk)
287 self.assertEqual(expected_hash, sha1_hash.hexdigest())
Tao Baof3282b42015-04-01 11:21:55 -0700288 self.assertIsNone(zip_file.testzip())
289
Dan Albert8e0178d2015-01-27 15:53:15 -0800290 def _test_ZipWrite(self, contents, extra_zipwrite_args=None):
291 extra_zipwrite_args = dict(extra_zipwrite_args or {})
292
293 test_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -0800294 test_file_name = test_file.name
Tao Baof3282b42015-04-01 11:21:55 -0700295
296 zip_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -0800297 zip_file_name = zip_file.name
298
299 # File names within an archive strip the leading slash.
300 arcname = extra_zipwrite_args.get("arcname", test_file_name)
301 if arcname[0] == "/":
302 arcname = arcname[1:]
303
304 zip_file.close()
305 zip_file = zipfile.ZipFile(zip_file_name, "w")
306
307 try:
Tao Bao31b08072017-11-08 15:50:59 -0800308 sha1_hash = sha1()
309 for data in contents:
Tao Baoc1a1ec32019-06-18 16:29:37 -0700310 sha1_hash.update(bytes(data))
311 test_file.write(bytes(data))
Dan Albert8e0178d2015-01-27 15:53:15 -0800312 test_file.close()
313
Tao Baof3282b42015-04-01 11:21:55 -0700314 expected_stat = os.stat(test_file_name)
Dan Albert8e0178d2015-01-27 15:53:15 -0800315 expected_mode = extra_zipwrite_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700316 expected_compress_type = extra_zipwrite_args.get("compress_type",
317 zipfile.ZIP_STORED)
Dan Albert8e0178d2015-01-27 15:53:15 -0800318 time.sleep(5) # Make sure the atime/mtime will change measurably.
319
320 common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
Tao Baof3282b42015-04-01 11:21:55 -0700321 common.ZipClose(zip_file)
Dan Albert8e0178d2015-01-27 15:53:15 -0800322
Tao Bao31b08072017-11-08 15:50:59 -0800323 self._verify(zip_file, zip_file_name, arcname, sha1_hash.hexdigest(),
324 test_file_name, expected_stat, expected_mode,
325 expected_compress_type)
Dan Albert8e0178d2015-01-27 15:53:15 -0800326 finally:
327 os.remove(test_file_name)
328 os.remove(zip_file_name)
329
Tao Baof3282b42015-04-01 11:21:55 -0700330 def _test_ZipWriteStr(self, zinfo_or_arcname, contents, extra_args=None):
331 extra_args = dict(extra_args or {})
332
333 zip_file = tempfile.NamedTemporaryFile(delete=False)
334 zip_file_name = zip_file.name
335 zip_file.close()
336
337 zip_file = zipfile.ZipFile(zip_file_name, "w")
338
339 try:
340 expected_compress_type = extra_args.get("compress_type",
341 zipfile.ZIP_STORED)
342 time.sleep(5) # Make sure the atime/mtime will change measurably.
343
344 if not isinstance(zinfo_or_arcname, zipfile.ZipInfo):
Tao Bao58c1b962015-05-20 09:32:18 -0700345 arcname = zinfo_or_arcname
346 expected_mode = extra_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700347 else:
Tao Bao58c1b962015-05-20 09:32:18 -0700348 arcname = zinfo_or_arcname.filename
Tao Baoc1a1ec32019-06-18 16:29:37 -0700349 if zinfo_or_arcname.external_attr:
350 zinfo_perms = zinfo_or_arcname.external_attr >> 16
351 else:
352 zinfo_perms = 0o600
353 expected_mode = extra_args.get("perms", zinfo_perms)
Tao Baof3282b42015-04-01 11:21:55 -0700354
Tao Bao58c1b962015-05-20 09:32:18 -0700355 common.ZipWriteStr(zip_file, zinfo_or_arcname, contents, **extra_args)
Tao Baof3282b42015-04-01 11:21:55 -0700356 common.ZipClose(zip_file)
357
Tao Bao31b08072017-11-08 15:50:59 -0800358 self._verify(zip_file, zip_file_name, arcname, sha1(contents).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700359 expected_mode=expected_mode,
Tao Baof3282b42015-04-01 11:21:55 -0700360 expected_compress_type=expected_compress_type)
361 finally:
362 os.remove(zip_file_name)
363
364 def _test_ZipWriteStr_large_file(self, large, small, extra_args=None):
365 extra_args = dict(extra_args or {})
366
367 zip_file = tempfile.NamedTemporaryFile(delete=False)
368 zip_file_name = zip_file.name
369
370 test_file = tempfile.NamedTemporaryFile(delete=False)
371 test_file_name = test_file.name
372
373 arcname_large = test_file_name
374 arcname_small = "bar"
375
376 # File names within an archive strip the leading slash.
377 if arcname_large[0] == "/":
378 arcname_large = arcname_large[1:]
379
380 zip_file.close()
381 zip_file = zipfile.ZipFile(zip_file_name, "w")
382
383 try:
Tao Bao31b08072017-11-08 15:50:59 -0800384 sha1_hash = sha1()
385 for data in large:
386 sha1_hash.update(data)
387 test_file.write(data)
Tao Baof3282b42015-04-01 11:21:55 -0700388 test_file.close()
389
390 expected_stat = os.stat(test_file_name)
391 expected_mode = 0o644
392 expected_compress_type = extra_args.get("compress_type",
393 zipfile.ZIP_STORED)
394 time.sleep(5) # Make sure the atime/mtime will change measurably.
395
396 common.ZipWrite(zip_file, test_file_name, **extra_args)
397 common.ZipWriteStr(zip_file, arcname_small, small, **extra_args)
398 common.ZipClose(zip_file)
399
400 # Verify the contents written by ZipWrite().
Tao Bao31b08072017-11-08 15:50:59 -0800401 self._verify(zip_file, zip_file_name, arcname_large,
402 sha1_hash.hexdigest(), test_file_name, expected_stat,
403 expected_mode, expected_compress_type)
Tao Baof3282b42015-04-01 11:21:55 -0700404
405 # Verify the contents written by ZipWriteStr().
Tao Bao31b08072017-11-08 15:50:59 -0800406 self._verify(zip_file, zip_file_name, arcname_small,
407 sha1(small).hexdigest(),
Tao Baof3282b42015-04-01 11:21:55 -0700408 expected_compress_type=expected_compress_type)
409 finally:
410 os.remove(zip_file_name)
411 os.remove(test_file_name)
412
413 def _test_reset_ZIP64_LIMIT(self, func, *args):
414 default_limit = (1 << 31) - 1
415 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
416 func(*args)
417 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
418
Dan Albert8e0178d2015-01-27 15:53:15 -0800419 def test_ZipWrite(self):
420 file_contents = os.urandom(1024)
421 self._test_ZipWrite(file_contents)
422
423 def test_ZipWrite_with_opts(self):
424 file_contents = os.urandom(1024)
425 self._test_ZipWrite(file_contents, {
426 "arcname": "foobar",
427 "perms": 0o777,
428 "compress_type": zipfile.ZIP_DEFLATED,
429 })
Tao Baof3282b42015-04-01 11:21:55 -0700430 self._test_ZipWrite(file_contents, {
431 "arcname": "foobar",
432 "perms": 0o700,
433 "compress_type": zipfile.ZIP_STORED,
434 })
Dan Albert8e0178d2015-01-27 15:53:15 -0800435
436 def test_ZipWrite_large_file(self):
Tao Baof3282b42015-04-01 11:21:55 -0700437 file_contents = get_2gb_string()
Dan Albert8e0178d2015-01-27 15:53:15 -0800438 self._test_ZipWrite(file_contents, {
439 "compress_type": zipfile.ZIP_DEFLATED,
440 })
441
442 def test_ZipWrite_resets_ZIP64_LIMIT(self):
Tao Baof3282b42015-04-01 11:21:55 -0700443 self._test_reset_ZIP64_LIMIT(self._test_ZipWrite, "")
444
445 def test_ZipWriteStr(self):
446 random_string = os.urandom(1024)
447 # Passing arcname
448 self._test_ZipWriteStr("foo", random_string)
449
450 # Passing zinfo
451 zinfo = zipfile.ZipInfo(filename="foo")
452 self._test_ZipWriteStr(zinfo, random_string)
453
454 # Timestamp in the zinfo should be overwritten.
455 zinfo.date_time = (2015, 3, 1, 15, 30, 0)
456 self._test_ZipWriteStr(zinfo, random_string)
457
458 def test_ZipWriteStr_with_opts(self):
459 random_string = os.urandom(1024)
460 # Passing arcname
461 self._test_ZipWriteStr("foo", random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700462 "perms": 0o700,
Tao Baof3282b42015-04-01 11:21:55 -0700463 "compress_type": zipfile.ZIP_DEFLATED,
464 })
Tao Bao58c1b962015-05-20 09:32:18 -0700465 self._test_ZipWriteStr("bar", random_string, {
Tao Baof3282b42015-04-01 11:21:55 -0700466 "compress_type": zipfile.ZIP_STORED,
467 })
468
469 # Passing zinfo
470 zinfo = zipfile.ZipInfo(filename="foo")
471 self._test_ZipWriteStr(zinfo, random_string, {
472 "compress_type": zipfile.ZIP_DEFLATED,
473 })
474 self._test_ZipWriteStr(zinfo, random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700475 "perms": 0o600,
Tao Baof3282b42015-04-01 11:21:55 -0700476 "compress_type": zipfile.ZIP_STORED,
477 })
Tao Baoc1a1ec32019-06-18 16:29:37 -0700478 self._test_ZipWriteStr(zinfo, random_string, {
479 "perms": 0o000,
480 "compress_type": zipfile.ZIP_STORED,
481 })
Tao Baof3282b42015-04-01 11:21:55 -0700482
483 def test_ZipWriteStr_large_file(self):
484 # zipfile.writestr() doesn't work when the str size is over 2GiB even with
485 # the workaround. We will only test the case of writing a string into a
486 # large archive.
487 long_string = get_2gb_string()
488 short_string = os.urandom(1024)
489 self._test_ZipWriteStr_large_file(long_string, short_string, {
490 "compress_type": zipfile.ZIP_DEFLATED,
491 })
492
493 def test_ZipWriteStr_resets_ZIP64_LIMIT(self):
Tao Baoc1a1ec32019-06-18 16:29:37 -0700494 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, 'foo', b'')
Tao Baof3282b42015-04-01 11:21:55 -0700495 zinfo = zipfile.ZipInfo(filename="foo")
Tao Baoc1a1ec32019-06-18 16:29:37 -0700496 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, zinfo, b'')
Tao Bao58c1b962015-05-20 09:32:18 -0700497
498 def test_bug21309935(self):
499 zip_file = tempfile.NamedTemporaryFile(delete=False)
500 zip_file_name = zip_file.name
501 zip_file.close()
502
503 try:
504 random_string = os.urandom(1024)
505 zip_file = zipfile.ZipFile(zip_file_name, "w")
506 # Default perms should be 0o644 when passing the filename.
507 common.ZipWriteStr(zip_file, "foo", random_string)
508 # Honor the specified perms.
509 common.ZipWriteStr(zip_file, "bar", random_string, perms=0o755)
510 # The perms in zinfo should be untouched.
511 zinfo = zipfile.ZipInfo(filename="baz")
512 zinfo.external_attr = 0o740 << 16
513 common.ZipWriteStr(zip_file, zinfo, random_string)
514 # Explicitly specified perms has the priority.
515 zinfo = zipfile.ZipInfo(filename="qux")
516 zinfo.external_attr = 0o700 << 16
517 common.ZipWriteStr(zip_file, zinfo, random_string, perms=0o400)
518 common.ZipClose(zip_file)
519
Tao Bao31b08072017-11-08 15:50:59 -0800520 self._verify(zip_file, zip_file_name, "foo",
521 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700522 expected_mode=0o644)
Tao Bao31b08072017-11-08 15:50:59 -0800523 self._verify(zip_file, zip_file_name, "bar",
524 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700525 expected_mode=0o755)
Tao Bao31b08072017-11-08 15:50:59 -0800526 self._verify(zip_file, zip_file_name, "baz",
527 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700528 expected_mode=0o740)
Tao Bao31b08072017-11-08 15:50:59 -0800529 self._verify(zip_file, zip_file_name, "qux",
530 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700531 expected_mode=0o400)
532 finally:
533 os.remove(zip_file_name)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700534
Tao Bao82490d32019-04-09 00:12:30 -0700535 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao89d7ab22017-12-14 17:05:33 -0800536 def test_ZipDelete(self):
537 zip_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
538 output_zip = zipfile.ZipFile(zip_file.name, 'w',
539 compression=zipfile.ZIP_DEFLATED)
540 with tempfile.NamedTemporaryFile() as entry_file:
541 entry_file.write(os.urandom(1024))
542 common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
543 common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
544 common.ZipWrite(output_zip, entry_file.name, arcname='Test3')
545 common.ZipClose(output_zip)
546 zip_file.close()
547
548 try:
549 common.ZipDelete(zip_file.name, 'Test2')
550 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
551 entries = check_zip.namelist()
552 self.assertTrue('Test1' in entries)
553 self.assertFalse('Test2' in entries)
554 self.assertTrue('Test3' in entries)
555
Tao Bao986ee862018-10-04 15:46:16 -0700556 self.assertRaises(
557 common.ExternalError, common.ZipDelete, zip_file.name, 'Test2')
Tao Bao89d7ab22017-12-14 17:05:33 -0800558 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
559 entries = check_zip.namelist()
560 self.assertTrue('Test1' in entries)
561 self.assertFalse('Test2' in entries)
562 self.assertTrue('Test3' in entries)
563
564 common.ZipDelete(zip_file.name, ['Test3'])
565 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
566 entries = check_zip.namelist()
567 self.assertTrue('Test1' in entries)
568 self.assertFalse('Test2' in entries)
569 self.assertFalse('Test3' in entries)
570
571 common.ZipDelete(zip_file.name, ['Test1', 'Test2'])
572 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
573 entries = check_zip.namelist()
574 self.assertFalse('Test1' in entries)
575 self.assertFalse('Test2' in entries)
576 self.assertFalse('Test3' in entries)
577 finally:
578 os.remove(zip_file.name)
579
Tao Bao0ff15de2019-03-20 11:26:06 -0700580 @staticmethod
581 def _test_UnzipTemp_createZipFile():
582 zip_file = common.MakeTempFile(suffix='.zip')
583 output_zip = zipfile.ZipFile(
584 zip_file, 'w', compression=zipfile.ZIP_DEFLATED)
585 contents = os.urandom(1024)
586 with tempfile.NamedTemporaryFile() as entry_file:
587 entry_file.write(contents)
588 common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
589 common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
590 common.ZipWrite(output_zip, entry_file.name, arcname='Foo3')
591 common.ZipWrite(output_zip, entry_file.name, arcname='Bar4')
592 common.ZipWrite(output_zip, entry_file.name, arcname='Dir5/Baz5')
593 common.ZipClose(output_zip)
594 common.ZipClose(output_zip)
595 return zip_file
596
Tao Bao82490d32019-04-09 00:12:30 -0700597 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700598 def test_UnzipTemp(self):
599 zip_file = self._test_UnzipTemp_createZipFile()
600 unzipped_dir = common.UnzipTemp(zip_file)
601 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
602 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
603 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
604 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
605 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
606
Tao Bao82490d32019-04-09 00:12:30 -0700607 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700608 def test_UnzipTemp_withPatterns(self):
609 zip_file = self._test_UnzipTemp_createZipFile()
610
611 unzipped_dir = common.UnzipTemp(zip_file, ['Test1'])
612 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
613 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
614 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
615 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
616 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
617
618 unzipped_dir = common.UnzipTemp(zip_file, ['Test1', 'Foo3'])
619 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
620 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
621 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
622 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
623 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
624
625 unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Foo3*'])
626 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
627 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
628 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
629 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
630 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
631
632 unzipped_dir = common.UnzipTemp(zip_file, ['*Test1', '*Baz*'])
633 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
634 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
635 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
636 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
637 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
638
639 def test_UnzipTemp_withEmptyPatterns(self):
640 zip_file = self._test_UnzipTemp_createZipFile()
641 unzipped_dir = common.UnzipTemp(zip_file, [])
642 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
643 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
644 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
645 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
646 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
647
Tao Bao82490d32019-04-09 00:12:30 -0700648 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao0ff15de2019-03-20 11:26:06 -0700649 def test_UnzipTemp_withPartiallyMatchingPatterns(self):
650 zip_file = self._test_UnzipTemp_createZipFile()
651 unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Nonexistent*'])
652 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
653 self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
654 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
655 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
656 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
657
658 def test_UnzipTemp_withNoMatchingPatterns(self):
659 zip_file = self._test_UnzipTemp_createZipFile()
660 unzipped_dir = common.UnzipTemp(zip_file, ['Foo4', 'Nonexistent*'])
661 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
662 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
663 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
664 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
665 self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
666
Tao Bao89d7ab22017-12-14 17:05:33 -0800667
Tao Bao65b94e92018-10-11 21:57:26 -0700668class CommonApkUtilsTest(test_utils.ReleaseToolsTestCase):
Tao Bao818ddf52018-01-05 11:17:34 -0800669 """Tests the APK utils related functions."""
670
671 APKCERTS_TXT1 = (
672 'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
673 ' private_key="certs/devkey.pk8"\n'
674 'name="Settings.apk"'
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700675 ' certificate="build/make/target/product/security/platform.x509.pem"'
676 ' private_key="build/make/target/product/security/platform.pk8"\n'
Tao Bao818ddf52018-01-05 11:17:34 -0800677 'name="TV.apk" certificate="PRESIGNED" private_key=""\n'
678 )
679
680 APKCERTS_CERTMAP1 = {
681 'RecoveryLocalizer.apk' : 'certs/devkey',
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700682 'Settings.apk' : 'build/make/target/product/security/platform',
Tao Bao818ddf52018-01-05 11:17:34 -0800683 'TV.apk' : 'PRESIGNED',
684 }
685
686 APKCERTS_TXT2 = (
687 'name="Compressed1.apk" certificate="certs/compressed1.x509.pem"'
688 ' private_key="certs/compressed1.pk8" compressed="gz"\n'
689 'name="Compressed2a.apk" certificate="certs/compressed2.x509.pem"'
690 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
691 'name="Compressed2b.apk" certificate="certs/compressed2.x509.pem"'
692 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
693 'name="Compressed3.apk" certificate="certs/compressed3.x509.pem"'
694 ' private_key="certs/compressed3.pk8" compressed="gz"\n'
695 )
696
697 APKCERTS_CERTMAP2 = {
698 'Compressed1.apk' : 'certs/compressed1',
699 'Compressed2a.apk' : 'certs/compressed2',
700 'Compressed2b.apk' : 'certs/compressed2',
701 'Compressed3.apk' : 'certs/compressed3',
702 }
703
704 APKCERTS_TXT3 = (
705 'name="Compressed4.apk" certificate="certs/compressed4.x509.pem"'
706 ' private_key="certs/compressed4.pk8" compressed="xz"\n'
707 )
708
709 APKCERTS_CERTMAP3 = {
710 'Compressed4.apk' : 'certs/compressed4',
711 }
712
Tao Bao17e4e612018-02-16 17:12:54 -0800713 def setUp(self):
714 self.testdata_dir = test_utils.get_testdata_dir()
715
Tao Bao818ddf52018-01-05 11:17:34 -0800716 @staticmethod
717 def _write_apkcerts_txt(apkcerts_txt, additional=None):
718 if additional is None:
719 additional = []
720 target_files = common.MakeTempFile(suffix='.zip')
721 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
722 target_files_zip.writestr('META/apkcerts.txt', apkcerts_txt)
723 for entry in additional:
724 target_files_zip.writestr(entry, '')
725 return target_files
726
727 def test_ReadApkCerts_NoncompressedApks(self):
728 target_files = self._write_apkcerts_txt(self.APKCERTS_TXT1)
729 with zipfile.ZipFile(target_files, 'r') as input_zip:
730 certmap, ext = common.ReadApkCerts(input_zip)
731
732 self.assertDictEqual(self.APKCERTS_CERTMAP1, certmap)
733 self.assertIsNone(ext)
734
735 def test_ReadApkCerts_CompressedApks(self):
736 # We have "installed" Compressed1.apk.gz only. Note that Compressed3.apk is
737 # not stored in '.gz' format, so it shouldn't be considered as installed.
738 target_files = self._write_apkcerts_txt(
739 self.APKCERTS_TXT2,
740 ['Compressed1.apk.gz', 'Compressed3.apk'])
741
742 with zipfile.ZipFile(target_files, 'r') as input_zip:
743 certmap, ext = common.ReadApkCerts(input_zip)
744
745 self.assertDictEqual(self.APKCERTS_CERTMAP2, certmap)
746 self.assertEqual('.gz', ext)
747
748 # Alternative case with '.xz'.
749 target_files = self._write_apkcerts_txt(
750 self.APKCERTS_TXT3, ['Compressed4.apk.xz'])
751
752 with zipfile.ZipFile(target_files, 'r') as input_zip:
753 certmap, ext = common.ReadApkCerts(input_zip)
754
755 self.assertDictEqual(self.APKCERTS_CERTMAP3, certmap)
756 self.assertEqual('.xz', ext)
757
758 def test_ReadApkCerts_CompressedAndNoncompressedApks(self):
759 target_files = self._write_apkcerts_txt(
760 self.APKCERTS_TXT1 + self.APKCERTS_TXT2,
761 ['Compressed1.apk.gz', 'Compressed3.apk'])
762
763 with zipfile.ZipFile(target_files, 'r') as input_zip:
764 certmap, ext = common.ReadApkCerts(input_zip)
765
766 certmap_merged = self.APKCERTS_CERTMAP1.copy()
767 certmap_merged.update(self.APKCERTS_CERTMAP2)
768 self.assertDictEqual(certmap_merged, certmap)
769 self.assertEqual('.gz', ext)
770
771 def test_ReadApkCerts_MultipleCompressionMethods(self):
772 target_files = self._write_apkcerts_txt(
773 self.APKCERTS_TXT2 + self.APKCERTS_TXT3,
774 ['Compressed1.apk.gz', 'Compressed4.apk.xz'])
775
776 with zipfile.ZipFile(target_files, 'r') as input_zip:
777 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
778
779 def test_ReadApkCerts_MismatchingKeys(self):
780 malformed_apkcerts_txt = (
781 'name="App1.apk" certificate="certs/cert1.x509.pem"'
782 ' private_key="certs/cert2.pk8"\n'
783 )
784 target_files = self._write_apkcerts_txt(malformed_apkcerts_txt)
785
786 with zipfile.ZipFile(target_files, 'r') as input_zip:
787 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
788
Tao Bao04e1f012018-02-04 12:13:35 -0800789 def test_ExtractPublicKey(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800790 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
791 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
Tao Baoda30cfa2017-12-01 16:19:46 -0800792 with open(pubkey) as pubkey_fp:
Tao Bao04e1f012018-02-04 12:13:35 -0800793 self.assertEqual(pubkey_fp.read(), common.ExtractPublicKey(cert))
794
795 def test_ExtractPublicKey_invalidInput(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800796 wrong_input = os.path.join(self.testdata_dir, 'testkey.pk8')
Tao Bao04e1f012018-02-04 12:13:35 -0800797 self.assertRaises(AssertionError, common.ExtractPublicKey, wrong_input)
798
Tao Bao82490d32019-04-09 00:12:30 -0700799 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao2cc0ca12019-03-15 10:44:43 -0700800 def test_ExtractAvbPublicKey(self):
801 privkey = os.path.join(self.testdata_dir, 'testkey.key')
802 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
Tao Bao1ac886e2019-06-26 11:58:22 -0700803 extracted_from_privkey = common.ExtractAvbPublicKey('avbtool', privkey)
804 extracted_from_pubkey = common.ExtractAvbPublicKey('avbtool', pubkey)
805 with open(extracted_from_privkey, 'rb') as privkey_fp, \
806 open(extracted_from_pubkey, 'rb') as pubkey_fp:
Tao Bao2cc0ca12019-03-15 10:44:43 -0700807 self.assertEqual(privkey_fp.read(), pubkey_fp.read())
808
Tao Bao17e4e612018-02-16 17:12:54 -0800809 def test_ParseCertificate(self):
810 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
811
812 cmd = ['openssl', 'x509', '-in', cert, '-outform', 'DER']
Tao Baoda30cfa2017-12-01 16:19:46 -0800813 proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
814 universal_newlines=False)
Tao Bao17e4e612018-02-16 17:12:54 -0800815 expected, _ = proc.communicate()
816 self.assertEqual(0, proc.returncode)
817
818 with open(cert) as cert_fp:
819 actual = common.ParseCertificate(cert_fp.read())
820 self.assertEqual(expected, actual)
821
Tao Bao82490d32019-04-09 00:12:30 -0700822 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700823 def test_GetMinSdkVersion(self):
824 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
825 self.assertEqual('24', common.GetMinSdkVersion(test_app))
826
Tao Bao82490d32019-04-09 00:12:30 -0700827 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700828 def test_GetMinSdkVersion_invalidInput(self):
829 self.assertRaises(
830 common.ExternalError, common.GetMinSdkVersion, 'does-not-exist.apk')
831
Tao Bao82490d32019-04-09 00:12:30 -0700832 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700833 def test_GetMinSdkVersionInt(self):
834 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
835 self.assertEqual(24, common.GetMinSdkVersionInt(test_app, {}))
836
Tao Bao82490d32019-04-09 00:12:30 -0700837 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof47bf0f2018-03-21 23:28:51 -0700838 def test_GetMinSdkVersionInt_invalidInput(self):
839 self.assertRaises(
840 common.ExternalError, common.GetMinSdkVersionInt, 'does-not-exist.apk',
841 {})
842
Tao Bao818ddf52018-01-05 11:17:34 -0800843
Tao Bao65b94e92018-10-11 21:57:26 -0700844class CommonUtilsTest(test_utils.ReleaseToolsTestCase):
Tao Baofc7e0e02018-02-13 13:54:02 -0800845
Tao Bao02a08592018-07-22 12:40:45 -0700846 def setUp(self):
847 self.testdata_dir = test_utils.get_testdata_dir()
848
Tao Bao82490d32019-04-09 00:12:30 -0700849 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800850 def test_GetSparseImage_emptyBlockMapFile(self):
851 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
852 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
853 target_files_zip.write(
854 test_utils.construct_sparse_image([
855 (0xCAC1, 6),
856 (0xCAC3, 3),
857 (0xCAC1, 4)]),
858 arcname='IMAGES/system.img')
859 target_files_zip.writestr('IMAGES/system.map', '')
860 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
861 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
862
Tao Baodba59ee2018-01-09 13:21:02 -0800863 tempdir = common.UnzipTemp(target_files)
864 with zipfile.ZipFile(target_files, 'r') as input_zip:
865 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800866
867 self.assertDictEqual(
868 {
869 '__COPY': RangeSet("0"),
870 '__NONZERO-0': RangeSet("1-5 9-12"),
871 },
872 sparse_image.file_map)
873
Tao Baob2de7d92019-04-10 10:01:47 -0700874 def test_GetSparseImage_missingImageFile(self):
Tao Baofc7e0e02018-02-13 13:54:02 -0800875 self.assertRaises(
Tao Baob2de7d92019-04-10 10:01:47 -0700876 AssertionError, common.GetSparseImage, 'system2', self.testdata_dir,
877 None, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800878 self.assertRaises(
Tao Baob2de7d92019-04-10 10:01:47 -0700879 AssertionError, common.GetSparseImage, 'unknown', self.testdata_dir,
880 None, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800881
Tao Bao82490d32019-04-09 00:12:30 -0700882 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800883 def test_GetSparseImage_missingBlockMapFile(self):
884 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
885 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
886 target_files_zip.write(
887 test_utils.construct_sparse_image([
888 (0xCAC1, 6),
889 (0xCAC3, 3),
890 (0xCAC1, 4)]),
891 arcname='IMAGES/system.img')
892 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
893 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
894
Tao Baodba59ee2018-01-09 13:21:02 -0800895 tempdir = common.UnzipTemp(target_files)
896 with zipfile.ZipFile(target_files, 'r') as input_zip:
897 self.assertRaises(
898 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
899 False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800900
Tao Bao82490d32019-04-09 00:12:30 -0700901 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800902 def test_GetSparseImage_sharedBlocks_notAllowed(self):
903 """Tests the case of having overlapping blocks but disallowed."""
904 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
905 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
906 target_files_zip.write(
907 test_utils.construct_sparse_image([(0xCAC2, 16)]),
908 arcname='IMAGES/system.img')
909 # Block 10 is shared between two files.
910 target_files_zip.writestr(
911 'IMAGES/system.map',
912 '\n'.join([
913 '/system/file1 1-5 9-10',
914 '/system/file2 10-12']))
915 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
916 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
917
Tao Baodba59ee2018-01-09 13:21:02 -0800918 tempdir = common.UnzipTemp(target_files)
919 with zipfile.ZipFile(target_files, 'r') as input_zip:
920 self.assertRaises(
921 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
922 False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800923
Tao Bao82490d32019-04-09 00:12:30 -0700924 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800925 def test_GetSparseImage_sharedBlocks_allowed(self):
926 """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true."""
927 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
928 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
929 # Construct an image with a care_map of "0-5 9-12".
930 target_files_zip.write(
931 test_utils.construct_sparse_image([(0xCAC2, 16)]),
932 arcname='IMAGES/system.img')
933 # Block 10 is shared between two files.
934 target_files_zip.writestr(
935 'IMAGES/system.map',
936 '\n'.join([
937 '/system/file1 1-5 9-10',
938 '/system/file2 10-12']))
939 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
940 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
941
Tao Baodba59ee2018-01-09 13:21:02 -0800942 tempdir = common.UnzipTemp(target_files)
943 with zipfile.ZipFile(target_files, 'r') as input_zip:
944 sparse_image = common.GetSparseImage('system', tempdir, input_zip, True)
Tao Baofc7e0e02018-02-13 13:54:02 -0800945
946 self.assertDictEqual(
947 {
948 '__COPY': RangeSet("0"),
949 '__NONZERO-0': RangeSet("6-8 13-15"),
950 '/system/file1': RangeSet("1-5 9-10"),
951 '/system/file2': RangeSet("11-12"),
952 },
953 sparse_image.file_map)
954
955 # '/system/file2' should be marked with 'uses_shared_blocks', but not with
956 # 'incomplete'.
957 self.assertTrue(
958 sparse_image.file_map['/system/file2'].extra['uses_shared_blocks'])
959 self.assertNotIn(
960 'incomplete', sparse_image.file_map['/system/file2'].extra)
961
Tao Baoa264fef2019-10-06 21:55:20 -0700962 # '/system/file1' will only contain one field -- a copy of the input text.
963 self.assertEqual(1, len(sparse_image.file_map['/system/file1'].extra))
964
965 # Meta entries should not have any extra tag.
Tao Baofc7e0e02018-02-13 13:54:02 -0800966 self.assertFalse(sparse_image.file_map['__COPY'].extra)
967 self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
Tao Baofc7e0e02018-02-13 13:54:02 -0800968
Tao Bao82490d32019-04-09 00:12:30 -0700969 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofc7e0e02018-02-13 13:54:02 -0800970 def test_GetSparseImage_incompleteRanges(self):
971 """Tests the case of ext4 images with holes."""
972 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
973 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
974 target_files_zip.write(
975 test_utils.construct_sparse_image([(0xCAC2, 16)]),
976 arcname='IMAGES/system.img')
977 target_files_zip.writestr(
978 'IMAGES/system.map',
979 '\n'.join([
980 '/system/file1 1-5 9-10',
981 '/system/file2 11-12']))
982 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
983 # '/system/file2' has less blocks listed (2) than actual (3).
984 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
985
Tao Baodba59ee2018-01-09 13:21:02 -0800986 tempdir = common.UnzipTemp(target_files)
987 with zipfile.ZipFile(target_files, 'r') as input_zip:
988 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800989
Tao Baoa264fef2019-10-06 21:55:20 -0700990 self.assertEqual(
991 '1-5 9-10',
992 sparse_image.file_map['/system/file1'].extra['text_str'])
Tao Baofc7e0e02018-02-13 13:54:02 -0800993 self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
994
Tao Bao82490d32019-04-09 00:12:30 -0700995 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -0700996 def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
997 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
998 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
999 target_files_zip.write(
1000 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1001 arcname='IMAGES/system.img')
1002 target_files_zip.writestr(
1003 'IMAGES/system.map',
1004 '\n'.join([
1005 '//system/file1 1-5 9-10',
1006 '//system/file2 11-12',
1007 '/system/app/file3 13-15']))
1008 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1009 # '/system/file2' has less blocks listed (2) than actual (3).
1010 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1011 # '/system/app/file3' has less blocks listed (3) than actual (4).
1012 target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))
1013
1014 tempdir = common.UnzipTemp(target_files)
1015 with zipfile.ZipFile(target_files, 'r') as input_zip:
1016 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1017
Tao Baoa264fef2019-10-06 21:55:20 -07001018 self.assertEqual(
1019 '1-5 9-10',
1020 sparse_image.file_map['//system/file1'].extra['text_str'])
Tao Baod3554e62018-07-10 15:31:22 -07001021 self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
1022 self.assertTrue(
1023 sparse_image.file_map['/system/app/file3'].extra['incomplete'])
1024
Tao Bao82490d32019-04-09 00:12:30 -07001025 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -07001026 def test_GetSparseImage_systemRootImage_nonSystemFiles(self):
1027 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1028 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
1029 target_files_zip.write(
1030 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1031 arcname='IMAGES/system.img')
1032 target_files_zip.writestr(
1033 'IMAGES/system.map',
1034 '\n'.join([
1035 '//system/file1 1-5 9-10',
1036 '//init.rc 13-15']))
1037 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1038 # '/init.rc' has less blocks listed (3) than actual (4).
1039 target_files_zip.writestr('ROOT/init.rc', os.urandom(4096 * 4))
1040
1041 tempdir = common.UnzipTemp(target_files)
1042 with zipfile.ZipFile(target_files, 'r') as input_zip:
1043 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1044
Tao Baoa264fef2019-10-06 21:55:20 -07001045 self.assertEqual(
1046 '1-5 9-10',
1047 sparse_image.file_map['//system/file1'].extra['text_str'])
Tao Baod3554e62018-07-10 15:31:22 -07001048 self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
1049
Tao Bao82490d32019-04-09 00:12:30 -07001050 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baod3554e62018-07-10 15:31:22 -07001051 def test_GetSparseImage_fileNotFound(self):
1052 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1053 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
1054 target_files_zip.write(
1055 test_utils.construct_sparse_image([(0xCAC2, 16)]),
1056 arcname='IMAGES/system.img')
1057 target_files_zip.writestr(
1058 'IMAGES/system.map',
1059 '\n'.join([
1060 '//system/file1 1-5 9-10',
1061 '//system/file2 11-12']))
1062 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1063
1064 tempdir = common.UnzipTemp(target_files)
1065 with zipfile.ZipFile(target_files, 'r') as input_zip:
1066 self.assertRaises(
1067 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1068 False)
1069
Tao Bao82490d32019-04-09 00:12:30 -07001070 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001071 def test_GetAvbChainedPartitionArg(self):
1072 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1073 info_dict = {
1074 'avb_avbtool': 'avbtool',
1075 'avb_system_key_path': pubkey,
1076 'avb_system_rollback_index_location': 2,
1077 }
1078 args = common.GetAvbChainedPartitionArg('system', info_dict).split(':')
1079 self.assertEqual(3, len(args))
1080 self.assertEqual('system', args[0])
1081 self.assertEqual('2', args[1])
1082 self.assertTrue(os.path.exists(args[2]))
1083
Tao Bao82490d32019-04-09 00:12:30 -07001084 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001085 def test_GetAvbChainedPartitionArg_withPrivateKey(self):
1086 key = os.path.join(self.testdata_dir, 'testkey.key')
1087 info_dict = {
1088 'avb_avbtool': 'avbtool',
1089 'avb_product_key_path': key,
1090 'avb_product_rollback_index_location': 2,
1091 }
1092 args = common.GetAvbChainedPartitionArg('product', info_dict).split(':')
1093 self.assertEqual(3, len(args))
1094 self.assertEqual('product', args[0])
1095 self.assertEqual('2', args[1])
1096 self.assertTrue(os.path.exists(args[2]))
1097
Tao Bao82490d32019-04-09 00:12:30 -07001098 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001099 def test_GetAvbChainedPartitionArg_withSpecifiedKey(self):
1100 info_dict = {
1101 'avb_avbtool': 'avbtool',
1102 'avb_system_key_path': 'does-not-exist',
1103 'avb_system_rollback_index_location': 2,
1104 }
1105 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1106 args = common.GetAvbChainedPartitionArg(
1107 'system', info_dict, pubkey).split(':')
1108 self.assertEqual(3, len(args))
1109 self.assertEqual('system', args[0])
1110 self.assertEqual('2', args[1])
1111 self.assertTrue(os.path.exists(args[2]))
1112
Tao Bao82490d32019-04-09 00:12:30 -07001113 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao02a08592018-07-22 12:40:45 -07001114 def test_GetAvbChainedPartitionArg_invalidKey(self):
1115 pubkey = os.path.join(self.testdata_dir, 'testkey_with_passwd.x509.pem')
1116 info_dict = {
1117 'avb_avbtool': 'avbtool',
1118 'avb_system_key_path': pubkey,
1119 'avb_system_rollback_index_location': 2,
1120 }
1121 self.assertRaises(
Tao Bao986ee862018-10-04 15:46:16 -07001122 common.ExternalError, common.GetAvbChainedPartitionArg, 'system',
1123 info_dict)
Tao Bao02a08592018-07-22 12:40:45 -07001124
Tao Baoa57ab9f2018-08-24 12:08:38 -07001125 INFO_DICT_DEFAULT = {
1126 'recovery_api_version': 3,
1127 'fstab_version': 2,
1128 'system_root_image': 'true',
1129 'no_recovery' : 'true',
1130 'recovery_as_boot': 'true',
1131 }
1132
Daniel Norman4cc9df62019-07-18 10:11:07 -07001133 def test_LoadListFromFile(self):
1134 file_path = os.path.join(self.testdata_dir,
1135 'merge_config_framework_item_list')
1136 contents = common.LoadListFromFile(file_path)
1137 expected_contents = [
1138 'META/apkcerts.txt',
1139 'META/filesystem_config.txt',
1140 'META/root_filesystem_config.txt',
1141 'META/system_manifest.xml',
1142 'META/system_matrix.xml',
1143 'META/update_engine_config.txt',
1144 'PRODUCT/*',
1145 'ROOT/*',
1146 'SYSTEM/*',
1147 ]
1148 self.assertEqual(sorted(contents), sorted(expected_contents))
1149
Tao Baoa57ab9f2018-08-24 12:08:38 -07001150 @staticmethod
1151 def _test_LoadInfoDict_createTargetFiles(info_dict, fstab_path):
1152 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1153 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
1154 info_values = ''.join(
Tao Baoda30cfa2017-12-01 16:19:46 -08001155 ['{}={}\n'.format(k, v) for k, v in sorted(info_dict.items())])
Tao Baoa57ab9f2018-08-24 12:08:38 -07001156 common.ZipWriteStr(target_files_zip, 'META/misc_info.txt', info_values)
1157
1158 FSTAB_TEMPLATE = "/dev/block/system {} ext4 ro,barrier=1 defaults"
1159 if info_dict.get('system_root_image') == 'true':
1160 fstab_values = FSTAB_TEMPLATE.format('/')
1161 else:
1162 fstab_values = FSTAB_TEMPLATE.format('/system')
1163 common.ZipWriteStr(target_files_zip, fstab_path, fstab_values)
Tao Bao410ad8b2018-08-24 12:08:38 -07001164
1165 common.ZipWriteStr(
1166 target_files_zip, 'META/file_contexts', 'file-contexts')
Tao Baoa57ab9f2018-08-24 12:08:38 -07001167 return target_files
1168
1169 def test_LoadInfoDict(self):
1170 target_files = self._test_LoadInfoDict_createTargetFiles(
1171 self.INFO_DICT_DEFAULT,
1172 'BOOT/RAMDISK/system/etc/recovery.fstab')
1173 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1174 loaded_dict = common.LoadInfoDict(target_files_zip)
1175 self.assertEqual(3, loaded_dict['recovery_api_version'])
1176 self.assertEqual(2, loaded_dict['fstab_version'])
1177 self.assertIn('/', loaded_dict['fstab'])
1178 self.assertIn('/system', loaded_dict['fstab'])
1179
1180 def test_LoadInfoDict_legacyRecoveryFstabPath(self):
1181 target_files = self._test_LoadInfoDict_createTargetFiles(
1182 self.INFO_DICT_DEFAULT,
1183 'BOOT/RAMDISK/etc/recovery.fstab')
1184 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1185 loaded_dict = common.LoadInfoDict(target_files_zip)
1186 self.assertEqual(3, loaded_dict['recovery_api_version'])
1187 self.assertEqual(2, loaded_dict['fstab_version'])
1188 self.assertIn('/', loaded_dict['fstab'])
1189 self.assertIn('/system', loaded_dict['fstab'])
1190
Tao Bao82490d32019-04-09 00:12:30 -07001191 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoa57ab9f2018-08-24 12:08:38 -07001192 def test_LoadInfoDict_dirInput(self):
1193 target_files = self._test_LoadInfoDict_createTargetFiles(
1194 self.INFO_DICT_DEFAULT,
1195 'BOOT/RAMDISK/system/etc/recovery.fstab')
1196 unzipped = common.UnzipTemp(target_files)
1197 loaded_dict = common.LoadInfoDict(unzipped)
1198 self.assertEqual(3, loaded_dict['recovery_api_version'])
1199 self.assertEqual(2, loaded_dict['fstab_version'])
1200 self.assertIn('/', loaded_dict['fstab'])
1201 self.assertIn('/system', loaded_dict['fstab'])
1202
Tao Bao82490d32019-04-09 00:12:30 -07001203 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoa57ab9f2018-08-24 12:08:38 -07001204 def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self):
1205 target_files = self._test_LoadInfoDict_createTargetFiles(
1206 self.INFO_DICT_DEFAULT,
1207 'BOOT/RAMDISK/system/etc/recovery.fstab')
1208 unzipped = common.UnzipTemp(target_files)
1209 loaded_dict = common.LoadInfoDict(unzipped)
1210 self.assertEqual(3, loaded_dict['recovery_api_version'])
1211 self.assertEqual(2, loaded_dict['fstab_version'])
1212 self.assertIn('/', loaded_dict['fstab'])
1213 self.assertIn('/system', loaded_dict['fstab'])
1214
1215 def test_LoadInfoDict_systemRootImageFalse(self):
1216 # Devices not using system-as-root nor recovery-as-boot. Non-A/B devices
1217 # launched prior to P will likely have this config.
1218 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1219 del info_dict['no_recovery']
1220 del info_dict['system_root_image']
1221 del info_dict['recovery_as_boot']
1222 target_files = self._test_LoadInfoDict_createTargetFiles(
1223 info_dict,
1224 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
1225 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1226 loaded_dict = common.LoadInfoDict(target_files_zip)
1227 self.assertEqual(3, loaded_dict['recovery_api_version'])
1228 self.assertEqual(2, loaded_dict['fstab_version'])
1229 self.assertNotIn('/', loaded_dict['fstab'])
1230 self.assertIn('/system', loaded_dict['fstab'])
1231
1232 def test_LoadInfoDict_recoveryAsBootFalse(self):
1233 # Devices using system-as-root, but with standalone recovery image. Non-A/B
1234 # devices launched since P will likely have this config.
1235 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1236 del info_dict['no_recovery']
1237 del info_dict['recovery_as_boot']
1238 target_files = self._test_LoadInfoDict_createTargetFiles(
1239 info_dict,
1240 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
1241 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1242 loaded_dict = common.LoadInfoDict(target_files_zip)
1243 self.assertEqual(3, loaded_dict['recovery_api_version'])
1244 self.assertEqual(2, loaded_dict['fstab_version'])
1245 self.assertIn('/', loaded_dict['fstab'])
1246 self.assertIn('/system', loaded_dict['fstab'])
1247
1248 def test_LoadInfoDict_noRecoveryTrue(self):
1249 # Device doesn't have a recovery partition at all.
1250 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1251 del info_dict['recovery_as_boot']
1252 target_files = self._test_LoadInfoDict_createTargetFiles(
1253 info_dict,
1254 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
1255 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1256 loaded_dict = common.LoadInfoDict(target_files_zip)
1257 self.assertEqual(3, loaded_dict['recovery_api_version'])
1258 self.assertEqual(2, loaded_dict['fstab_version'])
1259 self.assertIsNone(loaded_dict['fstab'])
1260
Tao Bao82490d32019-04-09 00:12:30 -07001261 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao410ad8b2018-08-24 12:08:38 -07001262 def test_LoadInfoDict_missingMetaMiscInfoTxt(self):
1263 target_files = self._test_LoadInfoDict_createTargetFiles(
1264 self.INFO_DICT_DEFAULT,
1265 'BOOT/RAMDISK/system/etc/recovery.fstab')
1266 common.ZipDelete(target_files, 'META/misc_info.txt')
1267 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1268 self.assertRaises(ValueError, common.LoadInfoDict, target_files_zip)
1269
Tao Bao82490d32019-04-09 00:12:30 -07001270 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao410ad8b2018-08-24 12:08:38 -07001271 def test_LoadInfoDict_repacking(self):
1272 target_files = self._test_LoadInfoDict_createTargetFiles(
1273 self.INFO_DICT_DEFAULT,
1274 'BOOT/RAMDISK/system/etc/recovery.fstab')
1275 unzipped = common.UnzipTemp(target_files)
1276 loaded_dict = common.LoadInfoDict(unzipped, True)
1277 self.assertEqual(3, loaded_dict['recovery_api_version'])
1278 self.assertEqual(2, loaded_dict['fstab_version'])
1279 self.assertIn('/', loaded_dict['fstab'])
1280 self.assertIn('/system', loaded_dict['fstab'])
1281 self.assertEqual(
1282 os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir'])
1283 self.assertEqual(
1284 os.path.join(unzipped, 'META', 'root_filesystem_config.txt'),
1285 loaded_dict['root_fs_config'])
1286
1287 def test_LoadInfoDict_repackingWithZipFileInput(self):
1288 target_files = self._test_LoadInfoDict_createTargetFiles(
1289 self.INFO_DICT_DEFAULT,
1290 'BOOT/RAMDISK/system/etc/recovery.fstab')
1291 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
1292 self.assertRaises(
1293 AssertionError, common.LoadInfoDict, target_files_zip, True)
1294
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001295 def test_MergeDynamicPartitionInfoDicts_ReturnsMergedDict(self):
1296 framework_dict = {
1297 'super_partition_groups': 'group_a',
1298 'dynamic_partition_list': 'system',
Daniel Norman55417142019-11-25 16:04:36 -08001299 'super_group_a_partition_list': 'system',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001300 }
1301 vendor_dict = {
1302 'super_partition_groups': 'group_a group_b',
1303 'dynamic_partition_list': 'vendor product',
Daniel Norman55417142019-11-25 16:04:36 -08001304 'super_group_a_partition_list': 'vendor',
1305 'super_group_a_group_size': '1000',
1306 'super_group_b_partition_list': 'product',
1307 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001308 }
1309 merged_dict = common.MergeDynamicPartitionInfoDicts(
1310 framework_dict=framework_dict,
Daniel Norman55417142019-11-25 16:04:36 -08001311 vendor_dict=vendor_dict)
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001312 expected_merged_dict = {
1313 'super_partition_groups': 'group_a group_b',
1314 'dynamic_partition_list': 'system vendor product',
Daniel Norman55417142019-11-25 16:04:36 -08001315 'super_group_a_partition_list': 'system vendor',
1316 'super_group_a_group_size': '1000',
1317 'super_group_b_partition_list': 'product',
1318 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001319 }
1320 self.assertEqual(merged_dict, expected_merged_dict)
1321
1322 def test_MergeDynamicPartitionInfoDicts_IgnoringFrameworkGroupSize(self):
1323 framework_dict = {
1324 'super_partition_groups': 'group_a',
1325 'dynamic_partition_list': 'system',
Daniel Norman55417142019-11-25 16:04:36 -08001326 'super_group_a_partition_list': 'system',
1327 'super_group_a_group_size': '5000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001328 }
1329 vendor_dict = {
1330 'super_partition_groups': 'group_a group_b',
1331 'dynamic_partition_list': 'vendor product',
Daniel Norman55417142019-11-25 16:04:36 -08001332 'super_group_a_partition_list': 'vendor',
1333 'super_group_a_group_size': '1000',
1334 'super_group_b_partition_list': 'product',
1335 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001336 }
1337 merged_dict = common.MergeDynamicPartitionInfoDicts(
1338 framework_dict=framework_dict,
Daniel Norman55417142019-11-25 16:04:36 -08001339 vendor_dict=vendor_dict)
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001340 expected_merged_dict = {
1341 'super_partition_groups': 'group_a group_b',
1342 'dynamic_partition_list': 'system vendor product',
Daniel Norman55417142019-11-25 16:04:36 -08001343 'super_group_a_partition_list': 'system vendor',
1344 'super_group_a_group_size': '1000',
1345 'super_group_b_partition_list': 'product',
1346 'super_group_b_group_size': '2000',
Daniel Normanbfc51ef2019-07-24 14:34:54 -07001347 }
1348 self.assertEqual(merged_dict, expected_merged_dict)
1349
Daniel Norman276f0622019-07-26 14:13:51 -07001350 def test_GetAvbPartitionArg(self):
1351 info_dict = {}
1352 cmd = common.GetAvbPartitionArg('system', '/path/to/system.img', info_dict)
1353 self.assertEqual(
1354 ['--include_descriptors_from_image', '/path/to/system.img'], cmd)
1355
1356 @test_utils.SkipIfExternalToolsUnavailable()
1357 def test_AppendVBMetaArgsForPartition_vendorAsChainedPartition(self):
1358 testdata_dir = test_utils.get_testdata_dir()
1359 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1360 info_dict = {
1361 'avb_avbtool': 'avbtool',
1362 'avb_vendor_key_path': pubkey,
1363 'avb_vendor_rollback_index_location': 5,
1364 }
1365 cmd = common.GetAvbPartitionArg('vendor', '/path/to/vendor.img', info_dict)
1366 self.assertEqual(2, len(cmd))
1367 self.assertEqual('--chain_partition', cmd[0])
1368 chained_partition_args = cmd[1].split(':')
1369 self.assertEqual(3, len(chained_partition_args))
1370 self.assertEqual('vendor', chained_partition_args[0])
1371 self.assertEqual('5', chained_partition_args[1])
1372 self.assertTrue(os.path.exists(chained_partition_args[2]))
1373
Tao Bao3612c882019-10-14 17:49:31 -07001374 @test_utils.SkipIfExternalToolsUnavailable()
1375 def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_nonAb(self):
1376 testdata_dir = test_utils.get_testdata_dir()
1377 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1378 info_dict = {
1379 'avb_avbtool': 'avbtool',
1380 'avb_recovery_key_path': pubkey,
1381 'avb_recovery_rollback_index_location': 3,
1382 }
1383 cmd = common.GetAvbPartitionArg(
1384 'recovery', '/path/to/recovery.img', info_dict)
1385 self.assertFalse(cmd)
1386
1387 @test_utils.SkipIfExternalToolsUnavailable()
1388 def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_ab(self):
1389 testdata_dir = test_utils.get_testdata_dir()
1390 pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1391 info_dict = {
1392 'ab_update': 'true',
1393 'avb_avbtool': 'avbtool',
1394 'avb_recovery_key_path': pubkey,
1395 'avb_recovery_rollback_index_location': 3,
1396 }
1397 cmd = common.GetAvbPartitionArg(
1398 'recovery', '/path/to/recovery.img', info_dict)
1399 self.assertEqual(2, len(cmd))
1400 self.assertEqual('--chain_partition', cmd[0])
1401 chained_partition_args = cmd[1].split(':')
1402 self.assertEqual(3, len(chained_partition_args))
1403 self.assertEqual('recovery', chained_partition_args[0])
1404 self.assertEqual('3', chained_partition_args[1])
1405 self.assertTrue(os.path.exists(chained_partition_args[2]))
1406
Tao Baofc7e0e02018-02-13 13:54:02 -08001407
Tao Bao65b94e92018-10-11 21:57:26 -07001408class InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
Tao Bao1c830bf2017-12-25 10:43:47 -08001409 """Checks the format of install-recovery.sh.
Tianjie Xu9c384d22017-06-20 17:00:55 -07001410
Tao Bao1c830bf2017-12-25 10:43:47 -08001411 Its format should match between common.py and validate_target_files.py.
1412 """
Tianjie Xu9c384d22017-06-20 17:00:55 -07001413
1414 def setUp(self):
Tao Bao1c830bf2017-12-25 10:43:47 -08001415 self._tempdir = common.MakeTempDir()
Tianjie Xu9c384d22017-06-20 17:00:55 -07001416 # Create a dummy dict that contains the fstab info for boot&recovery.
1417 self._info = {"fstab" : {}}
Tao Bao1c830bf2017-12-25 10:43:47 -08001418 dummy_fstab = [
1419 "/dev/soc.0/by-name/boot /boot emmc defaults defaults",
1420 "/dev/soc.0/by-name/recovery /recovery emmc defaults defaults"]
Tao Bao31b08072017-11-08 15:50:59 -08001421 self._info["fstab"] = common.LoadRecoveryFSTab("\n".join, 2, dummy_fstab)
Tianjie Xudf055582017-11-07 12:22:58 -08001422 # Construct the gzipped recovery.img and boot.img
1423 self.recovery_data = bytearray([
1424 0x1f, 0x8b, 0x08, 0x00, 0x81, 0x11, 0x02, 0x5a, 0x00, 0x03, 0x2b, 0x4a,
1425 0x4d, 0xce, 0x2f, 0x4b, 0x2d, 0xaa, 0x04, 0x00, 0xc9, 0x93, 0x43, 0xf3,
1426 0x08, 0x00, 0x00, 0x00
1427 ])
1428 # echo -n "boot" | gzip -f | hd
1429 self.boot_data = bytearray([
1430 0x1f, 0x8b, 0x08, 0x00, 0x8c, 0x12, 0x02, 0x5a, 0x00, 0x03, 0x4b, 0xca,
1431 0xcf, 0x2f, 0x01, 0x00, 0xc4, 0xae, 0xed, 0x46, 0x04, 0x00, 0x00, 0x00
1432 ])
Tianjie Xu9c384d22017-06-20 17:00:55 -07001433
1434 def _out_tmp_sink(self, name, data, prefix="SYSTEM"):
1435 loc = os.path.join(self._tempdir, prefix, name)
1436 if not os.path.exists(os.path.dirname(loc)):
1437 os.makedirs(os.path.dirname(loc))
Tao Baoda30cfa2017-12-01 16:19:46 -08001438 with open(loc, "wb") as f:
Tianjie Xu9c384d22017-06-20 17:00:55 -07001439 f.write(data)
1440
1441 def test_full_recovery(self):
Tao Bao31b08072017-11-08 15:50:59 -08001442 recovery_image = common.File("recovery.img", self.recovery_data)
1443 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001444 self._info["full_recovery_image"] = "true"
1445
1446 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1447 recovery_image, boot_image, self._info)
1448 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1449 self._info)
1450
Tao Bao82490d32019-04-09 00:12:30 -07001451 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu9c384d22017-06-20 17:00:55 -07001452 def test_recovery_from_boot(self):
Tao Bao31b08072017-11-08 15:50:59 -08001453 recovery_image = common.File("recovery.img", self.recovery_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001454 self._out_tmp_sink("recovery.img", recovery_image.data, "IMAGES")
Tao Bao31b08072017-11-08 15:50:59 -08001455 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -07001456 self._out_tmp_sink("boot.img", boot_image.data, "IMAGES")
1457
1458 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1459 recovery_image, boot_image, self._info)
1460 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1461 self._info)
1462 # Validate 'recovery-from-boot' with bonus argument.
Tao Baoda30cfa2017-12-01 16:19:46 -08001463 self._out_tmp_sink("etc/recovery-resource.dat", b"bonus", "SYSTEM")
Tianjie Xu9c384d22017-06-20 17:00:55 -07001464 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1465 recovery_image, boot_image, self._info)
1466 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1467 self._info)
Yifan Hong45433e42019-01-18 13:55:25 -08001468
1469
Yifan Hong45433e42019-01-18 13:55:25 -08001470class MockBlockDifference(object):
Tao Baoda30cfa2017-12-01 16:19:46 -08001471
Yifan Hong45433e42019-01-18 13:55:25 -08001472 def __init__(self, partition, tgt, src=None):
1473 self.partition = partition
1474 self.tgt = tgt
1475 self.src = src
Tao Baoda30cfa2017-12-01 16:19:46 -08001476
Yifan Hong45433e42019-01-18 13:55:25 -08001477 def WriteScript(self, script, _, progress=None,
1478 write_verify_script=False):
1479 if progress:
1480 script.AppendExtra("progress({})".format(progress))
1481 script.AppendExtra("patch({});".format(self.partition))
1482 if write_verify_script:
1483 self.WritePostInstallVerifyScript(script)
Tao Baoda30cfa2017-12-01 16:19:46 -08001484
Yifan Hong45433e42019-01-18 13:55:25 -08001485 def WritePostInstallVerifyScript(self, script):
1486 script.AppendExtra("verify({});".format(self.partition))
1487
1488
1489class FakeSparseImage(object):
Tao Baoda30cfa2017-12-01 16:19:46 -08001490
Yifan Hong45433e42019-01-18 13:55:25 -08001491 def __init__(self, size):
1492 self.blocksize = 4096
1493 self.total_blocks = size // 4096
1494 assert size % 4096 == 0, "{} is not a multiple of 4096".format(size)
1495
1496
1497class DynamicPartitionsDifferenceTest(test_utils.ReleaseToolsTestCase):
Tao Baoda30cfa2017-12-01 16:19:46 -08001498
Yifan Hong45433e42019-01-18 13:55:25 -08001499 @staticmethod
1500 def get_op_list(output_path):
Tao Baof1113e92019-06-18 12:10:14 -07001501 with zipfile.ZipFile(output_path) as output_zip:
Tao Baoda30cfa2017-12-01 16:19:46 -08001502 with output_zip.open('dynamic_partitions_op_list') as op_list:
1503 return [line.decode().strip() for line in op_list.readlines()
1504 if not line.startswith(b'#')]
Yifan Hong45433e42019-01-18 13:55:25 -08001505
1506 def setUp(self):
Tao Baoe1148042019-10-07 20:00:34 -07001507 self.script = test_utils.MockScriptWriter()
Yifan Hong45433e42019-01-18 13:55:25 -08001508 self.output_path = common.MakeTempFile(suffix='.zip')
1509
1510 def test_full(self):
1511 target_info = common.LoadDictionaryFromLines("""
1512dynamic_partition_list=system vendor
1513super_partition_groups=group_foo
1514super_group_foo_group_size={group_size}
1515super_group_foo_partition_list=system vendor
1516""".format(group_size=4 * GiB).split("\n"))
1517 block_diffs = [MockBlockDifference("system", FakeSparseImage(3 * GiB)),
1518 MockBlockDifference("vendor", FakeSparseImage(1 * GiB))]
1519
1520 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs)
1521 with zipfile.ZipFile(self.output_path, 'w') as output_zip:
1522 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1523
1524 self.assertEqual(str(self.script).strip(), """
1525assert(update_dynamic_partitions(package_extract_file("dynamic_partitions_op_list")));
Yifan Hong45433e42019-01-18 13:55:25 -08001526patch(system);
1527verify(system);
1528unmap_partition("system");
Tao Baof1113e92019-06-18 12:10:14 -07001529patch(vendor);
1530verify(vendor);
1531unmap_partition("vendor");
Yifan Hong45433e42019-01-18 13:55:25 -08001532""".strip())
1533
1534 lines = self.get_op_list(self.output_path)
1535
1536 remove_all_groups = lines.index("remove_all_groups")
1537 add_group = lines.index("add_group group_foo 4294967296")
1538 add_vendor = lines.index("add vendor group_foo")
1539 add_system = lines.index("add system group_foo")
1540 resize_vendor = lines.index("resize vendor 1073741824")
1541 resize_system = lines.index("resize system 3221225472")
1542
1543 self.assertLess(remove_all_groups, add_group,
1544 "Should add groups after removing all groups")
1545 self.assertLess(add_group, min(add_vendor, add_system),
1546 "Should add partitions after adding group")
1547 self.assertLess(add_system, resize_system,
1548 "Should resize system after adding it")
1549 self.assertLess(add_vendor, resize_vendor,
1550 "Should resize vendor after adding it")
1551
1552 def test_inc_groups(self):
1553 source_info = common.LoadDictionaryFromLines("""
1554super_partition_groups=group_foo group_bar group_baz
1555super_group_foo_group_size={group_foo_size}
1556super_group_bar_group_size={group_bar_size}
1557""".format(group_foo_size=4 * GiB, group_bar_size=3 * GiB).split("\n"))
1558 target_info = common.LoadDictionaryFromLines("""
1559super_partition_groups=group_foo group_baz group_qux
1560super_group_foo_group_size={group_foo_size}
1561super_group_baz_group_size={group_baz_size}
1562super_group_qux_group_size={group_qux_size}
1563""".format(group_foo_size=3 * GiB, group_baz_size=4 * GiB,
1564 group_qux_size=1 * GiB).split("\n"))
1565
1566 dp_diff = common.DynamicPartitionsDifference(target_info,
1567 block_diffs=[],
1568 source_info_dict=source_info)
1569 with zipfile.ZipFile(self.output_path, 'w') as output_zip:
1570 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1571
1572 lines = self.get_op_list(self.output_path)
1573
1574 removed = lines.index("remove_group group_bar")
1575 shrunk = lines.index("resize_group group_foo 3221225472")
1576 grown = lines.index("resize_group group_baz 4294967296")
1577 added = lines.index("add_group group_qux 1073741824")
1578
Tao Baof1113e92019-06-18 12:10:14 -07001579 self.assertLess(max(removed, shrunk),
1580 min(grown, added),
Yifan Hong45433e42019-01-18 13:55:25 -08001581 "ops that remove / shrink partitions must precede ops that "
1582 "grow / add partitions")
1583
Yifan Hongbb2658d2019-01-25 12:30:58 -08001584 def test_incremental(self):
Yifan Hong45433e42019-01-18 13:55:25 -08001585 source_info = common.LoadDictionaryFromLines("""
Justin Yun6151e3f2019-06-25 15:58:13 +09001586dynamic_partition_list=system vendor product system_ext
Yifan Hong45433e42019-01-18 13:55:25 -08001587super_partition_groups=group_foo
1588super_group_foo_group_size={group_foo_size}
Justin Yun6151e3f2019-06-25 15:58:13 +09001589super_group_foo_partition_list=system vendor product system_ext
Yifan Hong45433e42019-01-18 13:55:25 -08001590""".format(group_foo_size=4 * GiB).split("\n"))
1591 target_info = common.LoadDictionaryFromLines("""
1592dynamic_partition_list=system vendor product odm
1593super_partition_groups=group_foo group_bar
1594super_group_foo_group_size={group_foo_size}
1595super_group_foo_partition_list=system vendor odm
1596super_group_bar_group_size={group_bar_size}
1597super_group_bar_partition_list=product
1598""".format(group_foo_size=3 * GiB, group_bar_size=1 * GiB).split("\n"))
1599
1600 block_diffs = [MockBlockDifference("system", FakeSparseImage(1536 * MiB),
1601 src=FakeSparseImage(1024 * MiB)),
1602 MockBlockDifference("vendor", FakeSparseImage(512 * MiB),
1603 src=FakeSparseImage(1024 * MiB)),
1604 MockBlockDifference("product", FakeSparseImage(1024 * MiB),
1605 src=FakeSparseImage(1024 * MiB)),
Justin Yun6151e3f2019-06-25 15:58:13 +09001606 MockBlockDifference("system_ext", None,
Yifan Hong45433e42019-01-18 13:55:25 -08001607 src=FakeSparseImage(1024 * MiB)),
1608 MockBlockDifference("odm", FakeSparseImage(1024 * MiB),
1609 src=None)]
1610
1611 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1612 source_info_dict=source_info)
1613 with zipfile.ZipFile(self.output_path, 'w') as output_zip:
1614 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1615
1616 metadata_idx = self.script.lines.index(
1617 'assert(update_dynamic_partitions(package_extract_file('
1618 '"dynamic_partitions_op_list")));')
1619 self.assertLess(self.script.lines.index('patch(vendor);'), metadata_idx)
1620 self.assertLess(metadata_idx, self.script.lines.index('verify(vendor);'))
1621 for p in ("product", "system", "odm"):
1622 patch_idx = self.script.lines.index("patch({});".format(p))
1623 verify_idx = self.script.lines.index("verify({});".format(p))
1624 self.assertLess(metadata_idx, patch_idx,
1625 "Should patch {} after updating metadata".format(p))
1626 self.assertLess(patch_idx, verify_idx,
1627 "Should verify {} after patching".format(p))
1628
Justin Yun6151e3f2019-06-25 15:58:13 +09001629 self.assertNotIn("patch(system_ext);", self.script.lines)
Yifan Hong45433e42019-01-18 13:55:25 -08001630
1631 lines = self.get_op_list(self.output_path)
1632
Justin Yun6151e3f2019-06-25 15:58:13 +09001633 remove = lines.index("remove system_ext")
Yifan Hong45433e42019-01-18 13:55:25 -08001634 move_product_out = lines.index("move product default")
1635 shrink = lines.index("resize vendor 536870912")
1636 shrink_group = lines.index("resize_group group_foo 3221225472")
1637 add_group_bar = lines.index("add_group group_bar 1073741824")
1638 add_odm = lines.index("add odm group_foo")
1639 grow_existing = lines.index("resize system 1610612736")
1640 grow_added = lines.index("resize odm 1073741824")
1641 move_product_in = lines.index("move product group_bar")
1642
1643 max_idx_move_partition_out_foo = max(remove, move_product_out, shrink)
1644 min_idx_move_partition_in_foo = min(add_odm, grow_existing, grow_added)
1645
1646 self.assertLess(max_idx_move_partition_out_foo, shrink_group,
1647 "Must shrink group after partitions inside group are shrunk"
1648 " / removed")
1649
1650 self.assertLess(add_group_bar, move_product_in,
1651 "Must add partitions to group after group is added")
1652
1653 self.assertLess(max_idx_move_partition_out_foo,
1654 min_idx_move_partition_in_foo,
1655 "Must shrink partitions / remove partitions from group"
1656 "before adding / moving partitions into group")
Yifan Hongbb2658d2019-01-25 12:30:58 -08001657
1658 def test_remove_partition(self):
1659 source_info = common.LoadDictionaryFromLines("""
1660blockimgdiff_versions=3,4
1661use_dynamic_partitions=true
1662dynamic_partition_list=foo
1663super_partition_groups=group_foo
1664super_group_foo_group_size={group_foo_size}
1665super_group_foo_partition_list=foo
1666""".format(group_foo_size=4 * GiB).split("\n"))
1667 target_info = common.LoadDictionaryFromLines("""
1668blockimgdiff_versions=3,4
1669use_dynamic_partitions=true
1670super_partition_groups=group_foo
1671super_group_foo_group_size={group_foo_size}
1672""".format(group_foo_size=4 * GiB).split("\n"))
1673
1674 common.OPTIONS.info_dict = target_info
1675 common.OPTIONS.target_info_dict = target_info
1676 common.OPTIONS.source_info_dict = source_info
1677 common.OPTIONS.cache_size = 4 * 4096
1678
1679 block_diffs = [common.BlockDifference("foo", EmptyImage(),
1680 src=DataImage("source", pad=True))]
1681
1682 dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1683 source_info_dict=source_info)
1684 with zipfile.ZipFile(self.output_path, 'w') as output_zip:
1685 dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1686
1687 self.assertNotIn("block_image_update", str(self.script),
Tao Bao2cc0ca12019-03-15 10:44:43 -07001688 "Removed partition should not be patched.")
Yifan Hongbb2658d2019-01-25 12:30:58 -08001689
1690 lines = self.get_op_list(self.output_path)
1691 self.assertEqual(lines, ["remove foo"])