Snap for 8426163 from 41bec4c46b0045ba68939eb0689fddd416a2171a to mainline-tzdata2-release

Change-Id: I40b6fc364b72ed23a0ca541baa3893922d72ba76
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index bee8a64..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__
diff --git a/Android.bp b/Android.bp
index 23c55b8..c3cf746 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,9 +1,5 @@
 // Copyright 2012 The Android Open Source Project
 
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
 cc_library_headers {
     name: "libmkbootimg_abi_headers",
     vendor_available: true,
@@ -21,10 +17,6 @@
             enabled: true,
         },
     },
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.virt",
-    ],
 }
 
 cc_library {
@@ -42,14 +34,16 @@
 
 python_defaults {
     name: "mkbootimg_defaults",
+
     version: {
         py2: {
-            enabled: false,
-        },
-        py3: {
             enabled: true,
             embedded_launcher: true,
         },
+        py3: {
+            enabled: false,
+            embedded_launcher: false,
+        },
     },
 }
 
@@ -59,9 +53,6 @@
     srcs: [
         "mkbootimg.py",
     ],
-    required: [
-        "avbtool",
-    ],
 }
 
 python_binary_host {
@@ -71,38 +62,3 @@
         "unpack_bootimg.py",
     ],
 }
-
-
-python_binary_host {
-    name: "repack_bootimg",
-    defaults: ["mkbootimg_defaults"],
-    srcs: [
-        "repack_bootimg.py",
-    ],
-    required: [
-        "lz4",
-        "minigzip",
-        "mkbootfs",
-        "mkbootimg",
-        "toybox",
-        "unpack_bootimg",
-    ],
-}
-
-python_test_host {
-    name: "mkbootimg_test",
-    defaults: ["mkbootimg_defaults"],
-    main: "tests/mkbootimg_test.py",
-    srcs: [
-        "tests/mkbootimg_test.py",
-    ],
-    data: [
-        ":avbtool",
-        ":mkbootimg",
-        ":unpack_bootimg",
-        "tests/data/*",
-    ],
-    test_options: {
-        unit_test: true,
-    },
-}
diff --git a/OWNERS b/OWNERS
index 51e09a2..de2d568 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,2 @@
 hridya@google.com
 smuckle@google.com
-yochiang@google.com
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 734a94d..d937da1 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,3 @@
 [Builtin Hooks]
-pylint = true
+pylint2 = true
+pylint3 = true
diff --git a/include/bootimg/bootimg.h b/include/bootimg/bootimg.h
index 8ad95a8..8c9f6ee 100644
--- a/include/bootimg/bootimg.h
+++ b/include/bootimg/bootimg.h
@@ -29,41 +29,8 @@
 #define VENDOR_BOOT_ARGS_SIZE 2048
 #define VENDOR_BOOT_NAME_SIZE 16
 
-#define VENDOR_RAMDISK_TYPE_NONE 0
-#define VENDOR_RAMDISK_TYPE_PLATFORM 1
-#define VENDOR_RAMDISK_TYPE_RECOVERY 2
-#define VENDOR_RAMDISK_TYPE_DLKM 3
-#define VENDOR_RAMDISK_NAME_SIZE 32
-#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16
-
-/* When a boot header is of version 0, the structure of boot image is as
- * follows:
- *
- * +-----------------+
- * | boot header     | 1 page
- * +-----------------+
- * | kernel          | n pages
- * +-----------------+
- * | ramdisk         | m pages
- * +-----------------+
- * | second stage    | o pages
- * +-----------------+
- *
- * n = (kernel_size + page_size - 1) / page_size
- * m = (ramdisk_size + page_size - 1) / page_size
- * o = (second_size + page_size - 1) / page_size
- *
- * 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
- * 2. second is optional (second_size == 0 -> no second)
- * 3. load each element (kernel, ramdisk, second) at
- *    the specified physical address (kernel_addr, etc)
- * 4. prepare tags at tag_addr.  kernel_args[] is
- *    appended to the kernel commandline in the tags.
- * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- * 6. if second_size != 0: jump to second_addr
- *    else: jump to kernel_addr
- */
+// The bootloader expects the structure of boot_img_hdr with header
+// version 0 to be as follows:
 struct boot_img_hdr_v0 {
     // Must be BOOT_MAGIC.
     uint8_t magic[BOOT_MAGIC_SIZE];
@@ -103,13 +70,12 @@
 
     uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
-    uint8_t cmdline[BOOT_ARGS_SIZE]; /* asciiz kernel commandline */
+    uint8_t cmdline[BOOT_ARGS_SIZE];
 
     uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
 
     // Supplemental command line data; kept here to maintain
     // binary compatibility with older versions of mkbootimg.
-    // Asciiz.
     uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
 } __attribute__((packed));
 
@@ -119,40 +85,35 @@
  */
 typedef struct boot_img_hdr_v0 boot_img_hdr;
 
-/* When a boot header is of version 1, the structure of boot image is as
+/* When a boot header is of version 0, the structure of boot image is as
  * follows:
  *
- * +---------------------+
- * | boot header         | 1 page
- * +---------------------+
- * | kernel              | n pages
- * +---------------------+
- * | ramdisk             | m pages
- * +---------------------+
- * | second stage        | o pages
- * +---------------------+
- * | recovery dtbo/acpio | p pages
- * +---------------------+
+ * +-----------------+
+ * | boot header     | 1 page
+ * +-----------------+
+ * | kernel          | n pages
+ * +-----------------+
+ * | ramdisk         | m pages
+ * +-----------------+
+ * | second stage    | o pages
+ * +-----------------+
  *
  * n = (kernel_size + page_size - 1) / page_size
  * m = (ramdisk_size + page_size - 1) / page_size
  * o = (second_size + page_size - 1) / page_size
- * p = (recovery_dtbo_size + page_size - 1) / page_size
  *
  * 0. all entities are page_size aligned in flash
  * 1. kernel and ramdisk are required (size != 0)
- * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
- *    devices(recovery_dtbo_size != 0)
- * 3. second is optional (second_size == 0 -> no second)
- * 4. load each element (kernel, ramdisk, second) at
+ * 2. second is optional (second_size == 0 -> no second)
+ * 3. load each element (kernel, ramdisk, second) at
  *    the specified physical address (kernel_addr, etc)
- * 5. If booting to recovery mode in a non-A/B device, extract recovery
- *    dtbo/acpio and apply the correct set of overlays on the base device tree
- *    depending on the hardware/product revision.
- * 6. set up registers for kernel entry as required by your architecture
- * 7. if second_size != 0: jump to second_addr
+ * 4. prepare tags at tag_addr.  kernel_args[] is
+ *    appended to the kernel commandline in the tags.
+ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 6. if second_size != 0: jump to second_addr
  *    else: jump to kernel_addr
  */
+
 struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
     uint32_t recovery_dtbo_size;   /* size in bytes for recovery DTBO/ACPIO image */
     uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
@@ -279,7 +240,6 @@
     // Version of the boot image header.
     uint32_t header_version;
 
-    // Asciiz kernel commandline.
     uint8_t cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
 } __attribute__((packed));
 
@@ -297,7 +257,7 @@
 
     uint32_t vendor_ramdisk_size; /* size in bytes */
 
-    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; /* asciiz kernel commandline */
+    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE];
 
     uint32_t tags_addr; /* physical addr for kernel tags (if required) */
     uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
@@ -307,114 +267,3 @@
     uint32_t dtb_size; /* size in bytes for DTB image */
     uint64_t dtb_addr; /* physical load address for DTB image */
 } __attribute__((packed));
-
-/* When the boot image header has a version of 4, the structure of the boot
- * image is as follows:
- *
- * +---------------------+
- * | boot header         | 4096 bytes
- * +---------------------+
- * | kernel              | m pages
- * +---------------------+
- * | ramdisk             | n pages
- * +---------------------+
- * | boot signature      | g pages
- * +---------------------+
- *
- * m = (kernel_size + 4096 - 1) / 4096
- * n = (ramdisk_size + 4096 - 1) / 4096
- * g = (signature_size + 4096 - 1) / 4096
- *
- * Note that in version 4 of the boot image header, page size is fixed at 4096
- * bytes.
- *
- * The structure of the vendor boot image version 4, which is required to be
- * present when a version 4 boot image is used, is as follows:
- *
- * +------------------------+
- * | vendor boot header     | o pages
- * +------------------------+
- * | vendor ramdisk section | p pages
- * +------------------------+
- * | dtb                    | q pages
- * +------------------------+
- * | vendor ramdisk table   | r pages
- * +------------------------+
- * | bootconfig             | s pages
- * +------------------------+
- *
- * o = (2128 + page_size - 1) / page_size
- * p = (vendor_ramdisk_size + page_size - 1) / page_size
- * q = (dtb_size + page_size - 1) / page_size
- * r = (vendor_ramdisk_table_size + page_size - 1) / page_size
- * s = (vendor_bootconfig_size + page_size - 1) / page_size
- *
- * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can
- * be included in the vendor boot image. The bootloader can select a subset of
- * ramdisks to load at runtime. To help the bootloader select the ramdisks, each
- * ramdisk is tagged with a type tag and a set of hardware identifiers
- * describing the board, soc or platform that this ramdisk is intended for.
- *
- * The vendor ramdisk section is consist of multiple ramdisk images concatenated
- * one after another, and vendor_ramdisk_size is the size of the section, which
- * is the total size of all the ramdisks included in the vendor boot image.
- *
- * The vendor ramdisk table holds the size, offset, type, name and hardware
- * identifiers of each ramdisk. The type field denotes the type of its content.
- * The vendor ramdisk names are unique. The hardware identifiers are specified
- * in the board_id field in each table entry. The board_id field is consist of a
- * vector of unsigned integer words, and the encoding scheme is defined by the
- * hardware vendor.
- *
- * For the different type of ramdisks, there are:
- *    - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified.
- *    - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so
- *      the bootloader should always load these into memory.
- *    - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so
- *      the bootloader should load these when booting into recovery.
- *    - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel
- *      modules.
- *
- * Version 4 of the vendor boot image also adds a bootconfig section to the end
- * of the image. This section contains Boot Configuration parameters known at
- * build time. The bootloader is responsible for placing this section directly
- * after the generic ramdisk, followed by the bootconfig trailer, before
- * entering the kernel.
- *
- * 0. all entities in the boot image are 4096-byte aligned in flash, all
- *    entities in the vendor boot image are page_size (determined by the vendor
- *    and specified in the vendor boot image header) aligned in flash
- * 1. kernel, ramdisk, and DTB are required (size != 0)
- * 2. load the kernel and DTB at the specified physical address (kernel_addr,
- *    dtb_addr)
- * 3. load the vendor ramdisks at ramdisk_addr
- * 4. load the generic ramdisk immediately following the vendor ramdisk in
- *    memory
- * 5. load the bootconfig immediately following the generic ramdisk. Add
- *    additional bootconfig parameters followed by the bootconfig trailer.
- * 6. set up registers for kernel entry as required by your architecture
- * 7. if the platform has a second stage bootloader jump to it (must be
- *    contained outside boot and vendor boot partitions), otherwise
- *    jump to kernel_addr
- */
-struct boot_img_hdr_v4 : public boot_img_hdr_v3 {
-    uint32_t signature_size; /* size in bytes */
-} __attribute__((packed));
-
-struct vendor_boot_img_hdr_v4 : public vendor_boot_img_hdr_v3 {
-    uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
-    uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
-    uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */
-    uint32_t bootconfig_size; /* size in bytes for the bootconfig section */
-} __attribute__((packed));
-
-struct vendor_ramdisk_table_entry_v4 {
-    uint32_t ramdisk_size; /* size in bytes for the ramdisk image */
-    uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */
-    uint32_t ramdisk_type; /* type of the ramdisk */
-    uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */
-
-    // Hardware identifiers describing the board, soc or platform which this
-    // ramdisk is intended to be loaded on.
-    uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE];
-} __attribute__((packed));
diff --git a/mkbootimg.py b/mkbootimg.py
old mode 100755
new mode 100644
index e0b0839..00a4623
--- a/mkbootimg.py
+++ b/mkbootimg.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python3
-#
+#!/usr/bin/env python
 # Copyright 2015, The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,55 +13,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Creates the boot image."""
+from __future__ import print_function
 
-from argparse import (ArgumentParser, ArgumentTypeError,
-                      FileType, RawDescriptionHelpFormatter)
+from argparse import ArgumentParser, FileType, Action
 from hashlib import sha1
 from os import fstat
+import re
 from struct import pack
 
-import array
-import collections
-import os
-import re
-import subprocess
-import tempfile
 
-# Constant and structure definition is in
-# system/tools/mkbootimg/include/bootimg/bootimg.h
-BOOT_MAGIC = 'ANDROID!'
-BOOT_MAGIC_SIZE = 8
-BOOT_NAME_SIZE = 16
-BOOT_ARGS_SIZE = 512
-BOOT_EXTRA_ARGS_SIZE = 1024
-BOOT_IMAGE_HEADER_V1_SIZE = 1648
-BOOT_IMAGE_HEADER_V2_SIZE = 1660
-BOOT_IMAGE_HEADER_V3_SIZE = 1580
 BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
-BOOT_IMAGE_HEADER_V4_SIZE = 1584
-BOOT_IMAGE_V4_SIGNATURE_SIZE = 4096
-
-VENDOR_BOOT_MAGIC = 'VNDRBOOT'
-VENDOR_BOOT_MAGIC_SIZE = 8
-VENDOR_BOOT_NAME_SIZE = BOOT_NAME_SIZE
-VENDOR_BOOT_ARGS_SIZE = 2048
-VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
-VENDOR_BOOT_IMAGE_HEADER_V4_SIZE = 2128
-
-VENDOR_RAMDISK_TYPE_NONE = 0
-VENDOR_RAMDISK_TYPE_PLATFORM = 1
-VENDOR_RAMDISK_TYPE_RECOVERY = 2
-VENDOR_RAMDISK_TYPE_DLKM = 3
-VENDOR_RAMDISK_NAME_SIZE = 32
-VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16
-VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE = 108
-
-# Names with special meaning, mustn't be specified in --ramdisk_name.
-VENDOR_RAMDISK_NAME_BLOCKLIST = {b'default'}
-
-PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT = '--vendor_ramdisk_fragment'
-
 
 def filesize(f):
     if f is None:
@@ -89,135 +49,87 @@
 
 def get_number_of_pages(image_size, page_size):
     """calculates the number of pages required for the image"""
