Example #1
0
def GenerateNonAbOtaPackage(target_file, output_file, source_file=None):
  """Generates a non-A/B OTA package."""
  # Check the loaded info dicts first.
  if OPTIONS.info_dict.get("no_recovery") == "true":
    raise common.ExternalError(
        "--- target build has specified no recovery ---")

  # Non-A/B OTAs rely on /cache partition to store temporary files.
  cache_size = OPTIONS.info_dict.get("cache_size")
  if cache_size is None:
    logger.warning("--- can't determine the cache partition size ---")
  OPTIONS.cache_size = cache_size

  if OPTIONS.extra_script is not None:
    with open(OPTIONS.extra_script) as fp:
      OPTIONS.extra_script = fp.read()

  if OPTIONS.extracted_input is not None:
    OPTIONS.input_tmp = OPTIONS.extracted_input
  else:
    logger.info("unzipping target target-files...")
    OPTIONS.input_tmp = common.UnzipTemp(target_file, UNZIP_PATTERN)
  OPTIONS.target_tmp = OPTIONS.input_tmp

  # If the caller explicitly specified the device-specific extensions path via
  # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it
  # is present in the target target_files. Otherwise, take the path of the file
  # from 'tool_extensions' in the info dict and look for that in the local
  # filesystem, relative to the current directory.
  if OPTIONS.device_specific is None:
    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
    if os.path.exists(from_input):
      logger.info("(using device-specific extensions from target_files)")
      OPTIONS.device_specific = from_input
    else:
      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions")

  if OPTIONS.device_specific is not None:
    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)

  # Generate a full OTA.
  if source_file is None:
    with zipfile.ZipFile(target_file) as input_zip:
      WriteFullOTAPackage(
          input_zip,
          output_file)

  # Generate an incremental OTA.
  else:
    logger.info("unzipping source target-files...")
    OPTIONS.source_tmp = common.UnzipTemp(
        OPTIONS.incremental_source, UNZIP_PATTERN)
    with zipfile.ZipFile(target_file) as input_zip, \
            zipfile.ZipFile(source_file) as source_zip:
      WriteBlockIncrementalOTAPackage(
          input_zip,
          source_zip,
          output_file)
def GetBootloaderImagesfromFls(unpack_dir, variant=None):
    """ Non-EFI bootloaders (example Sofia and its variants), comprise of
    various partitions. The partitions are obtained from get_bootloader_list().
    Extract and return the *LoadMap.bin files from the *.fls files. """

    bootloader_list = get_bootloader_list(unpack_dir)
    if variant:
        provdata_name = os.path.join(unpack_dir, "RADIO",
                                     "provdata_" + variant + ".zip")
    else:
        provdata_name = os.path.join(unpack_dir, "RADIO", "provdata" + ".zip")
    provdata, provdata_zip = common.UnzipTemp(provdata_name)
    additional_data_hash = collections.OrderedDict()
    partition_to_target = get_partition_target_hash(unpack_dir)

    platform_efi, platform_sflte = CheckIfSocEFI(unpack_dir, variant)

    for loader_partition in bootloader_list:
        curr_loader = partition_to_target[loader_partition]
        loader_filepath = os.path.join(provdata, curr_loader)
        extract = tempfile.mkdtemp(prefix=curr_loader)
        common.OPTIONS.tempfiles.append(extract)
        flstool = os.path.join(provdata, "FlsTool")
        cmd = [flstool, "-x", loader_filepath, "-o", extract]
        try:
            p = common.Run(cmd)
        except Exception as exc:
            print "Error: Unable to execute command: {}".format(' '.join(cmd))
            raise exc
        p.communicate()
        assert p.returncode == 0, "FlsTool failed to extract LoadMap.bin"
        if platform_sflte:
            #for psi: it is verfied by bootrom,
            #so no need add secpack header, need bypass;
            #for bootloader: the combinded images in this partition already has secpack
            #so no need add secpack header, need bypass
            if (loader_partition == 'psi') or (loader_partition
                                               == 'bootloader'):
                for current_file in os.listdir(extract):
                    if fnmatch.fnmatch(current_file, '*LoadMap0.bin'):
                        loader_datafile = current_file
            else:
                #generate Merged.secbin with tool binary_merge
                GenerateBootloaderSecbin(extract, variant)
                for current_file in os.listdir(extract):
                    if fnmatch.fnmatch(current_file, 'Merged.secbin'):
                        loader_datafile = current_file
        else:
            for current_file in os.listdir(extract):
                if fnmatch.fnmatch(current_file, '*LoadMap0.bin'):
                    loader_datafile = current_file

        loader_abspath = os.path.join(extract, loader_datafile)
        assert loader_datafile is not None, "Error in extracting the LoadMap.bin"
        loader_file = open(loader_abspath)
        loader_data = loader_file.read()
        additional_data_hash[loader_partition] = loader_data
        loader_file.close()

    return additional_data_hash
def ImgFromTargetFiles(input_file, output_file):
    """Creates an image archive from the input target_files zip.

  Args:
    input_file: Path to the input target_files zip.
    output_file: Output filename.

  Raises:
    ValueError: On invalid input.
  """
    if not zipfile.is_zipfile(input_file):
        raise ValueError("%s is not a valid zipfile" % input_file)

    logger.info("Building image zip from target files zip.")

    # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py.
    # However, common.LoadInfoDict() may read additional files under BOOT/,
    # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip.
    input_tmp = common.UnzipTemp(input_file)

    LoadOptions(input_tmp)
    output_zip = zipfile.ZipFile(output_file,
                                 "w",
                                 compression=zipfile.ZIP_DEFLATED,
                                 allowZip64=not OPTIONS.sparse_userimages)

    try:
        CopyInfo(input_tmp, output_zip)
        CopyUserImages(input_tmp, output_zip)
        WriteSuperImages(input_tmp, output_zip)
    finally:
        logger.info("cleaning up...")
        common.ZipClose(output_zip)
