blob: 5179900954b5d55f10631bce45d9a0f5cd203e38 [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
22import unittest
23import 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
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)
44 yield '\0' * (step_size - block_size)
Tao Baof3282b42015-04-01 11:21:55 -070045
Dan Albert8e0178d2015-01-27 15:53:15 -080046
47class CommonZipTest(unittest.TestCase):
Tao Bao31b08072017-11-08 15:50:59 -080048 def _verify(self, zip_file, zip_file_name, arcname, expected_hash,
Tao Baof3282b42015-04-01 11:21:55 -070049 test_file_name=None, expected_stat=None, expected_mode=0o644,
50 expected_compress_type=zipfile.ZIP_STORED):
51 # Verify the stat if present.
52 if test_file_name is not None:
53 new_stat = os.stat(test_file_name)
54 self.assertEqual(int(expected_stat.st_mode), int(new_stat.st_mode))
55 self.assertEqual(int(expected_stat.st_mtime), int(new_stat.st_mtime))
56
57 # Reopen the zip file to verify.
58 zip_file = zipfile.ZipFile(zip_file_name, "r")
59
60 # Verify the timestamp.
61 info = zip_file.getinfo(arcname)
62 self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0))
63
64 # Verify the file mode.
65 mode = (info.external_attr >> 16) & 0o777
66 self.assertEqual(mode, expected_mode)
67
68 # Verify the compress type.
69 self.assertEqual(info.compress_type, expected_compress_type)
70
71 # Verify the zip contents.
Tao Bao31b08072017-11-08 15:50:59 -080072 entry = zip_file.open(arcname)
73 sha1_hash = sha1()
74 for chunk in iter(lambda: entry.read(4 * MiB), ''):
75 sha1_hash.update(chunk)
76 self.assertEqual(expected_hash, sha1_hash.hexdigest())
Tao Baof3282b42015-04-01 11:21:55 -070077 self.assertIsNone(zip_file.testzip())
78
Dan Albert8e0178d2015-01-27 15:53:15 -080079 def _test_ZipWrite(self, contents, extra_zipwrite_args=None):
80 extra_zipwrite_args = dict(extra_zipwrite_args or {})
81
82 test_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -080083 test_file_name = test_file.name
Tao Baof3282b42015-04-01 11:21:55 -070084
85 zip_file = tempfile.NamedTemporaryFile(delete=False)
Dan Albert8e0178d2015-01-27 15:53:15 -080086 zip_file_name = zip_file.name
87
88 # File names within an archive strip the leading slash.
89 arcname = extra_zipwrite_args.get("arcname", test_file_name)
90 if arcname[0] == "/":
91 arcname = arcname[1:]
92
93 zip_file.close()
94 zip_file = zipfile.ZipFile(zip_file_name, "w")
95
96 try:
Tao Bao31b08072017-11-08 15:50:59 -080097 sha1_hash = sha1()
98 for data in contents:
99 sha1_hash.update(data)
100 test_file.write(data)
Dan Albert8e0178d2015-01-27 15:53:15 -0800101 test_file.close()
102
Tao Baof3282b42015-04-01 11:21:55 -0700103 expected_stat = os.stat(test_file_name)
Dan Albert8e0178d2015-01-27 15:53:15 -0800104 expected_mode = extra_zipwrite_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700105 expected_compress_type = extra_zipwrite_args.get("compress_type",
106 zipfile.ZIP_STORED)
Dan Albert8e0178d2015-01-27 15:53:15 -0800107 time.sleep(5) # Make sure the atime/mtime will change measurably.
108
109 common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
Tao Baof3282b42015-04-01 11:21:55 -0700110 common.ZipClose(zip_file)
Dan Albert8e0178d2015-01-27 15:53:15 -0800111
Tao Bao31b08072017-11-08 15:50:59 -0800112 self._verify(zip_file, zip_file_name, arcname, sha1_hash.hexdigest(),
113 test_file_name, expected_stat, expected_mode,
114 expected_compress_type)
Dan Albert8e0178d2015-01-27 15:53:15 -0800115 finally:
116 os.remove(test_file_name)
117 os.remove(zip_file_name)
118
Tao Baof3282b42015-04-01 11:21:55 -0700119 def _test_ZipWriteStr(self, zinfo_or_arcname, contents, extra_args=None):
120 extra_args = dict(extra_args or {})
121
122 zip_file = tempfile.NamedTemporaryFile(delete=False)
123 zip_file_name = zip_file.name
124 zip_file.close()
125
126 zip_file = zipfile.ZipFile(zip_file_name, "w")
127
128 try:
129 expected_compress_type = extra_args.get("compress_type",
130 zipfile.ZIP_STORED)
131 time.sleep(5) # Make sure the atime/mtime will change measurably.
132
133 if not isinstance(zinfo_or_arcname, zipfile.ZipInfo):
Tao Bao58c1b962015-05-20 09:32:18 -0700134 arcname = zinfo_or_arcname
135 expected_mode = extra_args.get("perms", 0o644)
Tao Baof3282b42015-04-01 11:21:55 -0700136 else:
Tao Bao58c1b962015-05-20 09:32:18 -0700137 arcname = zinfo_or_arcname.filename
138 expected_mode = extra_args.get("perms",
139 zinfo_or_arcname.external_attr >> 16)
Tao Baof3282b42015-04-01 11:21:55 -0700140
Tao Bao58c1b962015-05-20 09:32:18 -0700141 common.ZipWriteStr(zip_file, zinfo_or_arcname, contents, **extra_args)
Tao Baof3282b42015-04-01 11:21:55 -0700142 common.ZipClose(zip_file)
143
Tao Bao31b08072017-11-08 15:50:59 -0800144 self._verify(zip_file, zip_file_name, arcname, sha1(contents).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700145 expected_mode=expected_mode,
Tao Baof3282b42015-04-01 11:21:55 -0700146 expected_compress_type=expected_compress_type)
147 finally:
148 os.remove(zip_file_name)
149
150 def _test_ZipWriteStr_large_file(self, large, small, extra_args=None):
151 extra_args = dict(extra_args or {})
152
153 zip_file = tempfile.NamedTemporaryFile(delete=False)
154 zip_file_name = zip_file.name
155
156 test_file = tempfile.NamedTemporaryFile(delete=False)
157 test_file_name = test_file.name
158
159 arcname_large = test_file_name
160 arcname_small = "bar"
161
162 # File names within an archive strip the leading slash.
163 if arcname_large[0] == "/":
164 arcname_large = arcname_large[1:]
165
166 zip_file.close()
167 zip_file = zipfile.ZipFile(zip_file_name, "w")
168
169 try:
Tao Bao31b08072017-11-08 15:50:59 -0800170 sha1_hash = sha1()
171 for data in large:
172 sha1_hash.update(data)
173 test_file.write(data)
Tao Baof3282b42015-04-01 11:21:55 -0700174 test_file.close()
175
176 expected_stat = os.stat(test_file_name)
177 expected_mode = 0o644
178 expected_compress_type = extra_args.get("compress_type",
179 zipfile.ZIP_STORED)
180 time.sleep(5) # Make sure the atime/mtime will change measurably.
181
182 common.ZipWrite(zip_file, test_file_name, **extra_args)
183 common.ZipWriteStr(zip_file, arcname_small, small, **extra_args)
184 common.ZipClose(zip_file)
185
186 # Verify the contents written by ZipWrite().
Tao Bao31b08072017-11-08 15:50:59 -0800187 self._verify(zip_file, zip_file_name, arcname_large,
188 sha1_hash.hexdigest(), test_file_name, expected_stat,
189 expected_mode, expected_compress_type)
Tao Baof3282b42015-04-01 11:21:55 -0700190
191 # Verify the contents written by ZipWriteStr().
Tao Bao31b08072017-11-08 15:50:59 -0800192 self._verify(zip_file, zip_file_name, arcname_small,
193 sha1(small).hexdigest(),
Tao Baof3282b42015-04-01 11:21:55 -0700194 expected_compress_type=expected_compress_type)
195 finally:
196 os.remove(zip_file_name)
197 os.remove(test_file_name)
198
199 def _test_reset_ZIP64_LIMIT(self, func, *args):
200 default_limit = (1 << 31) - 1
201 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
202 func(*args)
203 self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
204
Dan Albert8e0178d2015-01-27 15:53:15 -0800205 def test_ZipWrite(self):
206 file_contents = os.urandom(1024)
207 self._test_ZipWrite(file_contents)
208
209 def test_ZipWrite_with_opts(self):
210 file_contents = os.urandom(1024)
211 self._test_ZipWrite(file_contents, {
212 "arcname": "foobar",
213 "perms": 0o777,
214 "compress_type": zipfile.ZIP_DEFLATED,
215 })
Tao Baof3282b42015-04-01 11:21:55 -0700216 self._test_ZipWrite(file_contents, {
217 "arcname": "foobar",
218 "perms": 0o700,
219 "compress_type": zipfile.ZIP_STORED,
220 })
Dan Albert8e0178d2015-01-27 15:53:15 -0800221
222 def test_ZipWrite_large_file(self):
Tao Baof3282b42015-04-01 11:21:55 -0700223 file_contents = get_2gb_string()
Dan Albert8e0178d2015-01-27 15:53:15 -0800224 self._test_ZipWrite(file_contents, {
225 "compress_type": zipfile.ZIP_DEFLATED,
226 })
227
228 def test_ZipWrite_resets_ZIP64_LIMIT(self):
Tao Baof3282b42015-04-01 11:21:55 -0700229 self._test_reset_ZIP64_LIMIT(self._test_ZipWrite, "")
230
231 def test_ZipWriteStr(self):
232 random_string = os.urandom(1024)
233 # Passing arcname
234 self._test_ZipWriteStr("foo", random_string)
235
236 # Passing zinfo
237 zinfo = zipfile.ZipInfo(filename="foo")
238 self._test_ZipWriteStr(zinfo, random_string)
239
240 # Timestamp in the zinfo should be overwritten.
241 zinfo.date_time = (2015, 3, 1, 15, 30, 0)
242 self._test_ZipWriteStr(zinfo, random_string)
243
244 def test_ZipWriteStr_with_opts(self):
245 random_string = os.urandom(1024)
246 # Passing arcname
247 self._test_ZipWriteStr("foo", random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700248 "perms": 0o700,
Tao Baof3282b42015-04-01 11:21:55 -0700249 "compress_type": zipfile.ZIP_DEFLATED,
250 })
Tao Bao58c1b962015-05-20 09:32:18 -0700251 self._test_ZipWriteStr("bar", random_string, {
Tao Baof3282b42015-04-01 11:21:55 -0700252 "compress_type": zipfile.ZIP_STORED,
253 })
254
255 # Passing zinfo
256 zinfo = zipfile.ZipInfo(filename="foo")
257 self._test_ZipWriteStr(zinfo, random_string, {
258 "compress_type": zipfile.ZIP_DEFLATED,
259 })
260 self._test_ZipWriteStr(zinfo, random_string, {
Tao Bao58c1b962015-05-20 09:32:18 -0700261 "perms": 0o600,
Tao Baof3282b42015-04-01 11:21:55 -0700262 "compress_type": zipfile.ZIP_STORED,
263 })
264
265 def test_ZipWriteStr_large_file(self):
266 # zipfile.writestr() doesn't work when the str size is over 2GiB even with
267 # the workaround. We will only test the case of writing a string into a
268 # large archive.
269 long_string = get_2gb_string()
270 short_string = os.urandom(1024)
271 self._test_ZipWriteStr_large_file(long_string, short_string, {
272 "compress_type": zipfile.ZIP_DEFLATED,
273 })
274
275 def test_ZipWriteStr_resets_ZIP64_LIMIT(self):
276 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, "foo", "")
277 zinfo = zipfile.ZipInfo(filename="foo")
278 self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, zinfo, "")
Tao Bao58c1b962015-05-20 09:32:18 -0700279
280 def test_bug21309935(self):
281 zip_file = tempfile.NamedTemporaryFile(delete=False)
282 zip_file_name = zip_file.name
283 zip_file.close()
284
285 try:
286 random_string = os.urandom(1024)
287 zip_file = zipfile.ZipFile(zip_file_name, "w")
288 # Default perms should be 0o644 when passing the filename.
289 common.ZipWriteStr(zip_file, "foo", random_string)
290 # Honor the specified perms.
291 common.ZipWriteStr(zip_file, "bar", random_string, perms=0o755)
292 # The perms in zinfo should be untouched.
293 zinfo = zipfile.ZipInfo(filename="baz")
294 zinfo.external_attr = 0o740 << 16
295 common.ZipWriteStr(zip_file, zinfo, random_string)
296 # Explicitly specified perms has the priority.
297 zinfo = zipfile.ZipInfo(filename="qux")
298 zinfo.external_attr = 0o700 << 16
299 common.ZipWriteStr(zip_file, zinfo, random_string, perms=0o400)
300 common.ZipClose(zip_file)
301
Tao Bao31b08072017-11-08 15:50:59 -0800302 self._verify(zip_file, zip_file_name, "foo",
303 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700304 expected_mode=0o644)
Tao Bao31b08072017-11-08 15:50:59 -0800305 self._verify(zip_file, zip_file_name, "bar",
306 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700307 expected_mode=0o755)
Tao Bao31b08072017-11-08 15:50:59 -0800308 self._verify(zip_file, zip_file_name, "baz",
309 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700310 expected_mode=0o740)
Tao Bao31b08072017-11-08 15:50:59 -0800311 self._verify(zip_file, zip_file_name, "qux",
312 sha1(random_string).hexdigest(),
Tao Bao58c1b962015-05-20 09:32:18 -0700313 expected_mode=0o400)
314 finally:
315 os.remove(zip_file_name)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700316
Tao Bao89d7ab22017-12-14 17:05:33 -0800317 def test_ZipDelete(self):
318 zip_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
319 output_zip = zipfile.ZipFile(zip_file.name, 'w',
320 compression=zipfile.ZIP_DEFLATED)
321 with tempfile.NamedTemporaryFile() as entry_file:
322 entry_file.write(os.urandom(1024))
323 common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
324 common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
325 common.ZipWrite(output_zip, entry_file.name, arcname='Test3')
326 common.ZipClose(output_zip)
327 zip_file.close()
328
329 try:
330 common.ZipDelete(zip_file.name, 'Test2')
331 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
332 entries = check_zip.namelist()
333 self.assertTrue('Test1' in entries)
334 self.assertFalse('Test2' in entries)
335 self.assertTrue('Test3' in entries)
336
337 self.assertRaises(AssertionError, common.ZipDelete, zip_file.name,
338 'Test2')
339 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
340 entries = check_zip.namelist()
341 self.assertTrue('Test1' in entries)
342 self.assertFalse('Test2' in entries)
343 self.assertTrue('Test3' in entries)
344
345 common.ZipDelete(zip_file.name, ['Test3'])
346 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
347 entries = check_zip.namelist()
348 self.assertTrue('Test1' in entries)
349 self.assertFalse('Test2' in entries)
350 self.assertFalse('Test3' in entries)
351
352 common.ZipDelete(zip_file.name, ['Test1', 'Test2'])
353 with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
354 entries = check_zip.namelist()
355 self.assertFalse('Test1' in entries)
356 self.assertFalse('Test2' in entries)
357 self.assertFalse('Test3' in entries)
358 finally:
359 os.remove(zip_file.name)
360
361
Tao Bao818ddf52018-01-05 11:17:34 -0800362class CommonApkUtilsTest(unittest.TestCase):
363 """Tests the APK utils related functions."""
364
365 APKCERTS_TXT1 = (
366 'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
367 ' private_key="certs/devkey.pk8"\n'
368 'name="Settings.apk"'
369 ' certificate="build/target/product/security/platform.x509.pem"'
370 ' private_key="build/target/product/security/platform.pk8"\n'
371 'name="TV.apk" certificate="PRESIGNED" private_key=""\n'
372 )
373
374 APKCERTS_CERTMAP1 = {
375 'RecoveryLocalizer.apk' : 'certs/devkey',
376 'Settings.apk' : 'build/target/product/security/platform',
377 'TV.apk' : 'PRESIGNED',
378 }
379
380 APKCERTS_TXT2 = (
381 'name="Compressed1.apk" certificate="certs/compressed1.x509.pem"'
382 ' private_key="certs/compressed1.pk8" compressed="gz"\n'
383 'name="Compressed2a.apk" certificate="certs/compressed2.x509.pem"'
384 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
385 'name="Compressed2b.apk" certificate="certs/compressed2.x509.pem"'
386 ' private_key="certs/compressed2.pk8" compressed="gz"\n'
387 'name="Compressed3.apk" certificate="certs/compressed3.x509.pem"'
388 ' private_key="certs/compressed3.pk8" compressed="gz"\n'
389 )
390
391 APKCERTS_CERTMAP2 = {
392 'Compressed1.apk' : 'certs/compressed1',
393 'Compressed2a.apk' : 'certs/compressed2',
394 'Compressed2b.apk' : 'certs/compressed2',
395 'Compressed3.apk' : 'certs/compressed3',
396 }
397
398 APKCERTS_TXT3 = (
399 'name="Compressed4.apk" certificate="certs/compressed4.x509.pem"'
400 ' private_key="certs/compressed4.pk8" compressed="xz"\n'
401 )
402
403 APKCERTS_CERTMAP3 = {
404 'Compressed4.apk' : 'certs/compressed4',
405 }
406
Tao Bao17e4e612018-02-16 17:12:54 -0800407 def setUp(self):
408 self.testdata_dir = test_utils.get_testdata_dir()
409
Tao Bao818ddf52018-01-05 11:17:34 -0800410 def tearDown(self):
411 common.Cleanup()
412
413 @staticmethod
414 def _write_apkcerts_txt(apkcerts_txt, additional=None):
415 if additional is None:
416 additional = []
417 target_files = common.MakeTempFile(suffix='.zip')
418 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
419 target_files_zip.writestr('META/apkcerts.txt', apkcerts_txt)
420 for entry in additional:
421 target_files_zip.writestr(entry, '')
422 return target_files
423
424 def test_ReadApkCerts_NoncompressedApks(self):
425 target_files = self._write_apkcerts_txt(self.APKCERTS_TXT1)
426 with zipfile.ZipFile(target_files, 'r') as input_zip:
427 certmap, ext = common.ReadApkCerts(input_zip)
428
429 self.assertDictEqual(self.APKCERTS_CERTMAP1, certmap)
430 self.assertIsNone(ext)
431
432 def test_ReadApkCerts_CompressedApks(self):
433 # We have "installed" Compressed1.apk.gz only. Note that Compressed3.apk is
434 # not stored in '.gz' format, so it shouldn't be considered as installed.
435 target_files = self._write_apkcerts_txt(
436 self.APKCERTS_TXT2,
437 ['Compressed1.apk.gz', 'Compressed3.apk'])
438
439 with zipfile.ZipFile(target_files, 'r') as input_zip:
440 certmap, ext = common.ReadApkCerts(input_zip)
441
442 self.assertDictEqual(self.APKCERTS_CERTMAP2, certmap)
443 self.assertEqual('.gz', ext)
444
445 # Alternative case with '.xz'.
446 target_files = self._write_apkcerts_txt(
447 self.APKCERTS_TXT3, ['Compressed4.apk.xz'])
448
449 with zipfile.ZipFile(target_files, 'r') as input_zip:
450 certmap, ext = common.ReadApkCerts(input_zip)
451
452 self.assertDictEqual(self.APKCERTS_CERTMAP3, certmap)
453 self.assertEqual('.xz', ext)
454
455 def test_ReadApkCerts_CompressedAndNoncompressedApks(self):
456 target_files = self._write_apkcerts_txt(
457 self.APKCERTS_TXT1 + self.APKCERTS_TXT2,
458 ['Compressed1.apk.gz', 'Compressed3.apk'])
459
460 with zipfile.ZipFile(target_files, 'r') as input_zip:
461 certmap, ext = common.ReadApkCerts(input_zip)
462
463 certmap_merged = self.APKCERTS_CERTMAP1.copy()
464 certmap_merged.update(self.APKCERTS_CERTMAP2)
465 self.assertDictEqual(certmap_merged, certmap)
466 self.assertEqual('.gz', ext)
467
468 def test_ReadApkCerts_MultipleCompressionMethods(self):
469 target_files = self._write_apkcerts_txt(
470 self.APKCERTS_TXT2 + self.APKCERTS_TXT3,
471 ['Compressed1.apk.gz', 'Compressed4.apk.xz'])
472
473 with zipfile.ZipFile(target_files, 'r') as input_zip:
474 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
475
476 def test_ReadApkCerts_MismatchingKeys(self):
477 malformed_apkcerts_txt = (
478 'name="App1.apk" certificate="certs/cert1.x509.pem"'
479 ' private_key="certs/cert2.pk8"\n'
480 )
481 target_files = self._write_apkcerts_txt(malformed_apkcerts_txt)
482
483 with zipfile.ZipFile(target_files, 'r') as input_zip:
484 self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
485
Tao Bao04e1f012018-02-04 12:13:35 -0800486 def test_ExtractPublicKey(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800487 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
488 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
Tao Bao04e1f012018-02-04 12:13:35 -0800489 with open(pubkey, 'rb') as pubkey_fp:
490 self.assertEqual(pubkey_fp.read(), common.ExtractPublicKey(cert))
491
492 def test_ExtractPublicKey_invalidInput(self):
Tao Bao17e4e612018-02-16 17:12:54 -0800493 wrong_input = os.path.join(self.testdata_dir, 'testkey.pk8')
Tao Bao04e1f012018-02-04 12:13:35 -0800494 self.assertRaises(AssertionError, common.ExtractPublicKey, wrong_input)
495
Tao Bao17e4e612018-02-16 17:12:54 -0800496 def test_ParseCertificate(self):
497 cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
498
499 cmd = ['openssl', 'x509', '-in', cert, '-outform', 'DER']
500 proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
501 expected, _ = proc.communicate()
502 self.assertEqual(0, proc.returncode)
503
504 with open(cert) as cert_fp:
505 actual = common.ParseCertificate(cert_fp.read())
506 self.assertEqual(expected, actual)
507
Tao Baof47bf0f2018-03-21 23:28:51 -0700508 def test_GetMinSdkVersion(self):
509 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
510 self.assertEqual('24', common.GetMinSdkVersion(test_app))
511
512 def test_GetMinSdkVersion_invalidInput(self):
513 self.assertRaises(
514 common.ExternalError, common.GetMinSdkVersion, 'does-not-exist.apk')
515
516 def test_GetMinSdkVersionInt(self):
517 test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
518 self.assertEqual(24, common.GetMinSdkVersionInt(test_app, {}))
519
520 def test_GetMinSdkVersionInt_invalidInput(self):
521 self.assertRaises(
522 common.ExternalError, common.GetMinSdkVersionInt, 'does-not-exist.apk',
523 {})
524
Tao Bao818ddf52018-01-05 11:17:34 -0800525
Tao Baofc7e0e02018-02-13 13:54:02 -0800526class CommonUtilsTest(unittest.TestCase):
527
Tao Bao02a08592018-07-22 12:40:45 -0700528 def setUp(self):
529 self.testdata_dir = test_utils.get_testdata_dir()
530
Tao Baofc7e0e02018-02-13 13:54:02 -0800531 def tearDown(self):
532 common.Cleanup()
533
534 def test_GetSparseImage_emptyBlockMapFile(self):
535 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
536 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
537 target_files_zip.write(
538 test_utils.construct_sparse_image([
539 (0xCAC1, 6),
540 (0xCAC3, 3),
541 (0xCAC1, 4)]),
542 arcname='IMAGES/system.img')
543 target_files_zip.writestr('IMAGES/system.map', '')
544 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
545 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
546
Tao Baodba59ee2018-01-09 13:21:02 -0800547 tempdir = common.UnzipTemp(target_files)
548 with zipfile.ZipFile(target_files, 'r') as input_zip:
549 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800550
551 self.assertDictEqual(
552 {
553 '__COPY': RangeSet("0"),
554 '__NONZERO-0': RangeSet("1-5 9-12"),
555 },
556 sparse_image.file_map)
557
558 def test_GetSparseImage_invalidImageName(self):
559 self.assertRaises(
560 AssertionError, common.GetSparseImage, 'system2', None, None, False)
561 self.assertRaises(
562 AssertionError, common.GetSparseImage, 'unknown', None, None, False)
563
564 def test_GetSparseImage_missingBlockMapFile(self):
565 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
566 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
567 target_files_zip.write(
568 test_utils.construct_sparse_image([
569 (0xCAC1, 6),
570 (0xCAC3, 3),
571 (0xCAC1, 4)]),
572 arcname='IMAGES/system.img')
573 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
574 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
575
Tao Baodba59ee2018-01-09 13:21:02 -0800576 tempdir = common.UnzipTemp(target_files)
577 with zipfile.ZipFile(target_files, 'r') as input_zip:
578 self.assertRaises(
579 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
580 False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800581
582 def test_GetSparseImage_sharedBlocks_notAllowed(self):
583 """Tests the case of having overlapping blocks but disallowed."""
584 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
585 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
586 target_files_zip.write(
587 test_utils.construct_sparse_image([(0xCAC2, 16)]),
588 arcname='IMAGES/system.img')
589 # Block 10 is shared between two files.
590 target_files_zip.writestr(
591 'IMAGES/system.map',
592 '\n'.join([
593 '/system/file1 1-5 9-10',
594 '/system/file2 10-12']))
595 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
596 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
597
Tao Baodba59ee2018-01-09 13:21:02 -0800598 tempdir = common.UnzipTemp(target_files)
599 with zipfile.ZipFile(target_files, 'r') as input_zip:
600 self.assertRaises(
601 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
602 False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800603
604 def test_GetSparseImage_sharedBlocks_allowed(self):
605 """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true."""
606 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
607 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
608 # Construct an image with a care_map of "0-5 9-12".
609 target_files_zip.write(
610 test_utils.construct_sparse_image([(0xCAC2, 16)]),
611 arcname='IMAGES/system.img')
612 # Block 10 is shared between two files.
613 target_files_zip.writestr(
614 'IMAGES/system.map',
615 '\n'.join([
616 '/system/file1 1-5 9-10',
617 '/system/file2 10-12']))
618 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
619 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
620
Tao Baodba59ee2018-01-09 13:21:02 -0800621 tempdir = common.UnzipTemp(target_files)
622 with zipfile.ZipFile(target_files, 'r') as input_zip:
623 sparse_image = common.GetSparseImage('system', tempdir, input_zip, True)
Tao Baofc7e0e02018-02-13 13:54:02 -0800624
625 self.assertDictEqual(
626 {
627 '__COPY': RangeSet("0"),
628 '__NONZERO-0': RangeSet("6-8 13-15"),
629 '/system/file1': RangeSet("1-5 9-10"),
630 '/system/file2': RangeSet("11-12"),
631 },
632 sparse_image.file_map)
633
634 # '/system/file2' should be marked with 'uses_shared_blocks', but not with
635 # 'incomplete'.
636 self.assertTrue(
637 sparse_image.file_map['/system/file2'].extra['uses_shared_blocks'])
638 self.assertNotIn(
639 'incomplete', sparse_image.file_map['/system/file2'].extra)
640
641 # All other entries should look normal without any tags.
642 self.assertFalse(sparse_image.file_map['__COPY'].extra)
643 self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
644 self.assertFalse(sparse_image.file_map['/system/file1'].extra)
645
646 def test_GetSparseImage_incompleteRanges(self):
647 """Tests the case of ext4 images with holes."""
648 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
649 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
650 target_files_zip.write(
651 test_utils.construct_sparse_image([(0xCAC2, 16)]),
652 arcname='IMAGES/system.img')
653 target_files_zip.writestr(
654 'IMAGES/system.map',
655 '\n'.join([
656 '/system/file1 1-5 9-10',
657 '/system/file2 11-12']))
658 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
659 # '/system/file2' has less blocks listed (2) than actual (3).
660 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
661
Tao Baodba59ee2018-01-09 13:21:02 -0800662 tempdir = common.UnzipTemp(target_files)
663 with zipfile.ZipFile(target_files, 'r') as input_zip:
664 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
Tao Baofc7e0e02018-02-13 13:54:02 -0800665
666 self.assertFalse(sparse_image.file_map['/system/file1'].extra)
667 self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
668
Tao Baod3554e62018-07-10 15:31:22 -0700669 def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
670 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
671 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
672 target_files_zip.write(
673 test_utils.construct_sparse_image([(0xCAC2, 16)]),
674 arcname='IMAGES/system.img')
675 target_files_zip.writestr(
676 'IMAGES/system.map',
677 '\n'.join([
678 '//system/file1 1-5 9-10',
679 '//system/file2 11-12',
680 '/system/app/file3 13-15']))
681 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
682 # '/system/file2' has less blocks listed (2) than actual (3).
683 target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
684 # '/system/app/file3' has less blocks listed (3) than actual (4).
685 target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))
686
687 tempdir = common.UnzipTemp(target_files)
688 with zipfile.ZipFile(target_files, 'r') as input_zip:
689 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
690
691 self.assertFalse(sparse_image.file_map['//system/file1'].extra)
692 self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
693 self.assertTrue(
694 sparse_image.file_map['/system/app/file3'].extra['incomplete'])
695
696 def test_GetSparseImage_systemRootImage_nonSystemFiles(self):
697 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
698 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
699 target_files_zip.write(
700 test_utils.construct_sparse_image([(0xCAC2, 16)]),
701 arcname='IMAGES/system.img')
702 target_files_zip.writestr(
703 'IMAGES/system.map',
704 '\n'.join([
705 '//system/file1 1-5 9-10',
706 '//init.rc 13-15']))
707 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
708 # '/init.rc' has less blocks listed (3) than actual (4).
709 target_files_zip.writestr('ROOT/init.rc', os.urandom(4096 * 4))
710
711 tempdir = common.UnzipTemp(target_files)
712 with zipfile.ZipFile(target_files, 'r') as input_zip:
713 sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
714
715 self.assertFalse(sparse_image.file_map['//system/file1'].extra)
716 self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
717
718 def test_GetSparseImage_fileNotFound(self):
719 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
720 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
721 target_files_zip.write(
722 test_utils.construct_sparse_image([(0xCAC2, 16)]),
723 arcname='IMAGES/system.img')
724 target_files_zip.writestr(
725 'IMAGES/system.map',
726 '\n'.join([
727 '//system/file1 1-5 9-10',
728 '//system/file2 11-12']))
729 target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
730
731 tempdir = common.UnzipTemp(target_files)
732 with zipfile.ZipFile(target_files, 'r') as input_zip:
733 self.assertRaises(
734 AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
735 False)
736
Tao Bao02a08592018-07-22 12:40:45 -0700737 def test_GetAvbChainedPartitionArg(self):
738 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
739 info_dict = {
740 'avb_avbtool': 'avbtool',
741 'avb_system_key_path': pubkey,
742 'avb_system_rollback_index_location': 2,
743 }
744 args = common.GetAvbChainedPartitionArg('system', info_dict).split(':')
745 self.assertEqual(3, len(args))
746 self.assertEqual('system', args[0])
747 self.assertEqual('2', args[1])
748 self.assertTrue(os.path.exists(args[2]))
749
750 def test_GetAvbChainedPartitionArg_withPrivateKey(self):
751 key = os.path.join(self.testdata_dir, 'testkey.key')
752 info_dict = {
753 'avb_avbtool': 'avbtool',
754 'avb_product_key_path': key,
755 'avb_product_rollback_index_location': 2,
756 }
757 args = common.GetAvbChainedPartitionArg('product', info_dict).split(':')
758 self.assertEqual(3, len(args))
759 self.assertEqual('product', args[0])
760 self.assertEqual('2', args[1])
761 self.assertTrue(os.path.exists(args[2]))
762
763 def test_GetAvbChainedPartitionArg_withSpecifiedKey(self):
764 info_dict = {
765 'avb_avbtool': 'avbtool',
766 'avb_system_key_path': 'does-not-exist',
767 'avb_system_rollback_index_location': 2,
768 }
769 pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
770 args = common.GetAvbChainedPartitionArg(
771 'system', info_dict, pubkey).split(':')
772 self.assertEqual(3, len(args))
773 self.assertEqual('system', args[0])
774 self.assertEqual('2', args[1])
775 self.assertTrue(os.path.exists(args[2]))
776
777 def test_GetAvbChainedPartitionArg_invalidKey(self):
778 pubkey = os.path.join(self.testdata_dir, 'testkey_with_passwd.x509.pem')
779 info_dict = {
780 'avb_avbtool': 'avbtool',
781 'avb_system_key_path': pubkey,
782 'avb_system_rollback_index_location': 2,
783 }
784 self.assertRaises(
785 AssertionError, common.GetAvbChainedPartitionArg, 'system', info_dict)
786
Tao Baoa57ab9f2018-08-24 12:08:38 -0700787 INFO_DICT_DEFAULT = {
788 'recovery_api_version': 3,
789 'fstab_version': 2,
790 'system_root_image': 'true',
791 'no_recovery' : 'true',
792 'recovery_as_boot': 'true',
793 }
794
795 @staticmethod
796 def _test_LoadInfoDict_createTargetFiles(info_dict, fstab_path):
797 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
798 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
799 info_values = ''.join(
800 ['{}={}\n'.format(k, v) for k, v in sorted(info_dict.iteritems())])
801 common.ZipWriteStr(target_files_zip, 'META/misc_info.txt', info_values)
802
803 FSTAB_TEMPLATE = "/dev/block/system {} ext4 ro,barrier=1 defaults"
804 if info_dict.get('system_root_image') == 'true':
805 fstab_values = FSTAB_TEMPLATE.format('/')
806 else:
807 fstab_values = FSTAB_TEMPLATE.format('/system')
808 common.ZipWriteStr(target_files_zip, fstab_path, fstab_values)
Tao Bao410ad8b2018-08-24 12:08:38 -0700809
810 common.ZipWriteStr(
811 target_files_zip, 'META/file_contexts', 'file-contexts')
Tao Baoa57ab9f2018-08-24 12:08:38 -0700812 return target_files
813
814 def test_LoadInfoDict(self):
815 target_files = self._test_LoadInfoDict_createTargetFiles(
816 self.INFO_DICT_DEFAULT,
817 'BOOT/RAMDISK/system/etc/recovery.fstab')
818 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
819 loaded_dict = common.LoadInfoDict(target_files_zip)
820 self.assertEqual(3, loaded_dict['recovery_api_version'])
821 self.assertEqual(2, loaded_dict['fstab_version'])
822 self.assertIn('/', loaded_dict['fstab'])
823 self.assertIn('/system', loaded_dict['fstab'])
824
825 def test_LoadInfoDict_legacyRecoveryFstabPath(self):
826 target_files = self._test_LoadInfoDict_createTargetFiles(
827 self.INFO_DICT_DEFAULT,
828 'BOOT/RAMDISK/etc/recovery.fstab')
829 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
830 loaded_dict = common.LoadInfoDict(target_files_zip)
831 self.assertEqual(3, loaded_dict['recovery_api_version'])
832 self.assertEqual(2, loaded_dict['fstab_version'])
833 self.assertIn('/', loaded_dict['fstab'])
834 self.assertIn('/system', loaded_dict['fstab'])
835
836 def test_LoadInfoDict_dirInput(self):
837 target_files = self._test_LoadInfoDict_createTargetFiles(
838 self.INFO_DICT_DEFAULT,
839 'BOOT/RAMDISK/system/etc/recovery.fstab')
840 unzipped = common.UnzipTemp(target_files)
841 loaded_dict = common.LoadInfoDict(unzipped)
842 self.assertEqual(3, loaded_dict['recovery_api_version'])
843 self.assertEqual(2, loaded_dict['fstab_version'])
844 self.assertIn('/', loaded_dict['fstab'])
845 self.assertIn('/system', loaded_dict['fstab'])
846
847 def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self):
848 target_files = self._test_LoadInfoDict_createTargetFiles(
849 self.INFO_DICT_DEFAULT,
850 'BOOT/RAMDISK/system/etc/recovery.fstab')
851 unzipped = common.UnzipTemp(target_files)
852 loaded_dict = common.LoadInfoDict(unzipped)
853 self.assertEqual(3, loaded_dict['recovery_api_version'])
854 self.assertEqual(2, loaded_dict['fstab_version'])
855 self.assertIn('/', loaded_dict['fstab'])
856 self.assertIn('/system', loaded_dict['fstab'])
857
858 def test_LoadInfoDict_systemRootImageFalse(self):
859 # Devices not using system-as-root nor recovery-as-boot. Non-A/B devices
860 # launched prior to P will likely have this config.
861 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
862 del info_dict['no_recovery']
863 del info_dict['system_root_image']
864 del info_dict['recovery_as_boot']
865 target_files = self._test_LoadInfoDict_createTargetFiles(
866 info_dict,
867 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
868 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
869 loaded_dict = common.LoadInfoDict(target_files_zip)
870 self.assertEqual(3, loaded_dict['recovery_api_version'])
871 self.assertEqual(2, loaded_dict['fstab_version'])
872 self.assertNotIn('/', loaded_dict['fstab'])
873 self.assertIn('/system', loaded_dict['fstab'])
874
875 def test_LoadInfoDict_recoveryAsBootFalse(self):
876 # Devices using system-as-root, but with standalone recovery image. Non-A/B
877 # devices launched since P will likely have this config.
878 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
879 del info_dict['no_recovery']
880 del info_dict['recovery_as_boot']
881 target_files = self._test_LoadInfoDict_createTargetFiles(
882 info_dict,
883 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
884 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
885 loaded_dict = common.LoadInfoDict(target_files_zip)
886 self.assertEqual(3, loaded_dict['recovery_api_version'])
887 self.assertEqual(2, loaded_dict['fstab_version'])
888 self.assertIn('/', loaded_dict['fstab'])
889 self.assertIn('/system', loaded_dict['fstab'])
890
891 def test_LoadInfoDict_noRecoveryTrue(self):
892 # Device doesn't have a recovery partition at all.
893 info_dict = copy.copy(self.INFO_DICT_DEFAULT)
894 del info_dict['recovery_as_boot']
895 target_files = self._test_LoadInfoDict_createTargetFiles(
896 info_dict,
897 'RECOVERY/RAMDISK/system/etc/recovery.fstab')
898 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
899 loaded_dict = common.LoadInfoDict(target_files_zip)
900 self.assertEqual(3, loaded_dict['recovery_api_version'])
901 self.assertEqual(2, loaded_dict['fstab_version'])
902 self.assertIsNone(loaded_dict['fstab'])
903
Tao Bao410ad8b2018-08-24 12:08:38 -0700904 def test_LoadInfoDict_missingMetaMiscInfoTxt(self):
905 target_files = self._test_LoadInfoDict_createTargetFiles(
906 self.INFO_DICT_DEFAULT,
907 'BOOT/RAMDISK/system/etc/recovery.fstab')
908 common.ZipDelete(target_files, 'META/misc_info.txt')
909 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
910 self.assertRaises(ValueError, common.LoadInfoDict, target_files_zip)
911
912 def test_LoadInfoDict_repacking(self):
913 target_files = self._test_LoadInfoDict_createTargetFiles(
914 self.INFO_DICT_DEFAULT,
915 'BOOT/RAMDISK/system/etc/recovery.fstab')
916 unzipped = common.UnzipTemp(target_files)
917 loaded_dict = common.LoadInfoDict(unzipped, True)
918 self.assertEqual(3, loaded_dict['recovery_api_version'])
919 self.assertEqual(2, loaded_dict['fstab_version'])
920 self.assertIn('/', loaded_dict['fstab'])
921 self.assertIn('/system', loaded_dict['fstab'])
922 self.assertEqual(
923 os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir'])
924 self.assertEqual(
925 os.path.join(unzipped, 'META', 'root_filesystem_config.txt'),
926 loaded_dict['root_fs_config'])
927
928 def test_LoadInfoDict_repackingWithZipFileInput(self):
929 target_files = self._test_LoadInfoDict_createTargetFiles(
930 self.INFO_DICT_DEFAULT,
931 'BOOT/RAMDISK/system/etc/recovery.fstab')
932 with zipfile.ZipFile(target_files, 'r') as target_files_zip:
933 self.assertRaises(
934 AssertionError, common.LoadInfoDict, target_files_zip, True)
935
Tao Baofc7e0e02018-02-13 13:54:02 -0800936
Tianjie Xu9c384d22017-06-20 17:00:55 -0700937class InstallRecoveryScriptFormatTest(unittest.TestCase):
Tao Bao1c830bf2017-12-25 10:43:47 -0800938 """Checks the format of install-recovery.sh.
Tianjie Xu9c384d22017-06-20 17:00:55 -0700939
Tao Bao1c830bf2017-12-25 10:43:47 -0800940 Its format should match between common.py and validate_target_files.py.
941 """
Tianjie Xu9c384d22017-06-20 17:00:55 -0700942
943 def setUp(self):
Tao Bao1c830bf2017-12-25 10:43:47 -0800944 self._tempdir = common.MakeTempDir()
Tianjie Xu9c384d22017-06-20 17:00:55 -0700945 # Create a dummy dict that contains the fstab info for boot&recovery.
946 self._info = {"fstab" : {}}
Tao Bao1c830bf2017-12-25 10:43:47 -0800947 dummy_fstab = [
948 "/dev/soc.0/by-name/boot /boot emmc defaults defaults",
949 "/dev/soc.0/by-name/recovery /recovery emmc defaults defaults"]
Tao Bao31b08072017-11-08 15:50:59 -0800950 self._info["fstab"] = common.LoadRecoveryFSTab("\n".join, 2, dummy_fstab)
Tianjie Xudf055582017-11-07 12:22:58 -0800951 # Construct the gzipped recovery.img and boot.img
952 self.recovery_data = bytearray([
953 0x1f, 0x8b, 0x08, 0x00, 0x81, 0x11, 0x02, 0x5a, 0x00, 0x03, 0x2b, 0x4a,
954 0x4d, 0xce, 0x2f, 0x4b, 0x2d, 0xaa, 0x04, 0x00, 0xc9, 0x93, 0x43, 0xf3,
955 0x08, 0x00, 0x00, 0x00
956 ])
957 # echo -n "boot" | gzip -f | hd
958 self.boot_data = bytearray([
959 0x1f, 0x8b, 0x08, 0x00, 0x8c, 0x12, 0x02, 0x5a, 0x00, 0x03, 0x4b, 0xca,
960 0xcf, 0x2f, 0x01, 0x00, 0xc4, 0xae, 0xed, 0x46, 0x04, 0x00, 0x00, 0x00
961 ])
Tianjie Xu9c384d22017-06-20 17:00:55 -0700962
963 def _out_tmp_sink(self, name, data, prefix="SYSTEM"):
964 loc = os.path.join(self._tempdir, prefix, name)
965 if not os.path.exists(os.path.dirname(loc)):
966 os.makedirs(os.path.dirname(loc))
967 with open(loc, "w+") as f:
968 f.write(data)
969
970 def test_full_recovery(self):
Tao Bao31b08072017-11-08 15:50:59 -0800971 recovery_image = common.File("recovery.img", self.recovery_data)
972 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700973 self._info["full_recovery_image"] = "true"
974
975 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
976 recovery_image, boot_image, self._info)
977 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
978 self._info)
979
980 def test_recovery_from_boot(self):
Tao Bao31b08072017-11-08 15:50:59 -0800981 recovery_image = common.File("recovery.img", self.recovery_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700982 self._out_tmp_sink("recovery.img", recovery_image.data, "IMAGES")
Tao Bao31b08072017-11-08 15:50:59 -0800983 boot_image = common.File("boot.img", self.boot_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700984 self._out_tmp_sink("boot.img", boot_image.data, "IMAGES")
985
986 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
987 recovery_image, boot_image, self._info)
988 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
989 self._info)
990 # Validate 'recovery-from-boot' with bonus argument.
991 self._out_tmp_sink("etc/recovery-resource.dat", "bonus", "SYSTEM")
992 common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
993 recovery_image, boot_image, self._info)
994 validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
995 self._info)
996
997 def tearDown(self):
Tao Bao1c830bf2017-12-25 10:43:47 -0800998 common.Cleanup()