-    return (image_size + page_size - 1) // page_size
+    return (image_size + page_size - 1) / page_size
 
 
 def get_recovery_dtbo_offset(args):
     """calculates the offset of recovery_dtbo image in the boot image"""
     num_header_pages = 1 # header occupies a page
     num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize)
-    num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk),
-                                            args.pagesize)
+    num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk), args.pagesize)
     num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize)
     dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages +
                                    num_ramdisk_pages + num_second_pages)
     return dtbo_offset
 
 
-def write_header_v3_and_above(args):
-    if args.header_version > 3:
-        boot_header_size = BOOT_IMAGE_HEADER_V4_SIZE
-    else:
-        boot_header_size = BOOT_IMAGE_HEADER_V3_SIZE
+def write_header_v3(args):
+    BOOT_IMAGE_HEADER_V3_SIZE = 1580
+    BOOT_MAGIC = 'ANDROID!'.encode()
 
-    args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
-    # kernel size in bytes
-    args.output.write(pack('I', filesize(args.kernel)))
-    # ramdisk size in bytes
-    args.output.write(pack('I', filesize(args.ramdisk)))
-    # os version and patch level
-    args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
-    args.output.write(pack('I', boot_header_size))
-    # reserved
-    args.output.write(pack('4I', 0, 0, 0, 0))
-    # version of boot image header
-    args.output.write(pack('I', args.header_version))
-    args.output.write(pack(f'{BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE}s',
-                           args.cmdline))
-    if args.header_version >= 4:
-        # The signature used to verify boot image v4.
-        args.output.write(pack('I', BOOT_IMAGE_V4_SIGNATURE_SIZE))
+    args.output.write(pack('8s', BOOT_MAGIC))
+    args.output.write(pack(
+        '4I',
+        filesize(args.kernel),                          # kernel size in bytes
+        filesize(args.ramdisk),                         # ramdisk size in bytes
+        (args.os_version << 11) | args.os_patch_level,  # os version and patch level
+        BOOT_IMAGE_HEADER_V3_SIZE))
+
+    args.output.write(pack('4I', 0, 0, 0, 0))           # reserved
+
+    args.output.write(pack('I', args.header_version))   # version of bootimage header
+    args.output.write(pack('1536s', args.cmdline.encode()))
     pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)
 
-
 def write_vendor_boot_header(args):
+    VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
+    BOOT_MAGIC = 'VNDRBOOT'.encode()
+
+    args.vendor_boot.write(pack('8s', BOOT_MAGIC))
+    args.vendor_boot.write(pack(
+        '5I',
+        args.header_version,                            # version of header
+        args.pagesize,                                  # flash page size we assume
+        args.base + args.kernel_offset,                 # kernel physical load addr
+        args.base + args.ramdisk_offset,                # ramdisk physical load addr
+        filesize(args.vendor_ramdisk)))                 # vendor ramdisk size in bytes
+    args.vendor_boot.write(pack('2048s', args.vendor_cmdline.encode()))
+    args.vendor_boot.write(pack('I', args.base + args.tags_offset)) # physical addr for kernel tags
+    args.vendor_boot.write(pack('16s', args.board.encode())) # asciiz product name
+    args.vendor_boot.write(pack('I', VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) # header size in bytes
     if filesize(args.dtb) == 0:
-        raise ValueError('DTB image must not be empty.')
-
-    if args.header_version > 3:
-        vendor_ramdisk_size = args.vendor_ramdisk_total_size
-        vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V4_SIZE
-    else:
-        vendor_ramdisk_size = filesize(args.vendor_ramdisk)
-        vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V3_SIZE
-
-    args.vendor_boot.write(pack(f'{VENDOR_BOOT_MAGIC_SIZE}s',
-                                VENDOR_BOOT_MAGIC.encode()))
-    # version of boot image header
-    args.vendor_boot.write(pack('I', args.header_version))
-    # flash page size
-    args.vendor_boot.write(pack('I', args.pagesize))
-    # kernel physical load address
-    args.vendor_boot.write(pack('I', args.base + args.kernel_offset))
-    # ramdisk physical load address
-    args.vendor_boot.write(pack('I', args.base + args.ramdisk_offset))
-    # ramdisk size in bytes
-    args.vendor_boot.write(pack('I', vendor_ramdisk_size))
-    args.vendor_boot.write(pack(f'{VENDOR_BOOT_ARGS_SIZE}s',
-                                args.vendor_cmdline))
-    # kernel tags physical load address
-    args.vendor_boot.write(pack('I', args.base + args.tags_offset))
-    # asciiz product name
-    args.vendor_boot.write(pack(f'{VENDOR_BOOT_NAME_SIZE}s', args.board))
-
-    # header size in bytes
-    args.vendor_boot.write(pack('I', vendor_boot_header_size))
-
-    # dtb size in bytes
-    args.vendor_boot.write(pack('I', filesize(args.dtb)))
-    # dtb physical load address
-    args.vendor_boot.write(pack('Q', args.base + args.dtb_offset))
-
-    if args.header_version > 3:
-        vendor_ramdisk_table_size = (args.vendor_ramdisk_table_entry_num *
-                                     VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE)
-        # vendor ramdisk table size in bytes
-        args.vendor_boot.write(pack('I', vendor_ramdisk_table_size))
-        # number of vendor ramdisk table entries
-        args.vendor_boot.write(pack('I', args.vendor_ramdisk_table_entry_num))
-        # vendor ramdisk table entry size in bytes
-        args.vendor_boot.write(pack('I', VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE))
-        # bootconfig section size in bytes
-        args.vendor_boot.write(pack('I', filesize(args.vendor_bootconfig)))
+        raise ValueError("DTB image must not be empty.")
+    args.vendor_boot.write(pack('I', filesize(args.dtb)))   # size in bytes
+    args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
     pad_file(args.vendor_boot, args.pagesize)
 
-
 def write_header(args):
-    if args.header_version > 4:
-        raise ValueError(
-            f'Boot header version {args.header_version} not supported')
-    if args.header_version in {3, 4}:
-        return write_header_v3_and_above(args)
+    BOOT_IMAGE_HEADER_V1_SIZE = 1648
+    BOOT_IMAGE_HEADER_V2_SIZE = 1660
+    BOOT_MAGIC = 'ANDROID!'.encode()
 
-    ramdisk_load_address = ((args.base + args.ramdisk_offset)
-                            if filesize(args.ramdisk) > 0 else 0)
-    second_load_address = ((args.base + args.second_offset)
-                           if filesize(args.second) > 0 else 0)
+    if args.header_version > 3:
+        raise ValueError('Boot header version %d not supported' % args.header_version)
+    elif args.header_version == 3:
+        return write_header_v3(args)
 
-    args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
-    # kernel size in bytes
-    args.output.write(pack('I', filesize(args.kernel)))
-    # kernel physical load address
-    args.output.write(pack('I', args.base + args.kernel_offset))
-    # ramdisk size in bytes
-    args.output.write(pack('I', filesize(args.ramdisk)))
-    # ramdisk physical load address
-    args.output.write(pack('I', ramdisk_load_address))
-    # second bootloader size in bytes
-    args.output.write(pack('I', filesize(args.second)))
-    # second bootloader physical load address
-    args.output.write(pack('I', second_load_address))
-    # kernel tags physical load address
-    args.output.write(pack('I', args.base + args.tags_offset))
-    # flash page size
-    args.output.write(pack('I', args.pagesize))
-    # version of boot image header
-    args.output.write(pack('I', args.header_version))
-    # os version and patch level
-    args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
-    # asciiz product name
-    args.output.write(pack(f'{BOOT_NAME_SIZE}s', args.board))
-    args.output.write(pack(f'{BOOT_ARGS_SIZE}s', args.cmdline))
+    args.output.write(pack('8s', BOOT_MAGIC))
+    final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0
+    final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0
+    args.output.write(pack(
+        '10I',
+        filesize(args.kernel),                          # size in bytes
+        args.base + args.kernel_offset,                 # physical load addr
+        filesize(args.ramdisk),                         # size in bytes
+        final_ramdisk_offset,                           # physical load addr
+        filesize(args.second),                          # size in bytes
+        final_second_offset,                            # physical load addr
+        args.base + args.tags_offset,                   # physical addr for kernel tags
+        args.pagesize,                                  # flash page size we assume
+        args.header_version,                            # version of bootimage header
+        (args.os_version << 11) | args.os_patch_level)) # os version and patch level
+    args.output.write(pack('16s', args.board.encode())) # asciiz product name
+    args.output.write(pack('512s', args.cmdline[:512].encode()))
 
     sha = sha1()
     update_sha(sha, args.kernel)
@@ -232,18 +144,14 @@
     img_id = pack('32s', sha.digest())
 
     args.output.write(img_id)
-    args.output.write(pack(f'{BOOT_EXTRA_ARGS_SIZE}s', args.extra_cmdline))
+    args.output.write(pack('1024s', args.cmdline[512:].encode()))
 
     if args.header_version > 0:
+        args.output.write(pack('I', filesize(args.recovery_dtbo)))   # size in bytes
         if args.recovery_dtbo:
-            # recovery dtbo size in bytes
-            args.output.write(pack('I', filesize(args.recovery_dtbo)))
-            # recovert dtbo offset in the boot image
-            args.output.write(pack('Q', get_recovery_dtbo_offset(args)))
+            args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
         else:
-            # Set to zero if no recovery dtbo
-            args.output.write(pack('I', 0))
-            args.output.write(pack('Q', 0))
+            args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
 
     # Populate boot image header size for header versions 1 and 2.
     if args.header_version == 1:
@@ -252,101 +160,29 @@
         args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
 
     if args.header_version > 1:
+
         if filesize(args.dtb) == 0:
-            raise ValueError('DTB image must not be empty.')
+            raise ValueError("DTB image must not be empty.")
 
-        # dtb size in bytes
-        args.output.write(pack('I', filesize(args.dtb)))
-        # dtb physical load address
-        args.output.write(pack('Q', args.base + args.dtb_offset))
-
+        args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
+        args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
     pad_file(args.output, args.pagesize)
     return img_id
 
 
-class AsciizBytes:
-    """Parses a string and encodes it as an asciiz bytes object.
+class ValidateStrLenAction(Action):
+    def __init__(self, option_strings, dest, nargs=None, **kwargs):
+        if 'maxlen' not in kwargs:
+            raise ValueError('maxlen must be set')
+        self.maxlen = int(kwargs['maxlen'])
+        del kwargs['maxlen']
+        super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)
 
-    >>> AsciizBytes(bufsize=4)('foo')
-    b'foo\\x00'
-    >>> AsciizBytes(bufsize=4)('foob')
-    Traceback (most recent call last):
-        ...
-    argparse.ArgumentTypeError: Encoded asciiz length exceeded: max 4, got 5
-    """
-
-    def __init__(self, bufsize):
-        self.bufsize = bufsize
-
-    def __call__(self, arg):
-        arg_bytes = arg.encode() + b'\x00'
-        if len(arg_bytes) > self.bufsize:
-            raise ArgumentTypeError(
-                'Encoded asciiz length exceeded: '
-                f'max {self.bufsize}, got {len(arg_bytes)}')
-        return arg_bytes
-
-
-class VendorRamdiskTableBuilder:
-    """Vendor ramdisk table builder.
-
-    Attributes:
-        entries: A list of VendorRamdiskTableEntry namedtuple.
-        ramdisk_total_size: Total size in bytes of all ramdisks in the table.
-    """
-
-    VendorRamdiskTableEntry = collections.namedtuple(  # pylint: disable=invalid-name
-        'VendorRamdiskTableEntry',
-        ['ramdisk_path', 'ramdisk_size', 'ramdisk_offset', 'ramdisk_type',
-         'ramdisk_name', 'board_id'])
-
-    def __init__(self):
-        self.entries = []
-        self.ramdisk_total_size = 0
-        self.ramdisk_names = set()
-
-    def add_entry(self, ramdisk_path, ramdisk_type, ramdisk_name, board_id):
-        # Strip any trailing null for simple comparison.
-        stripped_ramdisk_name = ramdisk_name.rstrip(b'\x00')
-        if stripped_ramdisk_name in VENDOR_RAMDISK_NAME_BLOCKLIST:
+    def __call__(self, parser, namespace, values, option_string=None):
+        if len(values) > self.maxlen:
             raise ValueError(
-                f'Banned vendor ramdisk name: {stripped_ramdisk_name}')
-        if stripped_ramdisk_name in self.ramdisk_names:
-            raise ValueError(
-                f'Duplicated vendor ramdisk name: {stripped_ramdisk_name}')
-        self.ramdisk_names.add(stripped_ramdisk_name)
-
-        if board_id is None:
-            board_id = array.array(
-                'I', [0] * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)
-        else:
-            board_id = array.array('I', board_id)
-        if len(board_id) != VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE:
-            raise ValueError('board_id size must be '
-                             f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}')
-
-        with open(ramdisk_path, 'rb') as f:
-            ramdisk_size = filesize(f)
-        self.entries.append(self.VendorRamdiskTableEntry(
-            ramdisk_path, ramdisk_size, self.ramdisk_total_size, ramdisk_type,
-            ramdisk_name, board_id))
-        self.ramdisk_total_size += ramdisk_size
-
-    def write_ramdisks_padded(self, fout, alignment):
-        for entry in self.entries:
-            with open(entry.ramdisk_path, 'rb') as f:
-                fout.write(f.read())
-        pad_file(fout, alignment)
-
-    def write_entries_padded(self, fout, alignment):
-        for entry in self.entries:
-            fout.write(pack('I', entry.ramdisk_size))
-            fout.write(pack('I', entry.ramdisk_offset))
-            fout.write(pack('I', entry.ramdisk_type))
-            fout.write(pack(f'{VENDOR_RAMDISK_NAME_SIZE}s',
-                            entry.ramdisk_name))
-            fout.write(entry.board_id)
-        pad_file(fout, alignment)
+                'String argument too long: max {0:d}, got {1:d}'.format(self.maxlen, len(values)))
+        setattr(namespace, self.dest, values)
 
 
 def write_padded_file(f_out, f_in, padding):
@@ -389,236 +225,49 @@
     return 0
 
 