Example #4
0
def main(argv):
    def option_handler():
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="",
                               extra_long_opts=[],
                               extra_option_handler=option_handler)

    if len(args) != 1:
        common.Usage(__doc__)
        sys.exit(1)

    logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s'
    date_format = '%Y/%m/%d %H:%M:%S'
    logging.basicConfig(level=logging.INFO,
                        format=logging_format,
                        datefmt=date_format)

    logging.info("Unzipping the input target_files.zip: %s", args[0])
    input_tmp, input_zip = common.UnzipTemp(args[0])

    ValidateFileConsistency(input_zip, input_tmp)

    info_dict = common.LoadInfoDict(input_tmp)
    ValidateInstallRecoveryScript(input_tmp, info_dict)

    # TODO: Check if the OTA keys have been properly updated (the ones on /system,
    # in recovery image).

    logging.info("Done.")
Example #5
0
  def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
      target_files_zip.write(
          test_utils.construct_sparse_image([(0xCAC2, 16)]),
          arcname='IMAGES/system.img')
      target_files_zip.writestr(
          'IMAGES/system.map',
          '\n'.join([
              '//system/file1 1-5 9-10',
              '//system/file2 11-12',
              '/system/app/file3 13-15']))
      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
      # '/system/file2' has less blocks listed (2) than actual (3).
      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
      # '/system/app/file3' has less blocks listed (3) than actual (4).
      target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))

    tempdir = common.UnzipTemp(target_files)
    with zipfile.ZipFile(target_files, 'r') as input_zip:
      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)

    self.assertFalse(sparse_image.file_map['//system/file1'].extra)
    self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
    self.assertTrue(
        sparse_image.file_map['/system/app/file3'].extra['incomplete'])
Example #6
0
def main(argv):
    def option_handler(o, a):
        if o in ("-I", "--ifwi-directory"):
            OPTIONS.ifwi_directory = a
        elif o in ("-A", "--avb-key"):
            OPTIONS.avb_key = a
            OPTIONS.all_keys.add(a)
        elif o in ("-K", "--oem-key"):
            OPTIONS.oem_key = a
            OPTIONS.all_keys.add(a)
        elif o in ("-V", "--variant"):
            OPTIONS.variant = a
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="I:A:K:V:",
                               extra_long_opts=[
                                   "ifwi-directory=", "avb-key=", "oem-key=",
                                   "variant="
                               ],
                               extra_option_handler=option_handler)

    if len(args) != 2:
        common.Usage(__doc__)
        sys.exit(1)

    output_fastboot_fn = args[1]

    print("Extracting the provdata.zip")
    prov_file = "provdata_" + OPTIONS.variant + ".zip"
    unpack_dir = common.UnzipTemp(args[0])
    input_zip = zipfile.ZipFile(args[0], "r")
    input_provzip = zipfile.ZipFile(
        os.path.join(unpack_dir, "RADIO", prov_file), "r")

    print("Parsing build.prop for target_product")
    d = {}
    try:
        with open(os.path.join(unpack_dir, "SYSTEM", "build.prop")) as f:
            d = common.LoadDictionaryFromLines(f.read().split("\n"))
    except IOError as e:
        if e.errno == errno.ENOENT:
            raise KeyError(f)
    OPTIONS.target_product = d["ro.product.system.name"]

    print("Processing private keys")
    OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    passwords = common.GetKeyPasswords(OPTIONS.all_keys)

    #process the provdata.zip to generate resigned one
    process_provzip(input_provzip, output_fastboot_fn)

    common.ZipClose(input_zip)
    print("Extract done.")
Example #7
0
def MakeVFATFilesystem(root_zip, filename, title="ANDROIDIA", size=0, block_size=None, extra_size=0,
        extra_files=[], zipped=True):
    """Create a VFAT filesystem image with all the files in the provided
    root zipfile. The size of the filesystem, if not provided by the
    caller, will be 101% the size of the containing files"""

    if zipped:
        root = common.UnzipTemp(root_zip)
        root_zip = zipfile.ZipFile(root_zip, "r")
    else:
        root = root_zip

    for fn_src, fn_dest in extra_files:
        fn_dest = os.path.join(root, fn_dest)
        if not os.path.exists(os.path.dirname(fn_dest)):
            os.makedirs(os.path.dirname(fn_dest))
        shutil.copy(fn_src, fn_dest)

    if size == 0:
        for dpath, dnames, fnames in os.walk(root):
            for f in fnames:
                size += os.path.getsize(os.path.join(dpath, f))

        # Add 1% extra space, minimum 32K
        extra = size / 100
        if extra < (32 * 1024):
            extra = 32 * 1024
        size += extra

    size += extra_size

    # Round the size of the disk up to 32K so that total sectors is
    # a multiple of sectors per track (mtools complains otherwise)
    mod = size % (32 * 1024)
    if mod != 0:
        size = size + (32 * 1024) - mod

    # mtools freaks out otherwise
    if os.path.exists(filename):
        os.unlink(filename)

    add_dir_to_path("/sbin")
    cmd = ["mkdosfs"]
    if block_size:
        cmd.extend(["-S", str(block_size)])
    cmd.extend(["-n", title, "-C", filename, str(size / 1024)])
    try:
        p = common.Run(cmd)
    except Exception as exc:
        print("Error: Unable to execute command: {}".format(' '.join(cmd)))
        raise exc
    p.wait()
    assert p.returncode == 0, "mkdosfs failed"
    for f in os.listdir(root):
        in_p = os.path.join(root, f)
        out_p = os.path.relpath(in_p, root)
        PutFatFile(filename, in_p, out_p)
