diff options
| author | Yi-Yo Chiang <yochiang@google.com> | 2021-04-08 10:56:29 +0000 |
|---|---|---|
| committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-04-08 10:56:29 +0000 |
| commit | 86d7f88cf8dbdb6d97d5fdc4c5ffa3ce9d6eb69c (patch) | |
| tree | 82775425a21bbd4c529b6d36329f722d60f3d639 | |
| parent | 3b29fe3f634dbda5c84eb5caef5d9e16faad79a9 (diff) | |
| parent | 3c1e9234d92949edb16c48903563f88943203df8 (diff) | |
| download | platform_system_tools_mkbootimg-86d7f88cf8dbdb6d97d5fdc4c5ffa3ce9d6eb69c.tar.gz platform_system_tools_mkbootimg-86d7f88cf8dbdb6d97d5fdc4c5ffa3ce9d6eb69c.tar.bz2 platform_system_tools_mkbootimg-86d7f88cf8dbdb6d97d5fdc4c5ffa3ce9d6eb69c.zip | |
unpack_bootimg: Add --format={info,mkbootimg} option am: 64b181cc95 am: 3c1e9234d9
Original change: https://android-review.googlesource.com/c/platform/system/tools/mkbootimg/+/1663143
Change-Id: Ia2b3394756c2916ffe877f6a190aa783dbf106d2
| -rw-r--r-- | tests/mkbootimg_test.py | 98 | ||||
| -rwxr-xr-x | unpack_bootimg.py | 83 |
2 files changed, 180 insertions, 1 deletions
diff --git a/tests/mkbootimg_test.py b/tests/mkbootimg_test.py index 40700e1..110b3cb 100644 --- a/tests/mkbootimg_test.py +++ b/tests/mkbootimg_test.py @@ -16,10 +16,12 @@ """Tests mkbootimg and unpack_bootimg.""" +import filecmp import json import logging import os import random +import shlex import subprocess import sys import tempfile @@ -307,6 +309,102 @@ class MkbootimgTest(unittest.TestCase): ]) self.fail(msg) + def test_unpack_vendor_boot_image_v4_format_mkbootimg(self): + """Tests `unpack_bootimg --format=mkbootimg`.""" + with tempfile.TemporaryDirectory() as temp_out_dir: + vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img') + vendor_boot_reconstructed = os.path.join( + temp_out_dir, 'vendor_boot.reconstructed') + dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000) + ramdisk1 = generate_test_file( + os.path.join(temp_out_dir, 'ramdisk1'), 0x121212) + ramdisk2 = generate_test_file( + os.path.join(temp_out_dir, 'ramdisk2'), 0x212121) + bootconfig = generate_test_file( + os.path.join(temp_out_dir, 'bootconfig'), 0x1000) + + mkbootimg_cmds = [ + 'mkbootimg', + '--header_version', '4', + '--vendor_boot', vendor_boot_img, + '--dtb', dtb, + '--vendor_ramdisk', ramdisk1, + '--ramdisk_type', 'PLATFORM', + '--ramdisk_name', 'RAMDISK1', + '--vendor_ramdisk_fragment', ramdisk1, + '--ramdisk_type', 'DLKM', + '--ramdisk_name', 'RAMDISK2', + '--board_id0', '0xC0FFEE', + '--board_id15', '0x15151515', + '--vendor_ramdisk_fragment', ramdisk2, + '--vendor_bootconfig', bootconfig, + ] + unpack_bootimg_cmds = [ + 'unpack_bootimg', + '--boot_img', vendor_boot_img, + '--out', os.path.join(temp_out_dir, 'out'), + '--format=mkbootimg', + ] + subprocess.run(mkbootimg_cmds, check=True) + result = subprocess.run(unpack_bootimg_cmds, check=True, + capture_output=True, encoding='utf-8') + mkbootimg_cmds = [ + 'mkbootimg', + '--vendor_boot', vendor_boot_reconstructed, + ] + unpack_format_args = shlex.split(result.stdout) + mkbootimg_cmds.extend(unpack_format_args) + + subprocess.run(mkbootimg_cmds, check=True) + self.assertTrue( + filecmp.cmp(vendor_boot_img, vendor_boot_reconstructed), + 'reconstructed vendor_boot image differ from the original') + + # Also check that -0, --null are as expected. + unpack_bootimg_cmds.append('--null') + result = subprocess.run(unpack_bootimg_cmds, check=True, + capture_output=True, encoding='utf-8') + unpack_format_null_args = result.stdout + self.assertEqual('\0'.join(unpack_format_args) + '\0', + unpack_format_null_args) + + def test_unpack_vendor_boot_image_v3_format_mkbootimg(self): + """Tests `unpack_bootimg --format=mkbootimg`.""" + with tempfile.TemporaryDirectory() as temp_out_dir: + vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img') + vendor_boot_reconstructed = os.path.join( + temp_out_dir, 'vendor_boot.reconstructed') + dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000) + ramdisk1 = generate_test_file( + os.path.join(temp_out_dir, 'ramdisk1'), 0x121212) + + mkbootimg_cmds = [ + 'mkbootimg', + '--header_version', '3', + '--vendor_boot', vendor_boot_img, + '--dtb', dtb, + '--vendor_ramdisk', ramdisk1, + ] + unpack_bootimg_cmds = [ + 'unpack_bootimg', + '--boot_img', vendor_boot_img, + '--out', os.path.join(temp_out_dir, 'out'), + '--format=mkbootimg', + ] + subprocess.run(mkbootimg_cmds, check=True) + result = subprocess.run(unpack_bootimg_cmds, check=True, + capture_output=True, encoding='utf-8') + mkbootimg_cmds = [ + 'mkbootimg', + '--vendor_boot', vendor_boot_reconstructed, + ] + mkbootimg_cmds.extend(shlex.split(result.stdout)) + + subprocess.run(mkbootimg_cmds, check=True) + self.assertTrue( + filecmp.cmp(vendor_boot_img, vendor_boot_reconstructed), + 'reconstructed vendor_boot image differ from the original') + def test_unpack_boot_image_v3_json_args(self): """Tests mkbootimg_args.json when unpacking a boot image version 3.""" with tempfile.TemporaryDirectory() as temp_out_dir: diff --git a/unpack_bootimg.py b/unpack_bootimg.py index 8861e7a..1a01da2 100755 --- a/unpack_bootimg.py +++ b/unpack_bootimg.py @@ -23,6 +23,7 @@ from argparse import ArgumentParser, FileType, RawDescriptionHelpFormatter from struct import unpack import json import os +import shlex BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096 VENDOR_RAMDISK_NAME_SIZE = 32 @@ -136,6 +137,7 @@ def unpack_boot_image(args): """extracts kernel, ramdisk, second bootloader and recovery dtbo""" boot_magic = unpack('8s', args.boot_img.read(8))[0].decode() print('boot_magic: %s' % boot_magic) + # TODO(yochiang): Support --format=mkbootimg kernel_ramdisk_second_info = unpack('9I', args.boot_img.read(9 * 4)) @@ -324,6 +326,44 @@ class VendorBootImageInfoFormatter: return '\n'.join(lines) + def format_mkbootimg_argument(self, null=False): + args = [] + args.extend(['--header_version', str(self.header_version)]) + args.extend(['--pagesize', f'{self.page_size:#010x}']) + args.extend(['--base', f'{0:#010x}']) + args.extend(['--kernel_offset', f'{self.kernel_load_address:#010x}']) + args.extend(['--ramdisk_offset', f'{self.ramdisk_load_address:#010x}']) + args.extend(['--tags_offset', f'{self.tags_load_address:#010x}']) + args.extend(['--dtb_offset', f'{self.dtb_load_address:#018x}']) + args.extend(['--vendor_cmdline', self.cmdline]) + args.extend(['--board', self.product_name]) + + dtb_path = os.path.join(self.image_dir, 'dtb') + args.extend(['--dtb', dtb_path]) + + if self.header_version > 3: + bootconfig_path = os.path.join(self.image_dir, 'bootconfig') + args.extend(['--vendor_bootconfig', bootconfig_path]) + + for entry in self.vendor_ramdisk_table: + (output_ramdisk_name, _, _, ramdisk_type, + ramdisk_name, board_id) = entry + args.extend(['--ramdisk_type', str(ramdisk_type)]) + args.extend(['--ramdisk_name', ramdisk_name]) + for idx, e in enumerate(board_id): + if e: + args.extend([f'--board_id{idx}', f'{e:#010x}']) + vendor_ramdisk_path = os.path.join( + self.image_dir, output_ramdisk_name) + args.extend(['--vendor_ramdisk_fragment', vendor_ramdisk_path]) + else: + vendor_ramdisk_path = os.path.join(self.image_dir, 'vendor_ramdisk') + args.extend(['--vendor_ramdisk', vendor_ramdisk_path]) + + if null: + return '\0'.join(args) + '\0' + return shlex.join(args) + def format_json_dict(self): """Returns a dict of arguments to be used in mkbootimg.py later.""" args_dict = {} @@ -450,7 +490,11 @@ def unpack_vendor_boot_image(args): with open(os.path.join(args.out, MKBOOTIMG_ARGS_FILE), 'w') as f: json.dump(mkbootimg_args, f, sort_keys=True, indent=4) - print(info.format_pretty_text()) + if args.format == 'mkbootimg': + print(info.format_mkbootimg_argument(null=args.null), + end='' if args.null else None) + else: + print(info.format_pretty_text()) def unpack_image(args): @@ -462,16 +506,53 @@ def unpack_image(args): unpack_vendor_boot_image(args) +def get_unpack_usage(): + return """Output format: + + * info + + Pretty-printed info-rich text format suitable for human inspection. + + * mkbootimg + + Output shell-escaped (quoted) argument strings that can be used to + reconstruct the boot image. For example: + + $ unpack_bootimg --boot_img vendor_boot.img --out out --format=mkbootimg | + tee mkbootimg_args + $ sh -c "mkbootimg $(cat mkbootimg_args) --vendor_boot repacked.img" + + vendor_boot.img and repacked.img would be equivalent. + + If the -0 option is specified, output unescaped null-terminated argument + strings that are suitable to be parsed by a shell script (xargs -0 format): + + $ unpack_bootimg --boot_img vendor_boot.img --out out --format=mkbootimg \\ + -0 | tee mkbootimg_args + $ declare -a MKBOOTIMG_ARGS=() + $ while IFS= read -r -d '' ARG; do + MKBOOTIMG_ARGS+=("${ARG}") + done <mkbootimg_args + $ mkbootimg "${MKBOOTIMG_ARGS[@]}" --vendor_boot repacked.img +""" + + def parse_cmdline(): """parse command line arguments""" parser = ArgumentParser( formatter_class=RawDescriptionHelpFormatter, description='Unpacks boot, recovery or vendor_boot image.', + epilog=get_unpack_usage(), ) parser.add_argument('--boot_img', type=FileType('rb'), required=True, help='path to the boot, recovery or vendor_boot image') parser.add_argument('--out', default='out', help='output directory of the unpacked images') + parser.add_argument('--format', choices=['info', 'mkbootimg'], + default='info', + help='text output format (default: info)') + parser.add_argument('-0', '--null', action='store_true', + help='output null-terminated argument strings') return parser.parse_args() |