-def parse_vendor_ramdisk_type(x):
-    type_dict = {
-        'none': VENDOR_RAMDISK_TYPE_NONE,
-        'platform': VENDOR_RAMDISK_TYPE_PLATFORM,
-        'recovery': VENDOR_RAMDISK_TYPE_RECOVERY,
-        'dlkm': VENDOR_RAMDISK_TYPE_DLKM,
-    }
-    if x.lower() in type_dict:
-        return type_dict[x.lower()]
-    return parse_int(x)
-
-
-def get_vendor_boot_v4_usage():
-    return """vendor boot version 4 arguments:
-  --ramdisk_type {none,platform,recovery,dlkm}
-                        specify the type of the ramdisk
-  --ramdisk_name NAME
-                        specify the name of the ramdisk
-  --board_id{0..15} NUMBER
-                        specify the value of the board_id vector, defaults to 0
-  --vendor_ramdisk_fragment VENDOR_RAMDISK_FILE
-                        path to the vendor ramdisk file
-
-  These options can be specified multiple times, where each vendor ramdisk
-  option group ends with a --vendor_ramdisk_fragment option.
-  Each option group appends an additional ramdisk to the vendor boot image.
-"""
-
-
-def parse_vendor_ramdisk_args(args, args_list):
-    """Parses vendor ramdisk specific arguments.
-
-    Args:
-        args: An argparse.Namespace object. Parsed results are stored into this
-            object.
-        args_list: A list of argument strings to be parsed.
-
-    Returns:
-        A list argument strings that are not parsed by this method.
-    """
-    parser = ArgumentParser(add_help=False)
-    parser.add_argument('--ramdisk_type', type=parse_vendor_ramdisk_type,
-                        default=VENDOR_RAMDISK_TYPE_NONE)
-    parser.add_argument('--ramdisk_name',
-                        type=AsciizBytes(bufsize=VENDOR_RAMDISK_NAME_SIZE),
-                        required=True)
-    for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE):
-        parser.add_argument(f'--board_id{i}', type=parse_int, default=0)
-    parser.add_argument(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT, required=True)
-
-    unknown_args = []
-
-    vendor_ramdisk_table_builder = VendorRamdiskTableBuilder()
-    if args.vendor_ramdisk is not None:
-        vendor_ramdisk_table_builder.add_entry(
-            args.vendor_ramdisk.name, VENDOR_RAMDISK_TYPE_PLATFORM, b'', None)
-
-    while PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT in args_list:
-        idx = args_list.index(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT) + 2
-        vendor_ramdisk_args = args_list[:idx]
-        args_list = args_list[idx:]
-
-        ramdisk_args, extra_args = parser.parse_known_args(vendor_ramdisk_args)
-        ramdisk_args_dict = vars(ramdisk_args)
-        unknown_args.extend(extra_args)
-
-        ramdisk_path = ramdisk_args.vendor_ramdisk_fragment
-        ramdisk_type = ramdisk_args.ramdisk_type
-        ramdisk_name = ramdisk_args.ramdisk_name
-        board_id = [ramdisk_args_dict[f'board_id{i}']
-                    for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)]
-        vendor_ramdisk_table_builder.add_entry(ramdisk_path, ramdisk_type,
-                                               ramdisk_name, board_id)
-
-    if len(args_list) > 0:
-        unknown_args.extend(args_list)
-
-    args.vendor_ramdisk_total_size = (vendor_ramdisk_table_builder
-                                      .ramdisk_total_size)
-    args.vendor_ramdisk_table_entry_num = len(vendor_ramdisk_table_builder
-                                              .entries)
-    args.vendor_ramdisk_table_builder = vendor_ramdisk_table_builder
-    return unknown_args
-
-
 def parse_cmdline():
-    version_parser = ArgumentParser(add_help=False)
-    version_parser.add_argument('--header_version', type=parse_int, default=0)
-    if version_parser.parse_known_args()[0].header_version < 3:
-        # For boot header v0 to v2, the kernel commandline field is split into
-        # two fields, cmdline and extra_cmdline. Both fields are asciiz strings,
-        # so we minus one here to ensure the encoded string plus the
-        # null-terminator can fit in the buffer size.
-        cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 1
-    else:
-        cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE
-
-    parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
-                            epilog=get_vendor_boot_v4_usage())
-    parser.add_argument('--kernel', type=FileType('rb'),
-                        help='path to the kernel')
-    parser.add_argument('--ramdisk', type=FileType('rb'),
-                        help='path to the ramdisk')
-    parser.add_argument('--second', type=FileType('rb'),
-                        help='path to the second bootloader')
-    parser.add_argument('--dtb', type=FileType('rb'), help='path to the dtb')
-    dtbo_group = parser.add_mutually_exclusive_group()
-    dtbo_group.add_argument('--recovery_dtbo', type=FileType('rb'),
-                            help='path to the recovery DTBO')
-    dtbo_group.add_argument('--recovery_acpio', type=FileType('rb'),
-                            metavar='RECOVERY_ACPIO', dest='recovery_dtbo',
-                            help='path to the recovery ACPIO')
-    parser.add_argument('--cmdline', type=AsciizBytes(bufsize=cmdline_size),
-                        default='', help='kernel command line arguments')
+    parser = ArgumentParser()
+    parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'))
+    parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
+    parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
+    parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
+    recovery_dtbo_group = parser.add_mutually_exclusive_group()
+    recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO',
+                                     type=FileType('rb'))
+    recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
+                                     type=FileType('rb'), metavar='RECOVERY_ACPIO',
+                                     dest='recovery_dtbo')
+    parser.add_argument('--cmdline', help='extra arguments to be passed on the '
+                        'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
     parser.add_argument('--vendor_cmdline',
-                        type=AsciizBytes(bufsize=VENDOR_BOOT_ARGS_SIZE),
-                        default='',
-                        help='vendor boot kernel command line arguments')
-    parser.add_argument('--base', type=parse_int, default=0x10000000,
-                        help='base address')
-    parser.add_argument('--kernel_offset', type=parse_int, default=0x00008000,
-                        help='kernel offset')
-    parser.add_argument('--ramdisk_offset', type=parse_int, default=0x01000000,
-                        help='ramdisk offset')
-    parser.add_argument('--second_offset', type=parse_int, default=0x00f00000,
-                        help='second bootloader offset')
-    parser.add_argument('--dtb_offset', type=parse_int, default=0x01f00000,
-                        help='dtb offset')
+                        help='kernel command line arguments contained in vendor boot',
+                        default='', action=ValidateStrLenAction, maxlen=2048)
+    parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
+    parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
+    parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int,
+                        default=0x01000000)
+    parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
+                        default=0x00f00000)
+    parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
 
-    parser.add_argument('--os_version', type=parse_os_version, default=0,
-                        help='operating system version')
-    parser.add_argument('--os_patch_level', type=parse_os_patch_level,
-                        default=0, help='operating system patch level')
-    parser.add_argument('--tags_offset', type=parse_int, default=0x00000100,
-                        help='tags offset')
-    parser.add_argument('--board', type=AsciizBytes(bufsize=BOOT_NAME_SIZE),
-                        default='', help='board name')
-    parser.add_argument('--pagesize', type=parse_int,
-                        choices=[2**i for i in range(11, 15)], default=2048,
-                        help='page size')
-    parser.add_argument('--id', action='store_true',
-                        help='print the image ID on standard output')
-    parser.add_argument('--header_version', type=parse_int, default=0,
-                        help='boot image header version')
-    parser.add_argument('-o', '--output', type=FileType('wb'),
-                        help='output file name')
-    parser.add_argument('--gki_signing_algorithm',
-                        help='GKI signing algorithm to use')
-    parser.add_argument('--gki_signing_key',
-                        help='path to RSA private key file')
-    parser.add_argument('--gki_signing_signature_args',
-                        help='other hash arguments passed to avbtool')
-    parser.add_argument('--gki_signing_avbtool_path',
-                        help='path to avbtool for boot signature generation')
-    parser.add_argument('--vendor_boot', type=FileType('wb'),
-                        help='vendor boot output file name')
-    parser.add_argument('--vendor_ramdisk', type=FileType('rb'),
-                        help='path to the vendor ramdisk')
-    parser.add_argument('--vendor_bootconfig', type=FileType('rb'),
-                        help='path to the vendor bootconfig file')
+    parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
+                        default=0)
+    parser.add_argument('--os_patch_level', help='operating system patch level',
+                        type=parse_os_patch_level, default=0)
+    parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
+    parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
+                        maxlen=16)
+    parser.add_argument('--pagesize', help='page size', type=parse_int,
+                        choices=[2**i for i in range(11, 15)], default=2048)
+    parser.add_argument('--id', help='print the image ID on standard output',
+                        action='store_true')
+    parser.add_argument('--header_version', help='boot image header version', type=parse_int,
+                        default=0)
+    parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'))
+    parser.add_argument('--vendor_boot', help='vendor boot output file name', type=FileType('wb'))
+    parser.add_argument('--vendor_ramdisk', help='path to the vendor ramdisk', type=FileType('rb'))
 
-    args, extra_args = parser.parse_known_args()
-    if args.vendor_boot is not None and args.header_version > 3:
-        extra_args = parse_vendor_ramdisk_args(args, extra_args)
-    if len(extra_args) > 0:
-        raise ValueError(f'Unrecognized arguments: {extra_args}')
-
-    if args.header_version < 3:
-        args.extra_cmdline = args.cmdline[BOOT_ARGS_SIZE-1:]
-        args.cmdline = args.cmdline[:BOOT_ARGS_SIZE-1] + b'\x00'
-        assert len(args.cmdline) <= BOOT_ARGS_SIZE
-        assert len(args.extra_cmdline) <= BOOT_EXTRA_ARGS_SIZE
-
-    return args
-
-
-def add_boot_image_signature(args, pagesize):
-    """Adds the boot image signature.
-
-    Note that the signature will only be verified in VTS to ensure a
-    generic boot.img is used. It will not be used by the device
-    bootloader at boot time. The bootloader should only verify
-    the boot vbmeta at the end of the boot partition (or in the top-level
-    vbmeta partition) via the Android Verified Boot process, when the
-    device boots.
-    """
-    args.output.flush()  # Flush the buffer for signature calculation.
-
-    # Appends zeros if the signing key is not specified.
-    if not args.gki_signing_key or not args.gki_signing_algorithm:
-        zeros = b'\x00' * BOOT_IMAGE_V4_SIGNATURE_SIZE
-        args.output.write(zeros)
-        pad_file(args.output, pagesize)
-        return
-
-    avbtool = 'avbtool'  # Used from otatools.zip or Android build env.
-
-    # We need to specify the path of avbtool in build/core/Makefile.
-    # Because avbtool is not guaranteed to be in $PATH there.
-    if args.gki_signing_avbtool_path:
-        avbtool = args.gki_signing_avbtool_path
-
-    # Need to specify a value of --partition_size for avbtool to work.
-    # We use 64 MB below, but avbtool will not resize the boot image to
-    # this size because --do_not_append_vbmeta_image is also specified.
-    avbtool_cmd = [
-        avbtool, 'add_hash_footer',
-        '--partition_name', 'boot',
-        '--partition_size', str(64 * 1024 * 1024),
-        '--image', args.output.name,
-        '--algorithm', args.gki_signing_algorithm,
-        '--key', args.gki_signing_key,
-        '--salt', 'd00df00d']  # TODO: use a hash of kernel/ramdisk as the salt.
-
-    # Additional arguments passed to avbtool.
-    if args.gki_signing_signature_args:
-        avbtool_cmd += args.gki_signing_signature_args.split()
-
-    # Outputs the signed vbmeta to a separate file, then append to boot.img
-    # as the boot signature.
-    with tempfile.TemporaryDirectory() as temp_out_dir:
-        boot_signature_output = os.path.join(temp_out_dir, 'boot_signature')
-        avbtool_cmd += ['--do_not_append_vbmeta_image',
-                        '--output_vbmeta_image', boot_signature_output]
-        subprocess.check_call(avbtool_cmd)
-        with open(boot_signature_output, 'rb') as boot_signature:
-            if filesize(boot_signature) > BOOT_IMAGE_V4_SIGNATURE_SIZE:
-                raise ValueError(
-                    f'boot sigature size is > {BOOT_IMAGE_V4_SIGNATURE_SIZE}')
-            write_padded_file(args.output, boot_signature, pagesize)
+    return parser.parse_args()
 
 
 def write_data(args, pagesize):
@@ -630,44 +279,37 @@
         write_padded_file(args.output, args.recovery_dtbo, pagesize)
     if args.header_version == 2:
         write_padded_file(args.output, args.dtb, pagesize)
-    if args.header_version >= 4:
-        add_boot_image_signature(args, pagesize)
 
 
 def write_vendor_boot_data(args):
-    if args.header_version > 3:
-        builder = args.vendor_ramdisk_table_builder
-        builder.write_ramdisks_padded(args.vendor_boot, args.pagesize)
-        write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
-        builder.write_entries_padded(args.vendor_boot, args.pagesize)
-        write_padded_file(args.vendor_boot, args.vendor_bootconfig,
-            args.pagesize)
-    else:
-        write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
-        write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
+    write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
+    write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
 
 
 def main():
     args = parse_cmdline()
     if args.vendor_boot is not None:
-        if args.header_version not in {3, 4}:
-            raise ValueError(
-                '--vendor_boot not compatible with given header version')
-        if args.header_version == 3 and args.vendor_ramdisk is None:
+        if args.header_version < 3:
+            raise ValueError('--vendor_boot not compatible with given header version')
+        if args.vendor_ramdisk is None:
             raise ValueError('--vendor_ramdisk missing or invalid')
         write_vendor_boot_header(args)
         write_vendor_boot_data(args)
     if args.output is not None:
+        if args.kernel is None:
+            raise ValueError('kernel must be supplied when creating a boot image')
         if args.second is not None and args.header_version > 2:
-            raise ValueError(
-                '--second not compatible with given header version')
+            raise ValueError('--second not compatible with given header version')
         img_id = write_header(args)
         if args.header_version > 2:
             write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
         else:
             write_data(args, args.pagesize)
         if args.id and img_id is not None:
-            print('0x' + ''.join(f'{octet:02x}' for octet in img_id))
+            # Python 2's struct.pack returns a string, but py3 returns bytes.
+            if isinstance(img_id, str):
+                img_id = [ord(x) for x in img_id]
+            print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
 
 
 if __name__ == '__main__':
diff --git a/pylintrc b/pylintrc
index b65d218..1990be7 100644
--- a/pylintrc
+++ b/pylintrc
@@ -1,33 +1,46 @@
-# This Pylint rcfile contains a best-effort configuration to uphold the
-# best-practices and style described in the Google Python style guide:
-#   https://google.github.io/styleguide/pyguide.html
-#
-# Its canonical open-source location is:
-#   https://google.github.io/styleguide/pylintrc
-
 [MASTER]
 
-# Files or directories to be skipped. They should be base names, not paths.
-ignore=third_party
+# Specify a configuration file.
+#rcfile=
 
-# Files or directories matching the regex patterns are skipped. The regex
-# matches against base names, not paths.
-ignore-patterns=
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
 
 # Pickle collected data for later comparisons.