Example #8
0
 def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self):
     target_files = self._test_LoadInfoDict_createTargetFiles(
         self.INFO_DICT_DEFAULT, 'BOOT/RAMDISK/system/etc/recovery.fstab')
     unzipped = common.UnzipTemp(target_files)
     loaded_dict = common.LoadInfoDict(unzipped)
     self.assertEqual(3, loaded_dict['recovery_api_version'])
     self.assertEqual(2, loaded_dict['fstab_version'])
     self.assertIn('/', loaded_dict['fstab'])
     self.assertIn('/system', loaded_dict['fstab'])
def main(argv):
  # This allows modifying the value from inner function.
  bootable_only_array = [False]

  def option_handler(o, _):
    if o in ("-z", "--bootable_zip"):
      bootable_only_array[0] = True
    else:
      return False
    return True

  args = common.ParseOptions(argv, __doc__,
                             extra_opts="z",
                             extra_long_opts=["bootable_zip"],
                             extra_option_handler=option_handler)

  bootable_only = bootable_only_array[0]

  if len(args) != 2:
    common.Usage(__doc__)
    sys.exit(1)

  common.InitLogging()

  target_files = args[0]
  if os.path.isdir(target_files):
    logger.info("Building image zip from extracted target files.")
    OPTIONS.input_tmp = target_files
  elif zipfile.is_zipfile(target_files):
    logger.info("Building image zip from target files zip.")
    OPTIONS.input_tmp = common.UnzipTemp(args[0], ["IMAGES/*", "OTA/*"])
  else:
    raise ValueError("%s is not a valid path." % target_files)

  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
  CopyInfo(output_zip)

  try:
    images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
    # A target-files zip must contain the images since Lollipop.
    assert os.path.exists(images_path)
    for image in sorted(os.listdir(images_path)):
      if bootable_only and image not in ("boot.img", "recovery.img"):
        continue
      if not image.endswith(".img"):
        continue
      if image == "recovery-two-step.img":
        continue
      common.ZipWrite(output_zip, os.path.join(images_path, image), image)

  finally:
    logger.info("cleaning up...")
    common.ZipClose(output_zip)

  logger.info("done.")
Example #10
0
def AddImagesToTargetFiles(filename):
    OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename)

    for n in input_zip.namelist():
        if n.startswith("IMAGES/"):
            print "target_files appears to already contain images."
            sys.exit(1)

    try:
        input_zip.getinfo("VENDOR/")
        has_vendor = True
    except KeyError:
        has_vendor = False

    OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    if "selinux_fc" in OPTIONS.info_dict:
        OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp,
                                                       "BOOT", "RAMDISK",
                                                       "file_contexts")

    input_zip.close()
    output_zip = zipfile.ZipFile(filename,
                                 "a",
                                 compression=zipfile.ZIP_DEFLATED)

    def banner(s):
        print "\n\n++++ " + s + " ++++\n\n"

    banner("boot")
    boot_image = common.GetBootableImage("IMAGES/boot.img", "boot.img",
                                         OPTIONS.input_tmp, "BOOT")
    if boot_image:
        boot_image.AddToZip(output_zip)

    banner("recovery")
    recovery_image = common.GetBootableImage("IMAGES/recovery.img",
                                             "recovery.img", OPTIONS.input_tmp,
                                             "RECOVERY")
    if recovery_image:
        recovery_image.AddToZip(output_zip)

    banner("system")
    AddSystem(output_zip)
    if has_vendor:
        banner("vendor")
        AddVendor(output_zip)
    banner("userdata")
    AddUserdata(output_zip)
    banner("userdata_extra")
    AddUserdataExtra(output_zip)
    banner("cache")
    AddCache(output_zip)

    output_zip.close()
Example #11
0
def main(argv):
    # This allows modifying the value from inner function.
    bootable_only_array = [False]

    def option_handler(o, _):
        if o in ("-z", "--bootable_zip"):
            bootable_only_array[0] = True
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="z",
                               extra_long_opts=["bootable_zip"],
                               extra_option_handler=option_handler)

    OPTIONS.bootable_only = bootable_only_array[0]

    if len(args) != 2:
        common.Usage(__doc__)
        sys.exit(1)

    common.InitLogging()

    target_files = args[0]
    if os.path.isdir(target_files):
        logger.info("Building image zip from extracted target files.")
        OPTIONS.input_tmp = target_files
    elif zipfile.is_zipfile(target_files):
        logger.info("Building image zip from target files zip.")
        # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py.
        # However, common.LoadInfoDict() may read additional files under BOOT/,
        # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip.
        OPTIONS.input_tmp = common.UnzipTemp(target_files)
    else:
        raise ValueError("%s is not a valid path." % target_files)

    LoadOptions(OPTIONS.input_tmp)
    output_zip = zipfile.ZipFile(args[1],
                                 "w",
                                 compression=zipfile.ZIP_DEFLATED,
                                 allowZip64=not OPTIONS.sparse_userimages)

    try:
        CopyInfo(OPTIONS.input_tmp, output_zip)
        CopyUserImages(OPTIONS.input_tmp, output_zip)
        WriteSuperImages(OPTIONS.input_tmp, output_zip)
    finally:
        logger.info("cleaning up...")
        common.ZipClose(output_zip)

    logger.info("done.")
def main(argv):
    bootable_only = [False]
    compression = [zipfile.ZIP_DEFLATED]

    def option_handler(o, _):
        if o in ("-z", "--bootable_zip"):
            bootable_only[0] = True
        elif o in ("-n", "--no_compression"):
            compression[0] = zipfile.ZIP_STORED
        else:
            return False
        return True

    args = common.ParseOptions(
        argv,
        __doc__,
        extra_opts="zn",
        extra_long_opts=["bootable_zip", "no_compression"],
        extra_option_handler=option_handler)

    bootable_only = bootable_only[0]
    compression = compression[0]

    if len(args) != 2:
        common.Usage(__doc__)
        sys.exit(1)

    OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0],
                                                    ["IMAGES/*", "OTA/*"])
    output_zip = zipfile.ZipFile(args[1], "w", compression)
    CopyInfo(output_zip)

    try:
        images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
        # A target-files zip must contain the images since Lollipop.
        assert os.path.exists(images_path)
        for image in sorted(os.listdir(images_path)):
            if bootable_only and image not in ("boot.img", "recovery.img"):
                continue
            if not image.endswith(".img"):
                continue
            if image == "recovery-two-step.img":
                continue
            common.ZipWrite(output_zip, os.path.join(images_path, image),
                            image)

    finally:
        print("cleaning up...")
        common.ZipClose(output_zip)
        shutil.rmtree(OPTIONS.input_tmp)

    print("done.")
