summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYi-Yo Chiang <yochiang@google.com>2021-04-08 10:56:29 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-04-08 10:56:29 +0000
commit86d7f88cf8dbdb6d97d5fdc4c5ffa3ce9d6eb69c (patch)
tree82775425a21bbd4c529b6d36329f722d60f3d639
parent3b29fe3f634dbda5c84eb5caef5d9e16faad79a9 (diff)
parent3c1e9234d92949edb16c48903563f88943203df8 (diff)
downloadplatform_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.py98
-rwxr-xr-xunpack_bootimg.py83
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()