-persistent=no
+persistent=yes
 
 # List of plugins (as comma separated values of python modules names) to load,
 # usually to register additional checkers.
 load-plugins=
 
 # Use multiple processes to speed up Pylint.
-jobs=4
+jobs=1
 
 # Allow loading of arbitrary C extensions. Extensions are imported into the
 # active Python interpreter and may run arbitrary code.
 unsafe-load-any-extension=no
 
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Allow optimization of some AST trees. This will activate a peephole AST
+# optimizer, which will apply various small optimizations. For instance, it can
+# be used to obtain the result of joining multiple strings with the addition
+# operator. Joining a lot of strings can lead to a maximum recursion error in
+# Pylint and this flag can prevent that. It has one side effect, the resulting
+# AST will be different than the one from reality.
+optimize-ast=no
+
 
 [MESSAGES CONTROL]
 
@@ -37,8 +50,7 @@
 
 # Enable the message, report, category or checker with the given id(s). You can
 # either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once). See also the "--disable" option for examples.
+# multiple time. See also the "--disable" option for examples.
 #enable=
 
 # Disable the message, report, category or checker with the given id(s). You
@@ -50,102 +62,7 @@
 # --enable=similarities". If you want to run only the classes checker, but have
 # no Warning level messages displayed, use"--disable=all --enable=classes
 # --disable=W"
-disable=abstract-method,
-        apply-builtin,
-        arguments-differ,
-        attribute-defined-outside-init,
-        backtick,
-        bad-option-value,
-        basestring-builtin,
-        buffer-builtin,
-        c-extension-no-member,
-        consider-using-enumerate,
-        cmp-builtin,
-        cmp-method,
-        coerce-builtin,
-        coerce-method,
-        delslice-method,
-        div-method,
-        duplicate-code,
-        eq-without-hash,
-        execfile-builtin,
-        file-builtin,
-        filter-builtin-not-iterating,
-        fixme,
-        getslice-method,
-        global-statement,
-        hex-method,
-        idiv-method,
-        implicit-str-concat-in-sequence,
-        import-error,
-        import-self,
-        import-star-module-level,
-        inconsistent-return-statements,
-        input-builtin,
-        intern-builtin,
-        invalid-str-codec,
-        locally-disabled,
-        long-builtin,
-        long-suffix,
-        map-builtin-not-iterating,
-        misplaced-comparison-constant,
-        missing-function-docstring,
-        metaclass-assignment,
-        next-method-called,
-        next-method-defined,
-        no-absolute-import,
-        no-else-break,
-        no-else-continue,
-        no-else-raise,
-        no-else-return,
-        no-init,  # added
-        no-member,
-        no-name-in-module,
-        no-self-use,
-        nonzero-method,
-        oct-method,
-        old-division,
-        old-ne-operator,
-        old-octal-literal,
-        old-raise-syntax,
-        parameter-unpacking,
-        print-statement,
-        raising-string,
-        range-builtin-not-iterating,
-        raw_input-builtin,
-        rdiv-method,
-        reduce-builtin,
-        relative-import,
-        reload-builtin,
-        round-builtin,
-        setslice-method,
-        signature-differs,
-        standarderror-builtin,
-        suppressed-message,
-        sys-max-int,
-        too-few-public-methods,
-        too-many-ancestors,
-        too-many-arguments,
-        too-many-boolean-expressions,
-        too-many-branches,
-        too-many-instance-attributes,
-        too-many-locals,
-        too-many-nested-blocks,
-        too-many-public-methods,
-        too-many-return-statements,
-        too-many-statements,
-        trailing-newlines,
-        unichr-builtin,
-        unicode-builtin,
-        unnecessary-pass,
-        unpacking-in-except,
-        useless-else-on-loop,
-        useless-object-inheritance,
-        useless-suppression,
-        using-cmp-argument,
-        wrong-import-order,
-        xrange-builtin,
-        zip-builtin-not-iterating,
+disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme,not-callable
 
 
 [REPORTS]
@@ -157,12 +74,11 @@
 
 # Put messages in a separate file for each module / package specified on the
 # command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]". This option is deprecated
-# and it will be removed in Pylint 2.0.
+# written in a file name "pylint_global.[txt|html]".
 files-output=no
 
 # Tells whether to display a full report or only the messages
-reports=no
+reports=yes
 
 # Python expression which should return a note less than 10 (10 is the highest
 # note). You have access to the variables errors warning, statement which
@@ -171,177 +87,15 @@
 # (RP0004).
 evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
 
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
 # Template used to display messages. This is a python new-style format string
 # used to format the message information. See doc for all details
 #msg-template=
 
 