Example #13
0
    def LoadZipFile(self, filename):
        # First read the APK certs file to figure out whether there are compressed
        # APKs in the archive. If we do have compressed APKs in the archive, then we
        # must decompress them individually before we perform any analysis.

        # This is the list of wildcards of files we extract from |filename|.
        apk_extensions = ['*.apk']

        self.certmap, compressed_extension = common.ReadApkCerts(
            zipfile.ZipFile(filename, "r"))
        if compressed_extension:
            apk_extensions.append("*.apk" + compressed_extension)

        d, z = common.UnzipTemp(filename, apk_extensions)
        try:
            self.apks = {}
            self.apks_by_basename = {}
            for dirpath, _, filenames in os.walk(d):
                for fn in filenames:
                    # Decompress compressed APKs before we begin processing them.
                    if compressed_extension and fn.endswith(
                            compressed_extension):
                        # First strip the compressed extension from the file.
                        uncompressed_fn = fn[:-len(compressed_extension)]

                        # Decompress the compressed file to the output file.
                        common.Gunzip(os.path.join(dirpath, fn),
                                      os.path.join(dirpath, uncompressed_fn))

                        # Finally, delete the compressed file and use the uncompressed file
                        # for further processing. Note that the deletion is not strictly required,
                        # but is done here to ensure that we're not using too much space in
                        # the temporary directory.
                        os.remove(os.path.join(dirpath, fn))
                        fn = uncompressed_fn

                    if fn.endswith(".apk"):
                        fullname = os.path.join(dirpath, fn)
                        displayname = fullname[len(d) + 1:]
                        apk = APK(fullname, displayname)
                        self.apks[apk.filename] = apk
                        self.apks_by_basename[os.path.basename(
                            apk.filename)] = apk

                        self.max_pkg_len = max(self.max_pkg_len,
                                               len(apk.package))
                        self.max_fn_len = max(self.max_fn_len,
                                              len(apk.filename))
        finally:
            shutil.rmtree(d)

        z.close()
Example #14
0
 def test_LoadInfoDict_repacking(self):
     target_files = self._test_LoadInfoDict_createTargetFiles(
         self.INFO_DICT_DEFAULT, 'BOOT/RAMDISK/system/etc/recovery.fstab')
     unzipped = common.UnzipTemp(target_files)
     loaded_dict = common.LoadInfoDict(unzipped, True)
     self.assertEqual(3, loaded_dict['recovery_api_version'])
     self.assertEqual(2, loaded_dict['fstab_version'])
     self.assertIn('/', loaded_dict['fstab'])
     self.assertIn('/system', loaded_dict['fstab'])
     self.assertEqual(os.path.join(unzipped, 'ROOT'),
                      loaded_dict['root_dir'])
     self.assertEqual(
         os.path.join(unzipped, 'META', 'root_filesystem_config.txt'),
         loaded_dict['root_fs_config'])
def CheckVintfFromTargetFiles(inp, info_dict=None):
    """
  Checks VINTF metadata of a target files zip.

  Args:
    inp: path to the target files archive.
    info_dict: The build-time info dict. If None, it will be loaded from inp.

  Returns:
    True if VINTF check is skipped or compatible, False if incompatible. Raise
    a RuntimeError if any error occurs.
  """
    input_tmp = common.UnzipTemp(inp, GetVintfFileList() + UNZIP_PATTERN)
    return CheckVintfFromExtractedTargetFiles(input_tmp, info_dict)
Example #16
0
    def test_GetSparseImage_missingBlockMapFile(self):
        target_files = common.MakeTempFile(prefix='target_files-',
                                           suffix='.zip')
        with zipfile.ZipFile(target_files, 'w') as target_files_zip:
            target_files_zip.write(test_utils.construct_sparse_image([
                (0xCAC1, 6), (0xCAC3, 3), (0xCAC1, 4)
            ]),
                                   arcname='IMAGES/system.img')
            target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
            target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))

        tempdir = common.UnzipTemp(target_files)
        with zipfile.ZipFile(target_files, 'r') as input_zip:
            self.assertRaises(AssertionError, common.GetSparseImage, 'system',
                              tempdir, input_zip, False)
Example #17
0
def main():
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('target_files',
                        help='the input target_files.zip to be validated')
    parser.add_argument(
        '--verity_key',
        help='the verity public key to verify the bootable images (Verified '
        'Boot 1.0), or the vbmeta image (Verified Boot 2.0, aka AVB), where '
        'applicable')
    for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
        parser.add_argument(
            '--avb_' + partition + '_key_path',
            help='the public or private key in PEM format to verify AVB chained '
            'partition of {}'.format(partition))
    parser.add_argument(
        '--verity_key_mincrypt',
        help='the verity public key in mincrypt format to verify the system '
        'images, if target using Verified Boot 1.0')
    args = parser.parse_args()

    # Unprovided args will have 'None' as the value.
    options = vars(args)

    logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s'
    date_format = '%Y/%m/%d %H:%M:%S'
    logging.basicConfig(level=logging.INFO,
                        format=logging_format,
                        datefmt=date_format)

    logging.info("Unzipping the input target_files.zip: %s", args.target_files)
    input_tmp = common.UnzipTemp(args.target_files)

    info_dict = common.LoadInfoDict(input_tmp)
    with zipfile.ZipFile(args.target_files, 'r', allowZip64=True) as input_zip:
        ValidateFileConsistency(input_zip, input_tmp, info_dict)

    CheckBuildPropDuplicity(input_tmp)

    ValidateInstallRecoveryScript(input_tmp, info_dict)

    ValidateVerifiedBootImages(input_tmp, info_dict, options)

    # TODO: Check if the OTA keys have been properly updated (the ones on /system,
    # in recovery image).

    logging.info("Done.")
Example #18
0
    def test_GetSparseImage_fileNotFound(self):
        target_files = common.MakeTempFile(prefix='target_files-',
                                           suffix='.zip')
        with zipfile.ZipFile(target_files, 'w') as target_files_zip:
            target_files_zip.write(test_utils.construct_sparse_image([(0xCAC2,
                                                                       16)]),
                                   arcname='IMAGES/system.img')
            target_files_zip.writestr(
                'IMAGES/system.map',
                '\n'.join(['//system/file1 1-5 9-10', '//system/file2 11-12']))
            target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))

        tempdir = common.UnzipTemp(target_files)
        with zipfile.ZipFile(target_files, 'r') as input_zip:
            self.assertRaises(AssertionError, common.GetSparseImage, 'system',
                              tempdir, input_zip, False)
def main(argv):
    def option_handler(o, a):
        if o in ("-I", "--ifwi-directory"):
            OPTIONS.ifwi_directory = a
        elif o in ("-A", "--avb-key"):
            OPTIONS.avb_key = a
            OPTIONS.all_keys.add(a)
        elif o in ("-K", "--oem-key"):
            OPTIONS.oem_key = a
            OPTIONS.all_keys.add(a)
        elif o in ("-V", "--variant"):
            OPTIONS.variant = a
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="I:A:K:V:",
                               extra_long_opts=[
                                   "ifwi-directory=", "avb-key=", "oem-key=",
                                   "variant="
                               ],
                               extra_option_handler=option_handler)

    if len(args) != 2:
        common.Usage(__doc__)
        sys.exit(1)

    output_fastboot_fn = args[1]

    print "Extracting the provdata.zip"
    prov_file = "provdata_" + OPTIONS.variant + ".zip"
    unpack_dir = common.UnzipTemp(args[0])
    input_zip = zipfile.ZipFile(args[0], "r")
    input_provzip = zipfile.ZipFile(
        os.path.join(unpack_dir, "RADIO", prov_file), "r")

    print "Parsing build.prop for target_product"
    d = {}
    try:
        with open(os.path.join(unpack_dir, "SYSTEM", "build.prop")) as f:
            d = common.LoadDictionaryFromLines(f.read().split("\n"))
    except IOError, e:
        if e.errno == errno.ENOENT:
            raise KeyError(f)
Example #20
0
def RebuildAndWriteSuperImages(input_file, output_file):
    """Builds and writes super images to the output file."""
    logger.info('Building super image...')

    # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py.
    # However, common.LoadInfoDict() may read additional files under BOOT/,
    # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip.
    input_tmp = common.UnzipTemp(input_file)

    super_file = common.MakeTempFile('super_', '.img')
    BuildSuperImage(input_tmp, super_file)

    logger.info('Writing super.img to archive...')
    with zipfile.ZipFile(output_file,
                         'a',
                         compression=zipfile.ZIP_DEFLATED,
                         allowZip64=True) as output_zip:
        common.ZipWrite(output_zip, super_file, 'super.img')
Example #21
0
    def test_GetSparseImage_sharedBlocks_notAllowed(self):
        """Tests the case of having overlapping blocks but disallowed."""
        target_files = common.MakeTempFile(prefix='target_files-',
                                           suffix='.zip')
        with zipfile.ZipFile(target_files, 'w') as target_files_zip:
            target_files_zip.write(test_utils.construct_sparse_image([(0xCAC2,
                                                                       16)]),
                                   arcname='IMAGES/system.img')
            # Block 10 is shared between two files.
            target_files_zip.writestr(
                'IMAGES/system.map',
                '\n'.join(['/system/file1 1-5 9-10', '/system/file2 10-12']))
            target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
            target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))

        tempdir = common.UnzipTemp(target_files)
        with zipfile.ZipFile(target_files, 'r') as input_zip:
            self.assertRaises(AssertionError, common.GetSparseImage, 'system',
                              tempdir, input_zip, False)
Example #22
0
  def test_GetSparseImage_sharedBlocks_allowed(self):
    """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true."""
    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
      # Construct an image with a care_map of "0-5 9-12".
      target_files_zip.write(
          test_utils.construct_sparse_image([(0xCAC2, 16)]),
          arcname='IMAGES/system.img')
      # Block 10 is shared between two files.
      target_files_zip.writestr(
          'IMAGES/system.map',
          '\n'.join([
              '/system/file1 1-5 9-10',
              '/system/file2 10-12']))
      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))

    tempdir = common.UnzipTemp(target_files)
    with zipfile.ZipFile(target_files, 'r') as input_zip:
      sparse_image = common.GetSparseImage('system', tempdir, input_zip, True)

    self.assertDictEqual(
        {
            '__COPY': RangeSet("0"),
            '__NONZERO-0': RangeSet("6-8 13-15"),
            '/system/file1': RangeSet("1-5 9-10"),
            '/system/file2': RangeSet("11-12"),
        },
        sparse_image.file_map)

    # '/system/file2' should be marked with 'uses_shared_blocks', but not with
    # 'incomplete'.
    self.assertTrue(
        sparse_image.file_map['/system/file2'].extra['uses_shared_blocks'])
    self.assertNotIn(
        'incomplete', sparse_image.file_map['/system/file2'].extra)

    # All other entries should look normal without any tags.
    self.assertFalse(sparse_image.file_map['__COPY'].extra)
    self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
    self.assertFalse(sparse_image.file_map['/system/file1'].extra)