-[BASIC]
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=main,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Include a hint for the correct naming format with invalid-name
-include-naming-hint=no
-
-# List of decorators that produce properties, such as abc.abstractproperty. Add
-# to this list to register other decorators that produce valid properties.
-property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
-
-# Regular expression matching correct function names
-function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
-
-# Regular expression matching correct variable names
-variable-rgx=^[a-z][a-z0-9_]*$
-
-# Regular expression matching correct constant names
-const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
-
-# Regular expression matching correct attribute names
-attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
-
-# Regular expression matching correct argument names
-argument-rgx=^[a-z][a-z0-9_]*$
-
-# Regular expression matching correct class attribute names
-class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
-
-# Regular expression matching correct inline iteration names
-inlinevar-rgx=^[a-z][a-z0-9_]*$
-
-# Regular expression matching correct class names
-class-rgx=^_?[A-Z][a-zA-Z0-9]*$
-
-# Regular expression matching correct module names
-module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
-
-# Regular expression matching correct method names
-method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=10
-
-
-[TYPECHECK]
-
-# List of decorators that produce context managers, such as
-# contextlib.contextmanager. Add to this list to register other decorators that
-# produce valid context managers.
-contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis. It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=
-
-# List of class names for which member attributes should not be checked (useful
-# for classes with dynamically set attributes). This supports the use of
-# qualified names.
-ignored-classes=optparse.Values,thread._local,_thread._local
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
-# lines made too long by directives to pytype.
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=(?x)(
-  ^\s*(\#\ )?<?https?://\S+>?$|
-  ^\s*(from\s+\S+\s+)?import\s+.+$)
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=yes
-
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=
-
-# Maximum number of lines in a module
-max-module-lines=99999
-
-# String used as indentation unit.  The internal Google style guide mandates 2
-# spaces.  Google's externaly-published style guide says 4, consistent with
-# PEP 8.
-indent-string='    '
-
-# Number of spaces of indent required inside a hanging  or continued line.
-indent-after-paren=4
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=LF
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=TODO
-
-
-[STRING]
-
-# This flag controls whether inconsistent-quotes generates a warning when the
-# character used as a quote delimiter is used inconsistently within a module.
-check-quote-consistency=yes
-
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the name of dummy variables (i.e. expectedly
-# not used).
-dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,_cb
-
-# List of qualified module names which can have objects that can redefine
-# builtins.
-redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
-
-
-[LOGGING]
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format
-logging-modules=logging,absl.logging,tensorflow.io.logging
-
-
 [SIMILARITIES]
 
 # Minimum lines number of a similarity.
@@ -357,6 +111,124 @@
 ignore-imports=no
 
 
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis
+ignored-modules=
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[BASIC]
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,input
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Regular expression matching correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for function names
+function-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for variable names
+variable-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct constant names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Naming hint for constant names
+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression matching correct attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for attribute names
+attr-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for argument names
+argument-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Naming hint for class attribute names
+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Naming hint for inline iteration names
+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
+
+# Regular expression matching correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Naming hint for class names
+class-name-hint=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression matching correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Naming hint for module names
+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression matching correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for method names
+method-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=__.*__
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+
 [SPELLING]
 
 # Spelling dictionary name. Available dictionaries: none. To make it working
@@ -374,14 +246,98 @@
 spelling-store-unknown-words=no
 
 
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+# List of optional constructs for which whitespace checking is disabled
+no-space-check=trailing-comma,dict-separator
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=LF
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_$|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
 [IMPORTS]
 
 # Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,
-                   TERMIOS,
-                   Bastion,
-                   rexec,
-                   sets
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
 
 # Create a graph of every (i.e. internal and external) dependencies in the
 # given file (report RP0402 must not be disabled)
@@ -395,46 +351,25 @@
 # not be disabled)
 int-import-graph=
 
-# Force import order to recognize a module as part of the standard
-# compatibility libraries.
-known-standard-library=
-
-# Force import order to recognize a module as part of a third party library.
-known-third-party=enchant, absl
-
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
 
 [CLASSES]
 
 # List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,
-                      __new__,
-                      setUp
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,
-                  _fields,
-                  _replace,
-                  _source,
-                  _make
+defining-attr-methods=__init__,__new__,setUp
 
 # List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls,
-                            class_
+valid-classmethod-first-arg=cls
 
 # List of valid names for the first argument in a metaclass class method.
 valid-metaclass-classmethod-first-arg=mcs
 
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,_fields,_replace,_source,_make
+
 
 [EXCEPTIONS]
 
 # Exceptions that will emit a warning when being caught. Defaults to
 # "Exception"
-overgeneral-exceptions=StandardError,
-                       Exception,
-                       BaseException
+overgeneral-exceptions=Exception
diff --git a/repack_bootimg.py b/repack_bootimg.py
deleted file mode 100755
index c320018..0000000
--- a/repack_bootimg.py
+++ /dev/null
@@ -1,362 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Repacks the boot image.
-
-Unpacks the boot image and the ramdisk inside, then add files into
-the ramdisk to repack the boot image.
-"""
-
-import argparse
-import datetime
-import enum
-import glob
-import os
-import shlex
-import shutil
-import subprocess
-import tempfile
-
-
-class TempFileManager:
-    """Manages temporary files and dirs."""
-
-    def __init__(self):
-        self._temp_files = []
-
-    def __del__(self):
-        """Removes temp dirs and files."""
-        for f in self._temp_files:
-            if os.path.isdir(f):
-                shutil.rmtree(f, ignore_errors=True)
-            else:
-                os.remove(f)
-
-    def make_temp_dir(self, prefix='tmp', suffix=''):
-        """Makes a temporary dir that will be cleaned up in the destructor.
-
-        Returns:
-            The absolute pathname of the new directory.
-        """
-        dir_name = tempfile.mkdtemp(prefix=prefix, suffix=suffix)
-        self._temp_files.append(dir_name)
-        return dir_name
-
-    def make_temp_file(self, prefix='tmp', suffix=''):
-        """Make a temp file that will be deleted in the destructor.
-
-        Returns:
-            The absolute pathname of the new file.
-        """
-        fd, file_name = tempfile.mkstemp(prefix=prefix, suffix=suffix)
-        os.close(fd)
-        self._temp_files.append(file_name)
-        return file_name
-
-
-class RamdiskFormat(enum.Enum):
-    """Enum class for different ramdisk compression formats."""
-    LZ4 = 1
-    GZIP = 2
-
-
-class BootImageType(enum.Enum):
-    """Enum class for different boot image types."""
-    BOOT_IMAGE = 1
-    VENDOR_BOOT_IMAGE = 2
-    SINGLE_RAMDISK_FRAGMENT = 3
-    MULTIPLE_RAMDISK_FRAGMENTS = 4
-
-
-class RamdiskImage:
-    """A class that supports packing/unpacking a ramdisk."""
-    def __init__(self, ramdisk_img, unpack=True):
-        self._ramdisk_img = ramdisk_img
-        self._ramdisk_format = None
-        self._ramdisk_dir = None
-        self._temp_file_manager = TempFileManager()
-
-        if unpack:
-            self._unpack_ramdisk()
-        else:
-            self._ramdisk_dir = self._temp_file_manager.make_temp_dir(
-                suffix='_new_ramdisk')
-
-    def _unpack_ramdisk(self):
-        """Unpacks the ramdisk."""
-        self._ramdisk_dir = self._temp_file_manager.make_temp_dir(
-            suffix='_' + os.path.basename(self._ramdisk_img))
-
-        # The compression format might be in 'lz4' or 'gzip' format,
-        # trying lz4 first.
-        for compression_type, compression_util in [
-            (RamdiskFormat.LZ4, 'lz4'),
-            (RamdiskFormat.GZIP, 'minigzip')]:
-
-            # Command arguments:
-            #   -d: decompression
-            #   -c: write to stdout
-            decompression_cmd = [
-                compression_util, '-d', '-c', self._ramdisk_img]
-
-            decompressed_result = subprocess.run(
-                decompression_cmd, check=False, capture_output=True)
-
-            if decompressed_result.returncode == 0:
-                self._ramdisk_format = compression_type
-                break
-
-        if self._ramdisk_format is not None:
-            # toybox cpio arguments:
-            #   -i: extract files from stdin
-            #   -d: create directories if needed
-            #   -u: override existing files
-            subprocess.run(
-                ['toybox', 'cpio', '-idu'], check=True,
-                input=decompressed_result.stdout, cwd=self._ramdisk_dir)
-
-            print("=== Unpacked ramdisk: '{}' ===".format(
-                self._ramdisk_img))
-        else:
-            raise RuntimeError('Failed to decompress ramdisk.')
-
-    def repack_ramdisk(self, out_ramdisk_file):
-        """Repacks a ramdisk from self._ramdisk_dir.
-
-        Args:
-            out_ramdisk_file: the output ramdisk file to save.
-        """
-        compression_cmd = ['lz4', '-l', '-12', '--favor-decSpeed']
-        if self._ramdisk_format == RamdiskFormat.GZIP:
-            compression_cmd = ['minigzip']
-
-        print('Repacking ramdisk, which might take a few seconds ...')
-
-        mkbootfs_result = subprocess.run(
-            ['mkbootfs', self._ramdisk_dir], check=True, capture_output=True)
-
-        with open(out_ramdisk_file, 'w') as output_fd:
-            subprocess.run(compression_cmd, check=True,
-                           input=mkbootfs_result.stdout, stdout=output_fd)
-
-        print("=== Repacked ramdisk: '{}' ===".format(out_ramdisk_file))
-
-    @property
-    def ramdisk_dir(self):
-        """Returns the internal ramdisk dir."""
-        return self._ramdisk_dir
-
-
-class BootImage:
-    """A class that supports packing/unpacking a boot.img and ramdisk."""
-
-    def __init__(self, bootimg):
-        self._bootimg = bootimg
-        self._bootimg_dir = None
-        self._bootimg_type = None
-        self._ramdisk = None
-        self._previous_mkbootimg_args = []
-        self._temp_file_manager = TempFileManager()
-
-        self._unpack_bootimg()
-
-    def _get_vendor_ramdisks(self):
-        """Returns a list of vendor ramdisks after unpack."""
-        return sorted(glob.glob(
-            os.path.join(self._bootimg_dir, 'vendor_ramdisk*')))
-
-    def _unpack_bootimg(self):
-        """Unpacks the boot.img and the ramdisk inside."""
-        self._bootimg_dir = self._temp_file_manager.make_temp_dir(
-            suffix='_' + os.path.basename(self._bootimg))
-
-        # Unpacks the boot.img first.
-        unpack_bootimg_cmds = [
-            'unpack_bootimg',
-            '--boot_img', self._bootimg,
-            '--out', self._bootimg_dir,
-            '--format=mkbootimg',
-        ]
-        result = subprocess.run(unpack_bootimg_cmds, check=True,
-                                capture_output=True, encoding='utf-8')
-        self._previous_mkbootimg_args = shlex.split(result.stdout)
-        print("=== Unpacked boot image: '{}' ===".format(self._bootimg))
-
-        # From the output dir, checks there is 'ramdisk' or 'vendor_ramdisk'.
-        ramdisk = os.path.join(self._bootimg_dir, 'ramdisk')
-        vendor_ramdisk = os.path.join(self._bootimg_dir, 'vendor_ramdisk')
-        vendor_ramdisks = self._get_vendor_ramdisks()
-        if os.path.exists(ramdisk):
-            self._ramdisk = RamdiskImage(ramdisk)
-            self._bootimg_type = BootImageType.BOOT_IMAGE
-        elif os.path.exists(vendor_ramdisk):
-            self._ramdisk = RamdiskImage(vendor_ramdisk)
-            self._bootimg_type = BootImageType.VENDOR_BOOT_IMAGE
-        elif len(vendor_ramdisks) == 1:
-            self._ramdisk = RamdiskImage(vendor_ramdisks[0])
-            self._bootimg_type = BootImageType.SINGLE_RAMDISK_FRAGMENT
-        elif len(vendor_ramdisks) > 1:
-            # Creates an empty RamdiskImage() below, without unpack.
-            # We'll then add files into this newly created ramdisk, then pack
-            # it with other vendor ramdisks together.
-            self._ramdisk = RamdiskImage(ramdisk_img=None, unpack=False)
-            self._bootimg_type = BootImageType.MULTIPLE_RAMDISK_FRAGMENTS
-        else:
-            raise RuntimeError('Both ramdisk and vendor_ramdisk do not exist.')
-
-    def repack_bootimg(self):
-        """Repacks the ramdisk and rebuild the boot.img"""
-
-        new_ramdisk = self._temp_file_manager.make_temp_file(
-            prefix='ramdisk-patched')
-        self._ramdisk.repack_ramdisk(new_ramdisk)
-
-        mkbootimg_cmd = ['mkbootimg']
-
-        # Uses previous mkbootimg args, e.g., --vendor_cmdline, --dtb_offset.
-        mkbootimg_cmd.extend(self._previous_mkbootimg_args)
-
-        ramdisk_option = ''
-        if self._bootimg_type == BootImageType.BOOT_IMAGE:
-            ramdisk_option = '--ramdisk'
-            mkbootimg_cmd.extend(['--output', self._bootimg])
-        elif self._bootimg_type == BootImageType.VENDOR_BOOT_IMAGE:
-            ramdisk_option = '--vendor_ramdisk'
-            mkbootimg_cmd.extend(['--vendor_boot', self._bootimg])
-        elif self._bootimg_type == BootImageType.SINGLE_RAMDISK_FRAGMENT:
-            ramdisk_option = '--vendor_ramdisk_fragment'
-            mkbootimg_cmd.extend(['--vendor_boot', self._bootimg])
-        elif self._bootimg_type == BootImageType.MULTIPLE_RAMDISK_FRAGMENTS:
-            mkbootimg_cmd.extend(['--ramdisk_type', 'PLATFORM'])
-            ramdisk_name = (
-                'RAMDISK_' +
-                datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S'))
-            mkbootimg_cmd.extend(['--ramdisk_name', ramdisk_name])
-            mkbootimg_cmd.extend(['--vendor_ramdisk_fragment', new_ramdisk])
-            mkbootimg_cmd.extend(['--vendor_boot', self._bootimg])
-
-        if ramdisk_option and ramdisk_option not in mkbootimg_cmd:
-            raise RuntimeError("Failed to find '{}' from:\n  {}".format(
-                ramdisk_option, shlex.join(mkbootimg_cmd)))
-        # Replaces the original ramdisk with the newly packed ramdisk.
-        if ramdisk_option:
-            ramdisk_index = mkbootimg_cmd.index(ramdisk_option) + 1
-            mkbootimg_cmd[ramdisk_index] = new_ramdisk
-
-        subprocess.check_call(mkbootimg_cmd)
-        print("=== Repacked boot image: '{}' ===".format(self._bootimg))
-
-    def add_files(self, src_dir, files):
-        """Copy files from the src_dir into current ramdisk.
-
-        Args:
-            src_dir: a source dir containing the files to copy from.
-            files: a list of files or src_file:dst_file pairs to copy from
-              src_dir to the current ramdisk.
-        """
-        # Creates missing parent dirs with 0o755.
-        original_mask = os.umask(0o022)
-        for f in files:
-            if ':' in f:
-                src_file = os.path.join(src_dir, f.split(':')[0])
-                dst_file = os.path.join(self.ramdisk_dir, f.split(':')[1])
-            else:
-                src_file = os.path.join(src_dir, f)
-                dst_file = os.path.join(self.ramdisk_dir, f)
-
-            dst_dir = os.path.dirname(dst_file)
-            if not os.path.exists(dst_dir):
-                print("Creating dir '{}'".format(dst_dir))
-                os.makedirs(dst_dir, 0o755)
-            print("Copying file '{}' into '{}'".format(src_file, dst_file))
-            shutil.copy2(src_file, dst_file)
-        os.umask(original_mask)
-
-    @property
-    def ramdisk_dir(self):
-        """Returns the internal ramdisk dir."""
-        return self._ramdisk.ramdisk_dir
-
-
-def _get_repack_usage():
-    return """Usage examples:
-
-  * --ramdisk_add
-
-    Specifies a list of files or src_file:dst_file pairs to copy from
-    --src_bootimg's ramdisk into --dst_bootimg's ramdisk.
-
-    $ repack_bootimg \\
-        --src_bootimg boot-debug-5.4.img --dst_bootimg vendor_boot-debug.img \\
-        --ramdisk_add first_stage_ramdisk/userdebug_plat_sepolicy.cil:userdebug_plat_sepolicy.cil
-
-    The above command copies '/first_stage_ramdisk/userdebug_plat_sepolicy.cil'
-    from --src_bootimg's ramdisk to '/userdebug_plat_sepolicy.cil' of
-    --dst_bootimg's ramdisk, then repacks the --dst_bootimg.
-
-    $ repack_bootimg \\
-        --src_bootimg boot-debug-5.4.img --dst_bootimg vendor_boot-debug.img \\
-        --ramdisk_add first_stage_ramdisk/userdebug_plat_sepolicy.cil
-
-    This is similar to the previous example, but the source file path and
-    destination file path are the same:
-        '/first_stage_ramdisk/userdebug_plat_sepolicy.cil'.
-
-    We can also combine both usage together with a list of copy instructions.
-    For example:
-
-    $ repack_bootimg \\
-        --src_bootimg boot-debug-5.4.img --dst_bootimg vendor_boot-debug.img \\
-        --ramdisk_add file1 file2:/subdir/file2 file3
-"""
-
-
-def _parse_args():
-    """Parse command-line options."""
-    parser = argparse.ArgumentParser(
-        formatter_class=argparse.RawDescriptionHelpFormatter,
-        description='Repacks boot, recovery or vendor_boot image by importing'
-                    'ramdisk files from --src_bootimg to --dst_bootimg.',
-        epilog=_get_repack_usage(),
-    )
-
-    parser.add_argument(
-        '--src_bootimg', help='filename to source boot image',
-        type=str, required=True)
-    parser.add_argument(
-        '--dst_bootimg', help='filename to destination boot image',
-        type=str, required=True)
-    parser.add_argument(
-        '--ramdisk_add', nargs='+',
-        help='a list of files or src_file:dst_file pairs to add into '
-             'the ramdisk',
-        default=['userdebug_plat_sepolicy.cil']
-    )
-
-    return parser.parse_args()
-
-
-def main():
-    """Parse arguments and repack boot image."""
-    args = _parse_args()
-    src_bootimg = BootImage(args.src_bootimg)
-    dst_bootimg = BootImage(args.dst_bootimg)
-    dst_bootimg.add_files(src_bootimg.ramdisk_dir, args.ramdisk_add)
-    dst_bootimg.repack_bootimg()
-
-
-if __name__ == '__main__':
-    main()
diff --git a/tests/data/testkey_rsa2048.pem b/tests/data/testkey_rsa2048.pem
deleted file mode 100644
index 867dcff..0000000
--- a/tests/data/testkey_rsa2048.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAxlVR3TIkouAOvH79vaJTgFhpfvVKQIeVkFRZPVXK/zY0Gvrh
-4JAqGjJoW/PfrQv5sdD36qtHH3a+G5hLZ6Ni+t/mtfjucxZfuLGC3kmJ1T3XqEKZ
-gXXI2IR7vVSoImREvDQGEDyJwtHzLANlkbGg0cghVhWZSCAndO8BenalC2v94/rt
-DfkPekH6dgU3Sf40T0sBSeSY94mOzTaqOR2pfV1rWlLRdWmo33zeHBv52Rlbt0dM
-uXAureXWiHztkm5GCBC1dgM+CaxNtizNEgC91KcD0xuRCCM2WxH+r1lpszyIJDct
-YbrFmVEYl/kjQpafhy7Nsk1fqSTyRdriZSYmTQIDAQABAoIBAQC+kJgaCuX8wYAn
-SXWQ0fmdZlXnMNRpcF0a0pD0SAzGb1RdYBXMaXiqtyhiwc53PPxsCDdNecjayIMd
-jJVXPTwLhTruOgMS/bp3gcgWwV34UHV4LJXGOGAE+jbS0hbDBMiudOYmj6RmVshp
-z9G1zZCSQNMXHaWsEYkX59XpzzoB384nRul2QgEtwzUNR9XlpzgtJBLk3SACkvsN
-mQ/DW8IWHXLg8vLn1LzVJ2e3B16H4MoE2TCHxqfMgr03IDRRJogkenQuQsFhevYT
-o/mJyHSWavVgzMHG9I5m+eepF4Wyhj1Y4WyKAuMI+9dHAX/h7Lt8XFCQCh5DbkVG
-zGr34sWBAoGBAOs7n7YZqNaaguovfIdRRsxxZr1yJAyDsr6w3yGImDZYju4c4WY9
-5esO2kP3FA4p0c7FhQF5oOb1rBuHEPp36cpL4aGeK87caqTfq63WZAujoTZpr9Lp
-BRbkL7w/xG7jpQ/clpA8sHzHGQs/nelxoOtC7E118FiRgvD/jdhlMyL9AoGBANfX
-vyoN1pplfT2xR8QOjSZ+Q35S/+SAtMuBnHx3l0qH2bbBjcvM1MNDWjnRDyaYhiRu
-i+KA7tqfib09+XpB3g5D6Ov7ls/Ldx0S/VcmVWtia2HK8y8iLGtokoBZKQ5AaFX2
-iQU8+tC4h69GnJYQKqNwgCUzh8+gHX5Y46oDiTmRAoGAYpOx8lX+czB8/Da6MNrW
-mIZNT8atZLEsDs2ANEVRxDSIcTCZJId7+m1W+nRoaycLTWNowZ1+2ErLvR10+AGY
-b7Ys79Wg9idYaY9yGn9lnZsMzAiuLeyIvXcSqgjvAKlVWrhOQFOughvNWvFl85Yy
-oWSCMlPiTLtt7CCsCKsgKuECgYBgdIp6GZsIfkgclKe0hqgvRoeU4TR3gcjJlM9A
-lBTo+pKhaBectplx9RxR8AnsPobbqwcaHnIfAuKDzjk5mEvKZjClnFXF4HAHbyAF
-nRzZEy9XkWFhc80T5rRpZO7C7qdxmu2aiKixM3V3L3/0U58qULEDbubHMw9bEhAT
-PudI8QKBgHEEiMm/hr9T41hbQi/LYanWnlFw1ue+osKuF8bXQuxnnHNuFT/c+9/A
-vWhgqG6bOEHu+p/IPrYm4tBMYlwsyh4nXCyGgDJLbLIfzKwKAWCtH9LwnyDVhOow
-GH9shdR+sW3Ew97xef02KAH4VlNANEmBV4sQNqWWvsYrcFm2rOdL
------END RSA PRIVATE KEY-----
diff --git a/tests/mkbootimg_test.py b/tests/mkbootimg_test.py
deleted file mode 100644
index ae5cf6b..0000000
--- a/tests/mkbootimg_test.py
+++ /dev/null
@@ -1,735 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2020, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Tests mkbootimg and unpack_bootimg."""
-
-import filecmp
-import logging
-import os
-import random
-import shlex
-import subprocess
-import sys
-import tempfile
-import unittest
-
-BOOT_ARGS_OFFSET = 64
-BOOT_ARGS_SIZE = 512
-BOOT_EXTRA_ARGS_OFFSET = 608
-BOOT_EXTRA_ARGS_SIZE = 1024
-BOOT_V3_ARGS_OFFSET = 44
-VENDOR_BOOT_ARGS_OFFSET = 28
-VENDOR_BOOT_ARGS_SIZE = 2048
-
-BOOT_IMAGE_V4_SIGNATURE_SIZE = 4096
-
-TEST_KERNEL_CMDLINE = (
-    'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init '
-    'kfence.sample_interval=500 loop.max_part=7 bootconfig'
-)
-
-
-def generate_test_file(pathname, size, seed=None):
-    """Generates a gibberish-filled test file and returns its pathname."""
-    random.seed(os.path.basename(pathname) if seed is None else seed)
-    with open(pathname, 'wb') as f:
-        f.write(random.randbytes(size))
-    return pathname
-
-
-def subsequence_of(list1, list2):
-    """Returns True if list1 is a subsequence of list2.
-
-    >>> subsequence_of([], [1])
-    True
-    >>> subsequence_of([2, 4], [1, 2, 3, 4])
-    True
-    >>> subsequence_of([1, 2, 2], [1, 2, 3])
-    False
-    """
-    if len(list1) == 0:
-        return True
-    if len(list2) == 0:
-        return False
-    if list1[0] == list2[0]:
-        return subsequence_of(list1[1:], list2[1:])
-    return subsequence_of(list1, list2[1:])
-
-
-class MkbootimgTest(unittest.TestCase):
-    """Tests the functionalities of mkbootimg and unpack_bootimg."""
-
-    def setUp(self):
-        # Saves the test executable directory so that relative path references
-        # to test dependencies don't rely on being manually run from the
-        # executable directory.
-        # With this, we can just open "./tests/data/testkey_rsa2048.pem" in the
-        # following tests with subprocess.run(..., cwd=self._exec_dir, ...).
-        self._exec_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
-
-        self._avbtool_path = os.path.join(self._exec_dir, 'avbtool')
-
-        # Set self.maxDiff to None to see full diff in assertion.
-        # C0103: invalid-name for maxDiff.
-        self.maxDiff = None  # pylint: disable=C0103
-
-    def _test_boot_image_v4_signature(self, avbtool_path):
-        """Tests the boot_signature in boot.img v4."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '4',
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', TEST_KERNEL_CMDLINE,
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-01',
-                '--gki_signing_algorithm', 'SHA256_RSA2048',
-                '--gki_signing_key', './tests/data/testkey_rsa2048.pem',
-                '--gki_signing_signature_args',
-                '--prop foo:bar --prop gki:nice',
-                '--output', boot_img,
-            ]
-
-            if avbtool_path:
-                mkbootimg_cmds.extend(
-                    ['--gki_signing_avbtool_path', avbtool_path])
-
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', boot_img,
-                '--out', os.path.join(temp_out_dir, 'out'),
-            ]
-
-            # cwd=self._exec_dir is required to read
-            # ./tests/data/testkey_rsa2048.pem for --gki_signing_key.
-            subprocess.run(mkbootimg_cmds, check=True, cwd=self._exec_dir)
-            subprocess.run(unpack_bootimg_cmds, check=True)
-
-            # Checks the content of the boot signature.
-            expected_boot_signature_info = (
-                'Minimum libavb version:   1.0\n'
-                'Header Block:             256 bytes\n'
-                'Authentication Block:     320 bytes\n'
-                'Auxiliary Block:          832 bytes\n'
-                'Public key (sha1):        '
-                'cdbb77177f731920bbe0a0f94f84d9038ae0617d\n'
-                'Algorithm:                SHA256_RSA2048\n'
-                'Rollback Index:           0\n'
-                'Flags:                    0\n'
-                'Rollback Index Location:  0\n'
-                "Release String:           'avbtool 1.2.0'\n"
-                'Descriptors:\n'
-                '    Hash descriptor:\n'
-                '      Image Size:            12288 bytes\n'
-                '      Hash Algorithm:        sha256\n'
-                '      Partition Name:        boot\n'
-                '      Salt:                  d00df00d\n'
-                '      Digest:                '
-                'cf3755630856f23ab70e501900050fee'
-                'f30b633b3e82a9085a578617e344f9c7\n'
-                '      Flags:                 0\n'
-                "    Prop: foo -> 'bar'\n"
-                "    Prop: gki -> 'nice'\n"
-            )
-
-            avbtool_info_cmds = [
-                # use avbtool_path if it is not None.
-                avbtool_path or 'avbtool',
-                'info_image', '--image',
-                os.path.join(temp_out_dir, 'out', 'boot_signature')
-            ]
-            result = subprocess.run(avbtool_info_cmds, check=True,
-                                    capture_output=True, encoding='utf-8')
-
-            self.assertEqual(result.stdout, expected_boot_signature_info)
-
-    def test_boot_image_v4_signature_without_avbtool_path(self):
-        """Boot signature generation without --gki_signing_avbtool_path."""
-        self._test_boot_image_v4_signature(avbtool_path=None)
-
-    def test_boot_image_v4_signature_with_avbtool_path(self):
-        """Boot signature generation with --gki_signing_avbtool_path."""
-        self._test_boot_image_v4_signature(avbtool_path=self._avbtool_path)
-
-    def test_boot_image_v4_signature_exceed_size(self):
-        """Tests the boot signature size exceeded in a boot image version 4."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '4',
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', TEST_KERNEL_CMDLINE,
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-01',
-                '--gki_signing_avbtool_path', self._avbtool_path,
-                '--gki_signing_algorithm', 'SHA256_RSA2048',
-                '--gki_signing_key', './tests/data/testkey_rsa2048.pem',
-                '--gki_signing_signature_args',
-                # Makes it exceed the signature max size.
-                '--prop foo:bar --prop gki:nice ' * 64,
-                '--output', boot_img,
-            ]
-
-            # cwd=self._exec_dir is required to read
-            # ./tests/data/testkey_rsa2048.pem for --gki_signing_key.
-            try:
-                subprocess.run(mkbootimg_cmds, check=True, capture_output=True,
-                               cwd=self._exec_dir, encoding='utf-8')
-                self.fail('Exceeding signature size assertion is not raised')
-            except subprocess.CalledProcessError as e:
-                self.assertIn('ValueError: boot sigature size is > 4096',
-                              e.stderr)
-
-    def test_boot_image_v4_signature_zeros(self):
-        """Tests no boot signature in a boot image version 4."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-
-            # The boot signature will be zeros if no
-            # --gki_signing_[algorithm|key] is provided.
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '4',
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', TEST_KERNEL_CMDLINE,
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-01',
-                '--output', boot_img,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', boot_img,
-                '--out', os.path.join(temp_out_dir, 'out'),
-            ]
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            subprocess.run(unpack_bootimg_cmds, check=True)
-
-            boot_signature = os.path.join(
-                temp_out_dir, 'out', 'boot_signature')
-            with open(boot_signature) as f:
-                zeros = '\x00' * BOOT_IMAGE_V4_SIGNATURE_SIZE
-                self.assertEqual(f.read(), zeros)
-
-    def test_vendor_boot_v4(self):
-        """Tests vendor_boot version 4."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img')
-            dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000)
-            ramdisk1 = generate_test_file(
-                os.path.join(temp_out_dir, 'ramdisk1'), 0x1000)
-            ramdisk2 = generate_test_file(
-                os.path.join(temp_out_dir, 'ramdisk2'), 0x2000)
-            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_cmdline', TEST_KERNEL_CMDLINE,
-                '--vendor_bootconfig', bootconfig,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', vendor_boot_img,
-                '--out', os.path.join(temp_out_dir, 'out'),
-            ]
-            expected_output = [
-                'boot magic: VNDRBOOT',
-                'vendor boot image header version: 4',
-                'vendor ramdisk total size: 16384',
-                f'vendor command line args: {TEST_KERNEL_CMDLINE}',
-                'dtb size: 4096',
-                'vendor ramdisk table size: 324',
-                'size: 4096', 'offset: 0', 'type: 0x1', 'name:',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                'size: 4096', 'offset: 4096', 'type: 0x1', 'name: RAMDISK1',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                'size: 8192', 'offset: 8192', 'type: 0x3', 'name: RAMDISK2',
-                '0x00c0ffee, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x00000000,',
-                '0x00000000, 0x00000000, 0x00000000, 0x15151515,',
-                'vendor bootconfig size: 4096',
-            ]
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            result = subprocess.run(unpack_bootimg_cmds, check=True,
-                                    capture_output=True, encoding='utf-8')
-            output = [line.strip() for line in result.stdout.splitlines()]
-            if not subsequence_of(expected_output, output):
-                msg = '\n'.join([
-                    'Unexpected unpack_bootimg output:',
-                    'Expected:',
-                    ' ' + '\n '.join(expected_output),
-                    '',
-                    'Actual:',
-                    ' ' + '\n '.join(output),
-                ])
-                self.fail(msg)
-
-    def test_unpack_vendor_boot_image_v4(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img')
-            vendor_boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'vendor_boot.img.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_cmdline', TEST_KERNEL_CMDLINE,
-                '--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_img_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_img_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(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img')
-            vendor_boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'vendor_boot.img.reconstructed')
-            dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x121212)
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '3',
-                '--vendor_boot', vendor_boot_img,
-                '--vendor_ramdisk', ramdisk,
-                '--dtb', dtb,
-                '--vendor_cmdline', TEST_KERNEL_CMDLINE,
-                '--board', 'product_name',
-                '--base', '0x00000000',
-                '--dtb_offset', '0x01f00000',
-                '--kernel_offset', '0x00008000',
-                '--pagesize', '0x00001000',
-                '--ramdisk_offset', '0x01000000',
-                '--tags_offset', '0x00000100',
-            ]
-            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_img_reconstructed,
-            ]
-            mkbootimg_cmds.extend(shlex.split(result.stdout))
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            self.assertTrue(
-                filecmp.cmp(vendor_boot_img, vendor_boot_img_reconstructed),
-                'reconstructed vendor_boot image differ from the original')
-
-    def test_unpack_boot_image_v3(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'boot.img.reconstructed')
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '3',
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', TEST_KERNEL_CMDLINE,
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-01',
-                '--output', boot_img,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', 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',
-                '--out', boot_img_reconstructed,
-            ]
-            mkbootimg_cmds.extend(shlex.split(result.stdout))
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            self.assertTrue(
-                filecmp.cmp(boot_img, boot_img_reconstructed),
-                'reconstructed boot image differ from the original')
-
-    def test_unpack_boot_image_v2(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            # Output image path.
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'boot.img.reconstructed')
-            # Creates blank images first.
-            kernel = generate_test_file(
-                os.path.join(temp_out_dir, 'kernel'), 0x1000)
-            ramdisk = generate_test_file(
-                os.path.join(temp_out_dir, 'ramdisk'), 0x1000)
-            second = generate_test_file(
-                os.path.join(temp_out_dir, 'second'), 0x1000)
-            recovery_dtbo = generate_test_file(
-                os.path.join(temp_out_dir, 'recovery_dtbo'), 0x1000)
-            dtb = generate_test_file(
-                os.path.join(temp_out_dir, 'dtb'), 0x1000)
-
-            cmdline = (BOOT_ARGS_SIZE - 1) * 'x'
-            extra_cmdline = (BOOT_EXTRA_ARGS_SIZE - 1) * 'y'
-
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '2',
-                '--base', '0x00000000',
-                '--kernel', kernel,
-                '--kernel_offset', '0x00008000',
-                '--ramdisk', ramdisk,
-                '--ramdisk_offset', '0x01000000',
-                '--second', second,
-                '--second_offset', '0x40000000',
-                '--recovery_dtbo', recovery_dtbo,
-                '--dtb', dtb,
-                '--dtb_offset', '0x01f00000',
-                '--tags_offset', '0x00000100',
-                '--pagesize', '0x00001000',
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-03',
-                '--board', 'boot_v2',
-                '--cmdline', cmdline + extra_cmdline,
-                '--output', boot_img,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', 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',
-                '--out', boot_img_reconstructed,
-            ]
-            mkbootimg_cmds.extend(shlex.split(result.stdout))
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            self.assertTrue(
-                filecmp.cmp(boot_img, boot_img_reconstructed),
-                'reconstructed boot image differ from the original')
-
-    def test_unpack_boot_image_v1(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            # Output image path.
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'boot.img.reconstructed')
-            # Creates blank images first.
-            kernel = generate_test_file(
-                os.path.join(temp_out_dir, 'kernel'), 0x1000)
-            ramdisk = generate_test_file(
-                os.path.join(temp_out_dir, 'ramdisk'), 0x1000)
-            recovery_dtbo = generate_test_file(
-                os.path.join(temp_out_dir, 'recovery_dtbo'), 0x1000)
-
-            cmdline = (BOOT_ARGS_SIZE - 1) * 'x'
-            extra_cmdline = (BOOT_EXTRA_ARGS_SIZE - 1) * 'y'
-
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '1',
-                '--base', '0x00000000',
-                '--kernel', kernel,
-                '--kernel_offset', '0x00008000',
-                '--ramdisk', ramdisk,
-                '--ramdisk_offset', '0x01000000',
-                '--recovery_dtbo', recovery_dtbo,
-                '--tags_offset', '0x00000100',
-                '--pagesize', '0x00001000',
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-03',
-                '--board', 'boot_v1',
-                '--cmdline', cmdline + extra_cmdline,
-                '--output', boot_img,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', 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',
-                '--out', boot_img_reconstructed,
-            ]
-            mkbootimg_cmds.extend(shlex.split(result.stdout))
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            self.assertTrue(
-                filecmp.cmp(boot_img, boot_img_reconstructed),
-                'reconstructed boot image differ from the original')
-
-    def test_unpack_boot_image_v0(self):
-        """Tests that mkbootimg(unpack_bootimg(image)) is an identity."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            # Output image path.
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            boot_img_reconstructed = os.path.join(
-                temp_out_dir, 'boot.img.reconstructed')
-            # Creates blank images first.
-            kernel = generate_test_file(
-                os.path.join(temp_out_dir, 'kernel'), 0x1000)
-            ramdisk = generate_test_file(
-                os.path.join(temp_out_dir, 'ramdisk'), 0x1000)
-            second = generate_test_file(
-                os.path.join(temp_out_dir, 'second'), 0x1000)
-
-            cmdline = (BOOT_ARGS_SIZE - 1) * 'x'
-            extra_cmdline = (BOOT_EXTRA_ARGS_SIZE - 1) * 'y'
-
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '0',
-                '--base', '0x00000000',
-                '--kernel', kernel,
-                '--kernel_offset', '0x00008000',
-                '--ramdisk', ramdisk,
-                '--ramdisk_offset', '0x01000000',
-                '--second', second,
-                '--second_offset', '0x40000000',
-                '--tags_offset', '0x00000100',
-                '--pagesize', '0x00001000',
-                '--os_version', '11.0.0',
-                '--os_patch_level', '2021-03',
-                '--board', 'boot_v0',
-                '--cmdline', cmdline + extra_cmdline,
-                '--output', boot_img,
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', boot_img,
-                '--out', os.path.join(temp_out_dir, 'out'),
-            ]
-            unpack_bootimg_cmds = [
-                'unpack_bootimg',
-                '--boot_img', 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',
-                '--out', boot_img_reconstructed,
-            ]
-            mkbootimg_cmds.extend(shlex.split(result.stdout))
-
-            subprocess.run(mkbootimg_cmds, check=True)
-            self.assertTrue(
-                filecmp.cmp(boot_img, boot_img_reconstructed),
-                'reconstructed boot image differ from the original')
-
-    def test_boot_image_v2_cmdline_null_terminator(self):
-        """Tests that kernel commandline is null-terminated."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000)
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            cmdline = (BOOT_ARGS_SIZE - 1) * 'x'
-            extra_cmdline = (BOOT_EXTRA_ARGS_SIZE - 1) * 'y'
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '2',
-                '--dtb', dtb,
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', cmdline + extra_cmdline,
-                '--output', boot_img,
-            ]
-
-            subprocess.run(mkbootimg_cmds, check=True)
-
-            with open(boot_img, 'rb') as f:
-                raw_boot_img = f.read()
-            raw_cmdline = raw_boot_img[BOOT_ARGS_OFFSET:][:BOOT_ARGS_SIZE]
-            raw_extra_cmdline = (raw_boot_img[BOOT_EXTRA_ARGS_OFFSET:]
-                                 [:BOOT_EXTRA_ARGS_SIZE])
-            self.assertEqual(raw_cmdline, cmdline.encode() + b'\x00')
-            self.assertEqual(raw_extra_cmdline,
-                             extra_cmdline.encode() + b'\x00')
-
-    def test_boot_image_v3_cmdline_null_terminator(self):
-        """Tests that kernel commandline is null-terminated."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            kernel = generate_test_file(os.path.join(temp_out_dir, 'kernel'),
-                                        0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            cmdline = BOOT_ARGS_SIZE * 'x' + (BOOT_EXTRA_ARGS_SIZE - 1) * 'y'
-            boot_img = os.path.join(temp_out_dir, 'boot.img')
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '3',
-                '--kernel', kernel,
-                '--ramdisk', ramdisk,
-                '--cmdline', cmdline,
-                '--output', boot_img,
-            ]
-
-            subprocess.run(mkbootimg_cmds, check=True)
-
-            with open(boot_img, 'rb') as f:
-                raw_boot_img = f.read()
-            raw_cmdline = (raw_boot_img[BOOT_V3_ARGS_OFFSET:]
-                           [:BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE])
-            self.assertEqual(raw_cmdline, cmdline.encode() + b'\x00')
-
-    def test_vendor_boot_image_v3_cmdline_null_terminator(self):
-        """Tests that kernel commandline is null-terminated."""
-        with tempfile.TemporaryDirectory() as temp_out_dir:
-            dtb = generate_test_file(os.path.join(temp_out_dir, 'dtb'), 0x1000)
-            ramdisk = generate_test_file(os.path.join(temp_out_dir, 'ramdisk'),
-                                         0x1000)
-            vendor_cmdline = (VENDOR_BOOT_ARGS_SIZE - 1) * 'x'
-            vendor_boot_img = os.path.join(temp_out_dir, 'vendor_boot.img')
-            mkbootimg_cmds = [
-                'mkbootimg',
-                '--header_version', '3',
-                '--dtb', dtb,
-                '--vendor_ramdisk', ramdisk,
-                '--vendor_cmdline', vendor_cmdline,
-                '--vendor_boot', vendor_boot_img,
-            ]
-
-            subprocess.run(mkbootimg_cmds, check=True)
-
-            with open(vendor_boot_img, 'rb') as f:
-                raw_vendor_boot_img = f.read()
-            raw_vendor_cmdline = (raw_vendor_boot_img[VENDOR_BOOT_ARGS_OFFSET:]
-                                  [:VENDOR_BOOT_ARGS_SIZE])
-            self.assertEqual(raw_vendor_cmdline,
-                             vendor_cmdline.encode() + b'\x00')
-
-
-# I don't know how, but we need both the logger configuration and verbosity
-# level > 2 to make atest work. And yes this line needs to be at the very top
-# level, not even in the "__main__" indentation block.
-logging.basicConfig(stream=sys.stdout)
-
-if __name__ == '__main__':
-    unittest.main(verbosity=2)
diff --git a/unpack_bootimg.py b/unpack_bootimg.py
index 2b176e5..83c2bbe 100755
--- a/unpack_bootimg.py
+++ b/unpack_bootimg.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python3
-#
+#!/usr/bin/env python
 # Copyright 2018, The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,20 +13,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Unpacks the boot image.
+"""unpacks the bootimage.
 
 Extracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images.
 """
 
-from argparse import ArgumentParser, FileType, RawDescriptionHelpFormatter
+from __future__ import print_function
+from argparse import ArgumentParser, FileType
 from struct import unpack
 import os
-import shlex
 
 BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
-VENDOR_RAMDISK_NAME_SIZE = 32
-VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16
-
+VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
 
 def create_out_dir(dir_path):
     """creates a directory 'dir_path' if it does not exist"""
@@ -66,480 +63,182 @@
     return '{:04d}-{:02d}'.format(y, m)
 
 
-def decode_os_version_patch_level(os_version_patch_level):
-    """Returns a tuple of (os_version, os_patch_level)."""
-    os_version = os_version_patch_level >> 11
-    os_patch_level = os_version_patch_level & ((1<<11) - 1)
-    return (format_os_version(os_version),
-            format_os_patch_level(os_patch_level))
+def print_os_version_patch_level(value):
+    os_version = value >> 11
+    os_patch_level = value & ((1<<11) - 1)
+    print('os version: %s' % format_os_version(os_version))
+    print('os patch level: %s' % format_os_patch_level(os_patch_level))
 
 
-class BootImageInfoFormatter:
-    """Formats the boot image info."""
-
-    def format_pretty_text(self):
-        lines = []
-        lines.append(f'boot magic: {self.boot_magic}')
-
-        if self.header_version < 3:
-            lines.append(f'kernel_size: {self.kernel_size}')
-            lines.append(
-                f'kernel load address: {self.kernel_load_address:#010x}')
-            lines.append(f'ramdisk size: {self.ramdisk_size}')
-            lines.append(
-                f'ramdisk load address: {self.ramdisk_load_address:#010x}')
-            lines.append(f'second bootloader size: {self.second_size}')
-            lines.append(
-                f'second bootloader load address: '
-                f'{self.second_load_address:#010x}')
-            lines.append(
-                f'kernel tags load address: {self.tags_load_address:#010x}')
-            lines.append(f'page size: {self.page_size}')
-        else:
-            lines.append(f'kernel_size: {self.kernel_size}')
-            lines.append(f'ramdisk size: {self.ramdisk_size}')
-
-        lines.append(f'os version: {self.os_version}')
-        lines.append(f'os patch level: {self.os_patch_level}')
-        lines.append(f'boot image header version: {self.header_version}')
-
-        if self.header_version < 3:
-            lines.append(f'product name: {self.product_name}')
-
-        lines.append(f'command line args: {self.cmdline}')
-
-        if self.header_version < 3:
-            lines.append(f'additional command line args: {self.extra_cmdline}')
-
-        if self.header_version in {1, 2}:
-            lines.append(f'recovery dtbo size: {self.recovery_dtbo_size}')
-            lines.append(
-                f'recovery dtbo offset: {self.recovery_dtbo_offset:#018x}')
-            lines.append(f'boot header size: {self.boot_header_size}')
-
-        if self.header_version == 2:
-            lines.append(f'dtb size: {self.dtb_size}')
-            lines.append(f'dtb address: {self.dtb_load_address:#018x}')
-
-        if self.header_version >= 4:
-            lines.append(
-                f'boot.img signature size: {self.boot_signature_size}')
-
-        return '\n'.join(lines)
-
-    def format_mkbootimg_argument(self):
-        args = []
-        args.extend(['--header_version', str(self.header_version)])
-        args.extend(['--os_version', self.os_version])
-        args.extend(['--os_patch_level', self.os_patch_level])
-
-        args.extend(['--kernel', os.path.join(self.image_dir, 'kernel')])
-        args.extend(['--ramdisk', os.path.join(self.image_dir, 'ramdisk')])
-
-        if self.header_version <= 2:
-            if self.second_size > 0:
-                args.extend(['--second',
-                             os.path.join(self.image_dir, 'second')])
-            if self.recovery_dtbo_size > 0:
-                args.extend(['--recovery_dtbo',
-                             os.path.join(self.image_dir, 'recovery_dtbo')])
-            if self.dtb_size > 0:
-                args.extend(['--dtb', os.path.join(self.image_dir, 'dtb')])
-
-            args.extend(['--pagesize', f'{self.page_size:#010x}'])
-
-            # Kernel load address is base + kernel_offset in mkbootimg.py.
-            # However we don't know the value of 'base' when unpacking a boot
-            # image in this script, so we set 'base' to zero and 'kernel_offset'
-            # to the kernel load address, 'ramdisk_offset' to the ramdisk load
-            # address, ... etc.
-            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(['--second_offset',
-                         f'{self.second_load_address:#010x}'])
-            args.extend(['--tags_offset', f'{self.tags_load_address:#010x}'])
-
-            # dtb is added in boot image v2, and is absent in v1 or v0.
-            if self.header_version == 2:
-                # dtb_offset is uint64_t.
-                args.extend(['--dtb_offset', f'{self.dtb_load_address:#018x}'])
-
-            args.extend(['--board', self.product_name])
-            args.extend(['--cmdline', self.cmdline + self.extra_cmdline])
-        else:
-            args.extend(['--cmdline', self.cmdline])
-
-        return args
-
-
-def unpack_boot_image(args):
+def unpack_bootimage(args):
     """extracts kernel, ramdisk, second bootloader and recovery dtbo"""
-    info = BootImageInfoFormatter()
-    info.boot_magic = unpack('8s', args.boot_img.read(8))[0].decode()
-
     kernel_ramdisk_second_info = unpack('9I', args.boot_img.read(9 * 4))
-    # header_version is always at [8] regardless of the value of header_version.
-    info.header_version = kernel_ramdisk_second_info[8]
-
-    if info.header_version < 3:
-        info.kernel_size = kernel_ramdisk_second_info[0]
-        info.kernel_load_address = kernel_ramdisk_second_info[1]
-        info.ramdisk_size = kernel_ramdisk_second_info[2]
-        info.ramdisk_load_address = kernel_ramdisk_second_info[3]
-        info.second_size = kernel_ramdisk_second_info[4]
-        info.second_load_address = kernel_ramdisk_second_info[5]
-        info.tags_load_address = kernel_ramdisk_second_info[6]
-        info.page_size = kernel_ramdisk_second_info[7]
-        os_version_patch_level = unpack('I', args.boot_img.read(1 * 4))[0]
+    version = kernel_ramdisk_second_info[8]
+    if version < 3:
+        print('kernel_size: %s' % kernel_ramdisk_second_info[0])
+        print('kernel load address: %#x' % kernel_ramdisk_second_info[1])
+        print('ramdisk size: %s' % kernel_ramdisk_second_info[2])
+        print('ramdisk load address: %#x' % kernel_ramdisk_second_info[3])
+        print('second bootloader size: %s' % kernel_ramdisk_second_info[4])
+        print('second bootloader load address: %#x' % kernel_ramdisk_second_info[5])
+        print('kernel tags load address: %#x' % kernel_ramdisk_second_info[6])
+        print('page size: %s' % kernel_ramdisk_second_info[7])
+        print_os_version_patch_level(unpack('I', args.boot_img.read(1 * 4))[0])
     else:
-        info.kernel_size = kernel_ramdisk_second_info[0]
-        info.ramdisk_size = kernel_ramdisk_second_info[1]
-        os_version_patch_level = kernel_ramdisk_second_info[2]
-        info.second_size = 0
-        info.page_size = BOOT_IMAGE_HEADER_V3_PAGESIZE
+        print('kernel_size: %s' % kernel_ramdisk_second_info[0])
+        print('ramdisk size: %s' % kernel_ramdisk_second_info[1])
+        print_os_version_patch_level(kernel_ramdisk_second_info[2])
 
-    info.os_version, info.os_patch_level = decode_os_version_patch_level(
-        os_version_patch_level)
+    print('boot image header version: %s' % version)
 
-    if info.header_version < 3:
-        info.product_name = cstr(unpack('16s',
-                                        args.boot_img.read(16))[0].decode())
-        info.cmdline = cstr(unpack('512s', args.boot_img.read(512))[0].decode())
+    if version < 3:
+        product_name = cstr(unpack('16s', args.boot_img.read(16))[0].decode())
+        print('product name: %s' % product_name)
+        cmdline = cstr(unpack('512s', args.boot_img.read(512))[0].decode())
+        print('command line args: %s' % cmdline)
+    else:
+        cmdline = cstr(unpack('1536s', args.boot_img.read(1536))[0].decode())
+        print('command line args: %s' % cmdline)
+
+    if version < 3:
         args.boot_img.read(32)  # ignore SHA
-        info.extra_cmdline = cstr(unpack('1024s',
-                                         args.boot_img.read(1024))[0].decode())
-    else:
-        info.cmdline = cstr(unpack('1536s',
-                                   args.boot_img.read(1536))[0].decode())
 
-    if info.header_version in {1, 2}:
-        info.recovery_dtbo_size = unpack('I', args.boot_img.read(1 * 4))[0]
-        info.recovery_dtbo_offset = unpack('Q', args.boot_img.read(8))[0]
-        info.boot_header_size = unpack('I', args.boot_img.read(4))[0]
-    else:
-        info.recovery_dtbo_size = 0
+    if version < 3:
+        extra_cmdline = cstr(unpack('1024s',
+                                    args.boot_img.read(1024))[0].decode())
+        print('additional command line args: %s' % extra_cmdline)
 
-    if info.header_version == 2:
-        info.dtb_size = unpack('I', args.boot_img.read(4))[0]
-        info.dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+    if version < 3:
+        kernel_size = kernel_ramdisk_second_info[0]
+        ramdisk_size = kernel_ramdisk_second_info[2]
+        second_size = kernel_ramdisk_second_info[4]
+        page_size = kernel_ramdisk_second_info[7]
     else:
-        info.dtb_size = 0
-        info.dtb_load_address = 0
+        kernel_size = kernel_ramdisk_second_info[0]
+        ramdisk_size = kernel_ramdisk_second_info[1]
+        second_size = 0
+        page_size = BOOT_IMAGE_HEADER_V3_PAGESIZE
 
-    if info.header_version >= 4:
-        info.boot_signature_size = unpack('I', args.boot_img.read(4))[0]
+    if 0 < version < 3:
+        recovery_dtbo_size = unpack('I', args.boot_img.read(1 * 4))[0]
+        print('recovery dtbo size: %s' % recovery_dtbo_size)
+        recovery_dtbo_offset = unpack('Q', args.boot_img.read(8))[0]
+        print('recovery dtbo offset: %#x' % recovery_dtbo_offset)
+        boot_header_size = unpack('I', args.boot_img.read(4))[0]
+        print('boot header size: %s' % boot_header_size)
     else:
-        info.boot_signature_size = 0
+        recovery_dtbo_size = 0
+    if 1 < version < 3:
+        dtb_size = unpack('I', args.boot_img.read(4))[0]
+        print('dtb size: %s' % dtb_size)
+        dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+        print('dtb address: %#x' % dtb_load_address)
+    else:
+        dtb_size = 0
+
 
     # The first page contains the boot header
     num_header_pages = 1
 
-    # Convenient shorthand.
-    page_size = info.page_size
-
-    num_kernel_pages = get_number_of_pages(info.kernel_size, page_size)
+    num_kernel_pages = get_number_of_pages(kernel_size, page_size)
     kernel_offset = page_size * num_header_pages  # header occupies a page
-    image_info_list = [(kernel_offset, info.kernel_size, 'kernel')]
+    image_info_list = [(kernel_offset, kernel_size, 'kernel')]
 
-    num_ramdisk_pages = get_number_of_pages(info.ramdisk_size, page_size)
+    num_ramdisk_pages = get_number_of_pages(ramdisk_size, page_size)
     ramdisk_offset = page_size * (num_header_pages + num_kernel_pages
                                  ) # header + kernel
-    image_info_list.append((ramdisk_offset, info.ramdisk_size, 'ramdisk'))
+    image_info_list.append((ramdisk_offset, ramdisk_size, 'ramdisk'))
 
-    if info.second_size > 0:
+    if second_size > 0:
         second_offset = page_size * (
             num_header_pages + num_kernel_pages + num_ramdisk_pages
             )  # header + kernel + ramdisk
-        image_info_list.append((second_offset, info.second_size, 'second'))
+        image_info_list.append((second_offset, second_size, 'second'))
 
-    if info.recovery_dtbo_size > 0:
-        image_info_list.append((info.recovery_dtbo_offset,
-                                info.recovery_dtbo_size,
+    if recovery_dtbo_size > 0:
+        image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size,
                                 'recovery_dtbo'))
-    if info.dtb_size > 0:
-        num_second_pages = get_number_of_pages(info.second_size, page_size)
-        num_recovery_dtbo_pages = get_number_of_pages(
-            info.recovery_dtbo_size, page_size)
+    if dtb_size > 0:
+        num_second_pages = get_number_of_pages(second_size, page_size)
+        num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size)
         dtb_offset = page_size * (
-            num_header_pages + num_kernel_pages + num_ramdisk_pages +
-            num_second_pages + num_recovery_dtbo_pages)
+            num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages +
+            num_recovery_dtbo_pages
+        )
 
-        image_info_list.append((dtb_offset, info.dtb_size, 'dtb'))
+        image_info_list.append((dtb_offset, dtb_size, 'dtb'))
 
-    if info.boot_signature_size > 0:
-        # boot signature only exists in boot.img version >= v4.
-        # There are only kernel and ramdisk pages before the signature.
-        boot_signature_offset = page_size * (
-            num_header_pages + num_kernel_pages + num_ramdisk_pages)
-
-        image_info_list.append((boot_signature_offset, info.boot_signature_size,
-                                'boot_signature'))
-
-    create_out_dir(args.out)
-    for offset, size, name in image_info_list:
-        extract_image(offset, size, args.boot_img, os.path.join(args.out, name))
-    info.image_dir = args.out
-
-    return info
+    for image_info in image_info_list:
+        extract_image(image_info[0], image_info[1], args.boot_img,
+                      os.path.join(args.out, image_info[2]))
 
 
-class VendorBootImageInfoFormatter:
-    """Formats the vendor_boot image info."""
+def unpack_vendor_bootimage(args):
+    kernel_ramdisk_info = unpack('5I', args.boot_img.read(5 * 4))
+    print('vendor boot image header version: %s' % kernel_ramdisk_info[0])
+    print('kernel load address: %#x' % kernel_ramdisk_info[2])
+    print('ramdisk load address: %#x' % kernel_ramdisk_info[3])
+    print('vendor ramdisk size: %s' % kernel_ramdisk_info[4])
 
-    def format_pretty_text(self):
-        lines = []
-        lines.append(f'boot magic: {self.boot_magic}')
-        lines.append(f'vendor boot image header version: {self.header_version}')
-        lines.append(f'page size: {self.page_size:#010x}')
-        lines.append(f'kernel load address: {self.kernel_load_address:#010x}')
-        lines.append(f'ramdisk load address: {self.ramdisk_load_address:#010x}')
-        if self.header_version > 3:
-            lines.append(
-                f'vendor ramdisk total size: {self.vendor_ramdisk_size}')
-        else:
-            lines.append(f'vendor ramdisk size: {self.vendor_ramdisk_size}')
-        lines.append(f'vendor command line args: {self.cmdline}')
-        lines.append(
-            f'kernel tags load address: {self.tags_load_address:#010x}')
-        lines.append(f'product name: {self.product_name}')
-        lines.append(f'vendor boot image header size: {self.header_size}')
-        lines.append(f'dtb size: {self.dtb_size}')
-        lines.append(f'dtb address: {self.dtb_load_address:#018x}')
-        if self.header_version > 3:
-            lines.append(
-                f'vendor ramdisk table size: {self.vendor_ramdisk_table_size}')
-            lines.append('vendor ramdisk table: [')
-            indent = lambda level: ' ' * 4 * level
-            for entry in self.vendor_ramdisk_table:
-                (output_ramdisk_name, ramdisk_size, ramdisk_offset,
-                 ramdisk_type, ramdisk_name, board_id) = entry
-                lines.append(indent(1) + f'{output_ramdisk_name}: ''{')
-                lines.append(indent(2) + f'size: {ramdisk_size}')
-                lines.append(indent(2) + f'offset: {ramdisk_offset}')
-                lines.append(indent(2) + f'type: {ramdisk_type:#x}')
-                lines.append(indent(2) + f'name: {ramdisk_name}')
-                lines.append(indent(2) + 'board_id: [')
-                stride = 4
-                for row_idx in range(0, len(board_id), stride):
-                    row = board_id[row_idx:row_idx + stride]
-                    lines.append(
-                        indent(3) + ' '.join(f'{e:#010x},' for e in row))
-                lines.append(indent(2) + ']')
-                lines.append(indent(1) + '}')
-            lines.append(']')
-            lines.append(
-                f'vendor bootconfig size: {self.vendor_bootconfig_size}')
+    cmdline = cstr(unpack('2048s', args.boot_img.read(2048))[0].decode())
+    print('vendor command line args: %s' % cmdline)
 
-        return '\n'.join(lines)
+    tags_load_address = unpack('I', args.boot_img.read(1 * 4))[0]
+    print('kernel tags load address: %#x' % tags_load_address)
 
-    def format_mkbootimg_argument(self):
-        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])
+    product_name = cstr(unpack('16s', args.boot_img.read(16))[0].decode())
+    print('product name: %s' % product_name)
 
-        args.extend(['--dtb', os.path.join(self.image_dir, 'dtb')])
+    dtb_size = unpack('2I', args.boot_img.read(2 * 4))[1]
+    print('dtb size: %s' % dtb_size)
+    dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+    print('dtb address: %#x' % dtb_load_address)
 
-        if self.header_version > 3:
-            args.extend(['--vendor_bootconfig',
-                         os.path.join(self.image_dir, 'bootconfig')])
+    ramdisk_size = kernel_ramdisk_info[4]
+    page_size = kernel_ramdisk_info[1]
 
-            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:
-            args.extend(['--vendor_ramdisk',
-                         os.path.join(self.image_dir, 'vendor_ramdisk')])
-
-        return args
-
-
-def unpack_vendor_boot_image(args):
-    info = VendorBootImageInfoFormatter()
-    info.boot_magic = unpack('8s', args.boot_img.read(8))[0].decode()
-    info.header_version = unpack('I', args.boot_img.read(4))[0]
-    info.page_size = unpack('I', args.boot_img.read(4))[0]
-    info.kernel_load_address = unpack('I', args.boot_img.read(4))[0]
-    info.ramdisk_load_address = unpack('I', args.boot_img.read(4))[0]
-    info.vendor_ramdisk_size = unpack('I', args.boot_img.read(4))[0]
-    info.cmdline = cstr(unpack('2048s', args.boot_img.read(2048))[0].decode())
-    info.tags_load_address = unpack('I', args.boot_img.read(4))[0]
-    info.product_name = cstr(unpack('16s', args.boot_img.read(16))[0].decode())
-    info.header_size = unpack('I', args.boot_img.read(4))[0]
-    info.dtb_size = unpack('I', args.boot_img.read(4))[0]
-    info.dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
-
-    # Convenient shorthand.
-    page_size = info.page_size
     # The first pages contain the boot header
-    num_boot_header_pages = get_number_of_pages(info.header_size, page_size)
-    num_boot_ramdisk_pages = get_number_of_pages(
-        info.vendor_ramdisk_size, page_size)
-    num_boot_dtb_pages = get_number_of_pages(info.dtb_size, page_size)
-
-    ramdisk_offset_base = page_size * num_boot_header_pages
-    image_info_list = []
-
-    if info.header_version > 3:
-        info.vendor_ramdisk_table_size = unpack('I', args.boot_img.read(4))[0]
-        vendor_ramdisk_table_entry_num = unpack('I', args.boot_img.read(4))[0]
-        vendor_ramdisk_table_entry_size = unpack('I', args.boot_img.read(4))[0]
-        info.vendor_bootconfig_size = unpack('I', args.boot_img.read(4))[0]
-        num_vendor_ramdisk_table_pages = get_number_of_pages(
-            info.vendor_ramdisk_table_size, page_size)
-        vendor_ramdisk_table_offset = page_size * (
-            num_boot_header_pages + num_boot_ramdisk_pages + num_boot_dtb_pages)
-
-        vendor_ramdisk_table = []
-        vendor_ramdisk_symlinks = []
-        for idx in range(vendor_ramdisk_table_entry_num):
-            entry_offset = vendor_ramdisk_table_offset + (
-                vendor_ramdisk_table_entry_size * idx)
-            args.boot_img.seek(entry_offset)
-            ramdisk_size = unpack('I', args.boot_img.read(4))[0]
-            ramdisk_offset = unpack('I', args.boot_img.read(4))[0]
-            ramdisk_type = unpack('I', args.boot_img.read(4))[0]
-            ramdisk_name = cstr(unpack(
-                f'{VENDOR_RAMDISK_NAME_SIZE}s',
-                args.boot_img.read(VENDOR_RAMDISK_NAME_SIZE))[0].decode())
-            board_id = unpack(
-                f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}I',
-                args.boot_img.read(
-                    4 * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE))
-            output_ramdisk_name = f'vendor_ramdisk{idx:02}'
-
-            image_info_list.append((ramdisk_offset_base + ramdisk_offset,
-                                    ramdisk_size, output_ramdisk_name))
-            vendor_ramdisk_symlinks.append((output_ramdisk_name, ramdisk_name))
-            vendor_ramdisk_table.append(
-                (output_ramdisk_name, ramdisk_size, ramdisk_offset,
-                 ramdisk_type, ramdisk_name, board_id))
-
-        info.vendor_ramdisk_table = vendor_ramdisk_table
-
-        bootconfig_offset = page_size * (num_boot_header_pages
-            + num_boot_ramdisk_pages + num_boot_dtb_pages
-            + num_vendor_ramdisk_table_pages)
-        image_info_list.append((bootconfig_offset, info.vendor_bootconfig_size,
-            'bootconfig'))
-    else:
-        image_info_list.append(
-            (ramdisk_offset_base, info.vendor_ramdisk_size, 'vendor_ramdisk'))
+    num_boot_header_pages = get_number_of_pages(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE, page_size)
+    num_boot_ramdisk_pages = get_number_of_pages(ramdisk_size, page_size)
+    ramdisk_offset = page_size * num_boot_header_pages
+    image_info_list = [(ramdisk_offset, ramdisk_size, 'vendor_ramdisk')]
 
     dtb_offset = page_size * (num_boot_header_pages + num_boot_ramdisk_pages
                              ) # header + vendor_ramdisk
-    image_info_list.append((dtb_offset, info.dtb_size, 'dtb'))
+    image_info_list.append((dtb_offset, dtb_size, 'dtb'))
 
-    create_out_dir(args.out)
-    for offset, size, name in image_info_list:
-        extract_image(offset, size, args.boot_img, os.path.join(args.out, name))
-    info.image_dir = args.out
-
-    if info.header_version > 3:
-        vendor_ramdisk_by_name_dir = os.path.join(
-            args.out, 'vendor-ramdisk-by-name')
-        create_out_dir(vendor_ramdisk_by_name_dir)
-        for src, dst in vendor_ramdisk_symlinks:
-            src_pathname = os.path.join('..', src)
-            dst_pathname = os.path.join(
-                vendor_ramdisk_by_name_dir, f'ramdisk_{dst}')
-            if os.path.lexists(dst_pathname):
-                os.remove(dst_pathname)
-            os.symlink(src_pathname, dst_pathname)
-
-    return info
+    for image_info in image_info_list:
+        extract_image(image_info[0], image_info[1], args.boot_img,
+                      os.path.join(args.out, image_info[2]))
 
 
 def unpack_image(args):
     boot_magic = unpack('8s', args.boot_img.read(8))[0].decode()
-    args.boot_img.seek(0)
-    if boot_magic == 'ANDROID!':
-        info = unpack_boot_image(args)
-    elif boot_magic == 'VNDRBOOT':
-        info = unpack_vendor_boot_image(args)
-    else:
-        raise ValueError(f'Not an Android boot image, magic: {boot_magic}')
-
-    if args.format == 'mkbootimg':
-        mkbootimg_args = info.format_mkbootimg_argument()
-        if args.null:
-            print('\0'.join(mkbootimg_args) + '\0', end='')
-        else:
-            print(shlex.join(mkbootimg_args))
-    else:
-        print(info.format_pretty_text())
-
-
-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
-"""
+    print('boot_magic: %s' % boot_magic)
+    if boot_magic == "ANDROID!":
+        unpack_bootimage(args)
+    elif boot_magic == "VNDRBOOT":
+        unpack_vendor_bootimage(args)
 
 
 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')
+        description='Unpacks boot.img/recovery.img, extracts the kernel,'
+        'ramdisk, second bootloader, recovery dtbo and dtb')
+    parser.add_argument(
+        '--boot_img',
+        help='path to boot image',
+        type=FileType('rb'),
+        required=True)
+    parser.add_argument('--out', help='path to out binaries', default='out')
     return parser.parse_args()
 
 
 def main():
     """parse arguments and unpack boot image"""
     args = parse_cmdline()
+    create_out_dir(args.out)
     unpack_image(args)