Example #23
0
  def LoadZipFile(self, filename):
    d, z = common.UnzipTemp(filename, ['*.apk'])
    try:
      self.apks = {}
      self.apks_by_basename = {}
      for dirpath, _, filenames in os.walk(d):
        for fn in filenames:
          if fn.endswith(".apk"):
            fullname = os.path.join(dirpath, fn)
            displayname = fullname[len(d)+1:]
            apk = APK(fullname, displayname)
            self.apks[apk.filename] = apk
            self.apks_by_basename[os.path.basename(apk.filename)] = apk

            self.max_pkg_len = max(self.max_pkg_len, len(apk.package))
            self.max_fn_len = max(self.max_fn_len, len(apk.filename))
    finally:
      shutil.rmtree(d)

    self.certmap = common.ReadApkCerts(z)
    z.close()
Example #24
0
def main(argv):
  bootable_only = [False]

  def option_handler(o, _):
    if o in ("-z", "--bootable_zip"):
      bootable_only[0] = True
    else:
      return False
    return True

  args = common.ParseOptions(argv, __doc__,
                             extra_opts="z",
                             extra_long_opts=["bootable_zip"],
                             extra_option_handler=option_handler)

  bootable_only = bootable_only[0]

  if len(args) != 2:
    common.Usage(__doc__)
    sys.exit(1)

  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
  CopyInfo(output_zip)
  AddRadio(output_zip)

  try:
    done = False
    images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
    if os.path.exists(images_path):
      # If this is a new target-files, it already contains the images,
      # and all we have to do is copy them to the output zip.
      # Skip oem.img files since they are not needed in fastboot images.
      images = os.listdir(images_path)
      if images:
        for image in images:
          if bootable_only and image not in ("boot.img", "recovery.img"):
            continue
          if not image.endswith(".img"):
            continue
Example #25
0
  def test_GetSparseImage_incompleteRanges(self):
    """Tests the case of ext4 images with holes."""
    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
      target_files_zip.write(
          test_utils.construct_sparse_image([(0xCAC2, 16)]),
          arcname='IMAGES/system.img')
      target_files_zip.writestr(
          'IMAGES/system.map',
          '\n'.join([
              '/system/file1 1-5 9-10',
              '/system/file2 11-12']))
      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
      # '/system/file2' has less blocks listed (2) than actual (3).
      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))

    tempdir = common.UnzipTemp(target_files)
    with zipfile.ZipFile(target_files, 'r') as input_zip:
      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)

    self.assertFalse(sparse_image.file_map['/system/file1'].extra)
    self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
Example #26
0
    def test_GetSparseImage_emptyBlockMapFile(self):
        target_files = common.MakeTempFile(prefix='target_files-',
                                           suffix='.zip')
        with zipfile.ZipFile(target_files, 'w') as target_files_zip:
            target_files_zip.write(test_utils.construct_sparse_image([
                (0xCAC1, 6), (0xCAC3, 3), (0xCAC1, 4)
            ]),
                                   arcname='IMAGES/system.img')
            target_files_zip.writestr('IMAGES/system.map', '')
            target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
            target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))

        tempdir = common.UnzipTemp(target_files)
        with zipfile.ZipFile(target_files, 'r') as input_zip:
            sparse_image = common.GetSparseImage('system', tempdir, input_zip,
                                                 False)

        self.assertDictEqual(
            {
                '__COPY': RangeSet("0"),
                '__NONZERO-0': RangeSet("1-5 9-12"),
            }, sparse_image.file_map)
def build_fls(unpack_dir, target, variant=None):
    """Build fls flash file out of tfp"""

    sign, target2tag = check_signed_fls(target)
    tag = get_tag(target2tag)
    provdata_zip = 'provdata_%s.zip' % variant if variant else 'provdata.zip'
    provdata_name = os.path.join(unpack_dir, "RADIO", provdata_zip)
    provdata, provdata_zip = common.UnzipTemp(provdata_name)

    target2file = open(os.path.join(provdata, "fftf_build.opt")).read().strip()
    t2f = init_t2f_dict(target2file)
    flstool = os.path.join(provdata, os.path.basename(t2f["FLSTOOL"]))

    prg = os.path.join(provdata, os.path.basename(t2f["INTEL_PRG_FILE"]))
    out = os.path.join(unpack_dir, "IMAGES", target2tag + '.fls')
    infile = os.path.join(unpack_dir, "IMAGES", target2tag + '.img')
    psi, eblsec = get_psi(provdata, t2f)

    run_fls(flstool, prg, out, tag, infile, psi, eblsec)

    if sign:
        script = os.path.join(provdata,
                              os.path.basename(t2f["SYSTEM_FLS_SIGN_SCRIPT"]))
        out_signed = os.path.join(unpack_dir, "IMAGES", target)

        sign_fls(flstool, out, script, out_signed, psi, eblsec)

    try:
        os.makedirs(os.path.join(t2f["FASTBOOT_IMG_DIR"]))
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(
                os.path.join(t2f["FASTBOOT_IMG_DIR"])):
            pass
        else:
            raise

    shutil.copyfile(os.path.join(unpack_dir, "IMAGES", target2tag + '.img'),
                    os.path.join(t2f["FASTBOOT_IMG_DIR"], target2tag + '.bin'))
def GetBootloaderImageFromTFP(unpack_dir, autosize=False, extra_files=None, variant=None, base_variant=None):
    if extra_files == None:
        extra_files = []

    if variant:
        provdata_name = os.path.join(unpack_dir, "RADIO", "provdata_" + variant +".zip")
        if base_variant and (os.path.isfile(provdata_name) == False):
            provdata_name = os.path.join(unpack_dir, "RADIO", "provdata_" + base_variant +".zip")
        provdata, provdata_zip = common.UnzipTemp(provdata_name)
        cap_path = os.path.join(provdata,"capsule.fv")
        if os.path.exists(cap_path):
            extra_files.append((cap_path, "capsules/current.fv"))
            extra_files.append((cap_path, "BIOSUPDATE.fv"))
        else:
            print "No capsule.fv found in provdata_" + variant + ".zip"

    bootloader = tempfile.NamedTemporaryFile(delete=False)
    filename = bootloader.name
    bootloader.close()

    fastboot = GetFastbootImage(unpack_dir)
    if fastboot:
        fastboot_file = fastboot.WriteToTemp()
        extra_files.append((fastboot_file.name,"fastboot.img"))

    if not autosize:
        size = int(open(os.path.join(unpack_dir, "RADIO", "bootloader-size.txt")).read().strip())
    else:
        size = 0
    MakeVFATFilesystem(os.path.join(unpack_dir, "RADIO", "bootloader.zip"),
            filename, size=size, extra_files=extra_files)
    bootloader = open(filename)
    data = bootloader.read()
    bootloader.close()
    os.unlink(filename)
    return data
Example #29
0
def BuildSuperImageFromTargetFiles(inp, out):
    input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN)
    return BuildSuperImageFromExtractedTargetFiles(input_tmp, out)
Example #30
0
def AddImagesToTargetFiles(filename):
    """Creates and adds images (boot/recovery/system/...) to a target_files.zip.

  It works with either a zip file (zip mode), or a directory that contains the
  files to be packed into a target_files.zip (dir mode). The latter is used when
  being called from build/make/core/Makefile.

  The images will be created under IMAGES/ in the input target_files.zip.

  Args:
    filename: the target_files.zip, or the zip root directory.
  """
    if os.path.isdir(filename):
        OPTIONS.input_tmp = os.path.abspath(filename)
    else:
        OPTIONS.input_tmp = common.UnzipTemp(filename)

    if not OPTIONS.add_missing:
        if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")):
            logger.warning("target_files appears to already contain images.")
            sys.exit(1)

    OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True)

    has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
    has_boot = OPTIONS.info_dict.get("no_boot") != "true"
    has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"

    # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system, system_other}.img
    # can be built from source, or  dropped into target_files.zip as a prebuilt blob.
    has_vendor = HasPartition("vendor")
    has_odm = HasPartition("odm")
    has_vendor_dlkm = HasPartition("vendor_dlkm")
    has_odm_dlkm = HasPartition("odm_dlkm")
    has_product = HasPartition("product")
    has_system_ext = HasPartition("system_ext")
    has_system = HasPartition("system")
    has_system_other = HasPartition("system_other")
    has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true"
    has_cache = OPTIONS.info_dict.get("building_cache_image") == "true"

    # Set up the output destination. It writes to the given directory for dir
    # mode; otherwise appends to the given ZIP.
    if os.path.isdir(filename):
        output_zip = None
    else:
        output_zip = zipfile.ZipFile(filename,
                                     "a",
                                     compression=zipfile.ZIP_DEFLATED,
                                     allowZip64=True)

    # Always make input_tmp/IMAGES available, since we may stage boot / recovery
    # images there even under zip mode. The directory will be cleaned up as part
    # of OPTIONS.input_tmp.
    images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES")
    if not os.path.isdir(images_dir):
        os.makedirs(images_dir)

    # A map between partition names and their paths, which could be used when
    # generating AVB vbmeta image.
    partitions = {}

    def banner(s):
        logger.info("\n\n++++ %s  ++++\n\n", s)

    boot_image = None
    if has_boot:
        banner("boot")
        boot_images = OPTIONS.info_dict.get("boot_images")
        if boot_images is None:
            boot_images = "boot.img"
        for index, b in enumerate(boot_images.split()):
            # common.GetBootableImage() returns the image directly if present.
            boot_image = common.GetBootableImage("IMAGES/" + b, b,
                                                 OPTIONS.input_tmp, "BOOT")
            # boot.img may be unavailable in some targets (e.g. aosp_arm64).
            if boot_image:
                boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b)
                # Although multiple boot images can be generated, include the image
                # descriptor of only the first boot image in vbmeta
                if index == 0:
                    partitions['boot'] = boot_image_path
                if not os.path.exists(boot_image_path):
                    boot_image.WriteToDir(OPTIONS.input_tmp)
                    if output_zip:
                        boot_image.AddToZip(output_zip)

    if has_vendor_boot:
        banner("vendor_boot")
        vendor_boot_image = common.GetVendorBootImage("IMAGES/vendor_boot.img",
                                                      "vendor_boot.img",
                                                      OPTIONS.input_tmp,
                                                      "VENDOR_BOOT")
        if vendor_boot_image:
            partitions['vendor_boot'] = os.path.join(OPTIONS.input_tmp,
                                                     "IMAGES",
                                                     "vendor_boot.img")
            if not os.path.exists(partitions['vendor_boot']):
                vendor_boot_image.WriteToDir(OPTIONS.input_tmp)
                if output_zip:
                    vendor_boot_image.AddToZip(output_zip)

    recovery_image = None
    if has_recovery:
        banner("recovery")
        recovery_image = common.GetBootableImage("IMAGES/recovery.img",
                                                 "recovery.img",
                                                 OPTIONS.input_tmp, "RECOVERY")
        assert recovery_image, "Failed to create recovery.img."
        partitions['recovery'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
                                              "recovery.img")
        if not os.path.exists(partitions['recovery']):
            recovery_image.WriteToDir(OPTIONS.input_tmp)
            if output_zip:
                recovery_image.AddToZip(output_zip)

            banner("recovery (two-step image)")
            # The special recovery.img for two-step package use.
            recovery_two_step_image = common.GetBootableImage(
                "OTA/recovery-two-step.img",
                "recovery-two-step.img",
                OPTIONS.input_tmp,
                "RECOVERY",
                two_step_image=True)
            assert recovery_two_step_image, "Failed to create recovery-two-step.img."
            recovery_two_step_image_path = os.path.join(
                OPTIONS.input_tmp, "OTA", "recovery-two-step.img")
            if not os.path.exists(recovery_two_step_image_path):
                recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
                if output_zip:
                    recovery_two_step_image.AddToZip(output_zip)

    if has_system:
        banner("system")
        partitions['system'] = AddSystem(output_zip,
                                         recovery_img=recovery_image,
                                         boot_img=boot_image)

    if has_vendor:
        banner("vendor")
        partitions['vendor'] = AddVendor(output_zip,
                                         recovery_img=recovery_image,
                                         boot_img=boot_image)

    if has_product:
        banner("product")
        partitions['product'] = AddProduct(output_zip)

    if has_system_ext:
        banner("system_ext")
        partitions['system_ext'] = AddSystemExt(output_zip)

    if has_odm:
        banner("odm")
        partitions['odm'] = AddOdm(output_zip)

    if has_vendor_dlkm:
        banner("vendor_dlkm")
        partitions['vendor_dlkm'] = AddVendorDlkm(output_zip)

    if has_odm_dlkm:
        banner("odm_dlkm")
        partitions['odm_dlkm'] = AddOdmDlkm(output_zip)

    if has_system_other:
        banner("system_other")
        AddSystemOther(output_zip)

    AddApexInfo(output_zip)

    if not OPTIONS.is_signing:
        banner("userdata")
        AddUserdata(output_zip)
        banner("cache")
        AddCache(output_zip)

    if OPTIONS.info_dict.get("board_bpt_enable") == "true":
        banner("partition-table")
        AddPartitionTable(output_zip)

    if OPTIONS.info_dict.get("has_dtbo") == "true":
        banner("dtbo")
        partitions['dtbo'] = AddDtbo(output_zip)

    if OPTIONS.info_dict.get("has_pvmfw") == "true":
        banner("pvmfw")
        partitions['pvmfw'] = AddPvmfw(output_zip)

    # Custom images.
    custom_partitions = OPTIONS.info_dict.get(
        "avb_custom_images_partition_list", "").strip().split()
    for partition_name in custom_partitions:
        partition_name = partition_name.strip()
        banner("custom images for " + partition_name)
        partitions[partition_name] = AddCustomImages(output_zip,
                                                     partition_name)

    if OPTIONS.info_dict.get("avb_enable") == "true":
        # vbmeta_partitions includes the partitions that should be included into
        # top-level vbmeta.img, which are the ones that are not included in any
        # chained VBMeta image plus the chained VBMeta images themselves.
        # Currently custom_partitions are all chained to VBMeta image.
        vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)

        vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
        if vbmeta_system:
            banner("vbmeta_system")
            partitions["vbmeta_system"] = AddVBMeta(output_zip, partitions,
                                                    "vbmeta_system",
                                                    vbmeta_system.split())
            vbmeta_partitions = [
                item for item in vbmeta_partitions
                if item not in vbmeta_system.split()
            ]
            vbmeta_partitions.append("vbmeta_system")

        vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
        if vbmeta_vendor:
            banner("vbmeta_vendor")
            partitions["vbmeta_vendor"] = AddVBMeta(output_zip, partitions,
                                                    "vbmeta_vendor",
                                                    vbmeta_vendor.split())
            vbmeta_partitions = [
                item for item in vbmeta_partitions
                if item not in vbmeta_vendor.split()
            ]
            vbmeta_partitions.append("vbmeta_vendor")

        if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
            banner("vbmeta")
            AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)

    if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
        if OPTIONS.info_dict.get("build_super_empty_partition") == "true":
            banner("super_empty")
            AddSuperEmpty(output_zip)

    if OPTIONS.info_dict.get("build_super_partition") == "true":
        if OPTIONS.info_dict.get(
                "build_retrofit_dynamic_partitions_ota_package") == "true":
            banner("super split images")
            AddSuperSplit(output_zip)

    banner("radio")
    ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META",
                                     "ab_partitions.txt")
    if os.path.exists(ab_partitions_txt):
        with open(ab_partitions_txt) as f:
            ab_partitions = f.readlines()

        # For devices using A/B update, make sure we have all the needed images
        # ready under IMAGES/ or RADIO/.
        CheckAbOtaImages(output_zip, ab_partitions)

        # Generate care_map.pb for ab_partitions, then write this file to
        # target_files package.
        output_care_map = os.path.join(OPTIONS.input_tmp, "META",
                                       "care_map.pb")
        AddCareMapForAbOta(output_zip if output_zip else output_care_map,
                           ab_partitions, partitions)

    # Radio images that need to be packed into IMAGES/, and product-img.zip.
    pack_radioimages_txt = os.path.join(OPTIONS.input_tmp, "META",
                                        "pack_radioimages.txt")
    if os.path.exists(pack_radioimages_txt):
        with open(pack_radioimages_txt) as f:
            AddPackRadioImages(output_zip, f.readlines())

    # Calculate the vbmeta digest and put the result in to META/
    boot_images = OPTIONS.info_dict.get("boot_images")
    # Disable the digest calculation if the target_file is used as a container
    # for boot images.
    boot_container = boot_images and len(boot_images.split()) >= 2
    if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container
            and OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"):
        avbtool = OPTIONS.info_dict["avb_avbtool"]
        digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool)
        vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META",
                                         "vbmeta_digest.txt")
        with open(vbmeta_digest_txt, 'w') as f:
            f.write(digest)

    if output_zip:
        common.ZipClose(output_zip)
        if OPTIONS.replace_updated_files_list:
            ReplaceUpdatedFiles(output_zip.filename,
                                OPTIONS.replace_updated_files_list)