示例#1
0
    def test_recovery_from_boot(self):
        recovery_image = common.File("recovery.img", self.recovery_data)
        self._out_tmp_sink("recovery.img", recovery_image.data, "IMAGES")
        boot_image = common.File("boot.img", self.boot_data)
        self._out_tmp_sink("boot.img", boot_image.data, "IMAGES")

        common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
                                 recovery_image, boot_image, self._info)
        validate_target_files.ValidateInstallRecoveryScript(
            self._tempdir, self._info)
        # Validate 'recovery-from-boot' with bonus argument.
        self._out_tmp_sink("etc/recovery-resource.dat", "bonus", "SYSTEM")
        common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
                                 recovery_image, boot_image, self._info)
        validate_target_files.ValidateInstallRecoveryScript(
            self._tempdir, self._info)
def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None):
    """Turn the contents of SYSTEM into a system image and store it in
  output_zip. Returns the name of the system image file."""

    img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "system.img")
    if os.path.exists(img.input_name):
        print("system.img already exists in %s, no need to rebuild..." %
              (prefix, ))
        return img.input_name

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w")
        ofile.write(data)
        ofile.close()

    if OPTIONS.rebuild_recovery:
        print("Building new recovery patch")
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = OutputFile(output_zip, OPTIONS.input_tmp, prefix,
                            "system.map")
    CreateImage(OPTIONS.input_tmp,
                OPTIONS.info_dict,
                "system",
                img,
                block_list=block_list)

    return img.name
def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None):
    """Turn the contents of SYSTEM into a system image and store it in
  output_zip."""

    prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "system.img")
    if os.path.exists(prebuilt_path):
        print "system.img already exists in %s, no need to rebuild..." % (
            prefix, )
        return

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w")
        ofile.write(data)
        ofile.close()

    if OPTIONS.rebuild_recovery:
        print "Building new recovery patch"
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
    imgname = BuildSystem(OPTIONS.input_tmp,
                          OPTIONS.info_dict,
                          block_list=block_list)
    common.ZipWrite(output_zip, imgname, prefix + "system.img")
    common.ZipWrite(output_zip, block_list, prefix + "system.map")
示例#4
0
    def test_full_recovery(self):
        recovery_image = common.File("recovery.img", self.recovery_data)
        boot_image = common.File("boot.img", self.boot_data)
        self._info["full_recovery_image"] = "true"

        common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
                                 recovery_image, boot_image, self._info)
        validate_target_files.ValidateInstallRecoveryScript(
            self._tempdir, self._info)
def AddVendor(output_zip, recovery_img=None, boot_img=None):
    """Turn the contents of VENDOR into a vendor image and store in it
  output_zip."""

    img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.img")
    if os.path.exists(img.name):
        logger.info("vendor.img already exists; no need to rebuild...")

        # AVB-sign the image as needed.
        if OPTIONS.info_dict.get("avb_enable") == "true":
            logger.info("updating avb hash for prebuilt vendor.img...")
            avbtool = OPTIONS.info_dict["avb_avbtool"]
            # The AVB hash footer will be replaced if already present.
            cmd = [
                avbtool, "add_hashtree_footer", "--image", img.name,
                "--partition_name", "vendor"
            ]
            common.AppendAVBSigningArgs(cmd, "vendor")
            args = OPTIONS.info_dict.get("avb_vendor_add_hash_footer_args")
            if args and args.strip():
                cmd.extend(shlex.split(args))
            common.RunAndCheckOutput(cmd)

        return img.name

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "VENDOR", fn), "w")
        ofile.write(data)
        ofile.close()

        if output_zip:
            arc_name = "VENDOR/" + fn
            if arc_name in output_zip.namelist():
                OPTIONS.replace_updated_files_list.append(arc_name)
            else:
                common.ZipWrite(output_zip, ofile.name, arc_name)

    board_uses_vendorimage = OPTIONS.info_dict.get(
        "board_uses_vendorimage") == "true"

    if (OPTIONS.rebuild_recovery and board_uses_vendorimage
            and recovery_img is not None and boot_img is not None):
        logger.info("Building new recovery patch on vendor")
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
                            "vendor.map")
    CreateImage(OPTIONS.input_tmp,
                OPTIONS.info_dict,
                "vendor",
                img,
                block_list=block_list)
    return img.name
def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None):
    """Turn the contents of SYSTEM into a system image and store it in
  output_zip. Returns the name of the system image file."""

    prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "system.img")
    if os.path.exists(prebuilt_path):
        print "system.img already exists in %s, no need to rebuild..." % (
            prefix, )
        return prebuilt_path

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w")
        ofile.write(data)
        ofile.close()

    if OPTIONS.rebuild_recovery:
        print "Building new recovery patch"
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
    imgname = BuildSystem(OPTIONS.input_tmp,
                          OPTIONS.info_dict,
                          block_list=block_list)

    # If requested, calculate and add dm-verity integrity hashes and
    # metadata to system.img.
    if OPTIONS.info_dict.get("board_bvb_enable", None) == "true":
        bvbtool = os.getenv('BVBTOOL') or "bvbtool"
        cmd = [bvbtool, "add_image_hashes", "--image", imgname]
        args = OPTIONS.info_dict.get("board_bvb_add_image_hashes_args", None)
        if args and args.strip():
            cmd.extend(shlex.split(args))
        p = common.Run(cmd, stdout=subprocess.PIPE)
        p.communicate()
        assert p.returncode == 0, "bvbtool add_image_hashes of %s image failed" % (
            os.path.basename(OPTIONS.input_tmp), )

    common.ZipWrite(output_zip, imgname, prefix + "system.img")
    common.ZipWrite(output_zip, block_list, prefix + "system.map")
    return imgname
def AddSystem(output_zip, recovery_img=None, boot_img=None):
    """Turn the contents of SYSTEM into a system image and store it in
  output_zip. Returns the name of the system image file."""

    img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system.img")
    if os.path.exists(img.name):
        logger.info("system.img already exists; no need to rebuild...")
        return img.name

    def output_sink(fn, data):
        output_file = os.path.join(OPTIONS.input_tmp, "SYSTEM", fn)
        with open(output_file, "wb") as ofile:
            ofile.write(data)

        if output_zip:
            arc_name = "SYSTEM/" + fn
            if arc_name in output_zip.namelist():
                OPTIONS.replace_updated_files_list.append(arc_name)
            else:
                common.ZipWrite(output_zip, output_file, arc_name)

    board_uses_vendorimage = OPTIONS.info_dict.get(
        "board_uses_vendorimage") == "true"

    if (OPTIONS.rebuild_recovery and not board_uses_vendorimage
            and recovery_img is not None and boot_img is not None):
        logger.info("Building new recovery patch on system at system/vendor")
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
                            "system.map")
    CreateImage(OPTIONS.input_tmp,
                OPTIONS.info_dict,
                "system",
                img,
                block_list=block_list)

    return img.name
示例#8
0
def AddVendor(output_zip, recovery_img=None, boot_img=None):
    """Turn the contents of VENDOR into a vendor image and store in it
  output_zip."""

    img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.img")
    if os.path.exists(img.name):
        logger.info("vendor.img already exists; no need to rebuild...")
        return img.name

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "VENDOR", fn), "w")
        ofile.write(data)
        ofile.close()

        if output_zip:
            arc_name = "VENDOR/" + fn
            if arc_name in output_zip.namelist():
                OPTIONS.replace_updated_files_list.append(arc_name)
            else:
                common.ZipWrite(output_zip, ofile.name, arc_name)

    board_uses_vendorimage = OPTIONS.info_dict.get(
        "board_uses_vendorimage") == "true"

    if (OPTIONS.rebuild_recovery and board_uses_vendorimage
            and recovery_img is not None and boot_img is not None):
        logger.info("Building new recovery patch on vendor")
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
                            "vendor.map")
    CreateImage(OPTIONS.input_tmp,
                OPTIONS.info_dict,
                "vendor",
                img,
                block_list=block_list)
    return img.name
def main(argv):
  # def option_handler(o, a):
  #   return False

  args = common.ParseOptions(argv, __doc__)
  input_dir, output_dir = args

  OPTIONS.info_dict = common.LoadInfoDict(input_dir)

  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
                                         input_dir, "RECOVERY")
  boot_img = common.GetBootableImage("boot.img", "boot.img",
                                     input_dir, "BOOT")

  if not recovery_img or not boot_img:
    sys.exit(0)

  def output_sink(fn, data):
    with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f:
      f.write(data)

  common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img)
def AddSystem(output_zip, recovery_img=None, boot_img=None):
    """Turn the contents of SYSTEM into a system image and store it in
  output_zip. Returns the name of the system image file."""

    img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system.img")
    if os.path.exists(img.name):
        logger.info("system.img already exists; no need to rebuild...")
        return img.name

    def output_sink(fn, data):
        ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w")
        ofile.write(data)
        ofile.close()

        if output_zip:
            arc_name = "SYSTEM/" + fn
            if arc_name in output_zip.namelist():
                OPTIONS.replace_updated_files_list.append(arc_name)
            else:
                common.ZipWrite(output_zip, ofile.name, arc_name)

    if OPTIONS.rebuild_recovery:
        logger.info("Building new recovery patch")
        common.MakeRecoveryPatch(OPTIONS.input_tmp,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=OPTIONS.info_dict)

    block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
                            "system.map")
    CreateImage(OPTIONS.input_tmp,
                OPTIONS.info_dict,
                "system",
                img,
                block_list=block_list)

    return img.name
示例#11
0
def main(argv):
  args = common.ParseOptions(argv, __doc__)
  input_dir, output_dir = args

  common.InitLogging()

  OPTIONS.info_dict = common.LoadInfoDict(input_dir)

  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
                                         input_dir, "RECOVERY")
  boot_img = common.GetBootableImage("boot.img", "boot.img",
                                     input_dir, "BOOT")

  if not recovery_img or not boot_img:
    sys.exit(0)

  board_uses_vendorimage = OPTIONS.info_dict.get(
      "board_uses_vendorimage") == "true"
  board_builds_vendorimage =  OPTIONS.info_dict.get(
      "board_builds_vendorimage") == "true"
  target_files_dir = None

  if board_builds_vendorimage:
    target_files_dir = "VENDOR"
  elif not board_uses_vendorimage:
    target_files_dir = "SYSTEM"

  def output_sink(fn, data):
    if target_files_dir is None:
      return

    with open(os.path.join(output_dir, target_files_dir,
                           *fn.split("/")), "wb") as f:
      f.write(data)

  common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img)
示例#12
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
                       apk_key_map, key_passwords, platform_api_level,
                       codename_to_api_level_map):

  maxsize = max([len(os.path.basename(i.filename))
                 for i in input_tf_zip.infolist()
                 if i.filename.endswith('.apk')])
  rebuild_recovery = False
  system_root_image = misc_info.get("system_root_image") == "true"

  # tmpdir will only be used to regenerate the recovery-from-boot patch.
  tmpdir = tempfile.mkdtemp()
  def write_to_temp(fn, attr, data):
    fn = os.path.join(tmpdir, fn)
    if fn.endswith("/"):
      fn = os.path.join(tmpdir, fn)
      os.mkdir(fn)
    else:
      d = os.path.dirname(fn)
      if d and not os.path.exists(d):
        os.makedirs(d)

      if attr >> 16 == 0xa1ff:
        os.symlink(data, fn)
      else:
        with open(fn, "wb") as f:
          f.write(data)

  for info in input_tf_zip.infolist():
    if info.filename.startswith("IMAGES/"):
      continue

    data = input_tf_zip.read(info.filename)
    out_info = copy.copy(info)

    # Sign APKs.
    if info.filename.endswith(".apk"):
      name = os.path.basename(info.filename)
      key = apk_key_map[name]
      if key not in common.SPECIAL_CERT_STRINGS:
        print "    signing: %-*s (%s)" % (maxsize, name, key)
        signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
            codename_to_api_level_map)
        common.ZipWriteStr(output_tf_zip, out_info, signed_data)
      else:
        # an APK we're not supposed to sign.
        print "NOT signing: %s" % (name,)
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # System properties.
    elif info.filename in ("SYSTEM/build.prop",
                           "VENDOR/build.prop",
                           "BOOT/RAMDISK/default.prop",
                           "ROOT/default.prop",
                           "RECOVERY/RAMDISK/default.prop"):
      print "rewriting %s:" % (info.filename,)
      new_data = RewriteProps(data, misc_info)
      common.ZipWriteStr(output_tf_zip, out_info, new_data)
      if info.filename in ("BOOT/RAMDISK/default.prop",
                           "ROOT/default.prop",
                           "RECOVERY/RAMDISK/default.prop"):
        write_to_temp(info.filename, info.external_attr, new_data)

    elif info.filename.endswith("mac_permissions.xml"):
      print "rewriting %s with new keys." % (info.filename,)
      new_data = ReplaceCerts(data)
      common.ZipWriteStr(output_tf_zip, out_info, new_data)

    # Trigger a rebuild of the recovery patch if needed.
    elif info.filename in ("SYSTEM/recovery-from-boot.p",
                           "SYSTEM/etc/recovery.img",
                           "SYSTEM/bin/install-recovery.sh"):
      rebuild_recovery = True

    # Don't copy OTA keys if we're replacing them.
    elif (OPTIONS.replace_ota_keys and
          info.filename in (
              "BOOT/RAMDISK/res/keys",
              "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem",
              "RECOVERY/RAMDISK/res/keys",
              "SYSTEM/etc/security/otacerts.zip",
              "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
      pass

    # Skip META/misc_info.txt if we will replace the verity private key later.
    elif (OPTIONS.replace_verity_private_key and
          info.filename == "META/misc_info.txt"):
      pass

    # Skip verity public key if we will replace it.
    elif (OPTIONS.replace_verity_public_key and
          info.filename in ("BOOT/RAMDISK/verity_key",
                            "ROOT/verity_key")):
      pass

    # Skip verity keyid (for system_root_image use) if we will replace it.
    elif (OPTIONS.replace_verity_keyid and
          info.filename == "BOOT/cmdline"):
      pass

    # Skip the care_map as we will regenerate the system/vendor images.
    elif (info.filename == "META/care_map.txt"):
      pass

    # Copy BOOT/, RECOVERY/, META/, ROOT/ to rebuild recovery patch. This case
    # must come AFTER other matching rules.
    elif (info.filename.startswith("BOOT/") or
          info.filename.startswith("RECOVERY/") or
          info.filename.startswith("META/") or
          info.filename.startswith("ROOT/") or
          info.filename == "SYSTEM/etc/recovery-resource.dat"):
      write_to_temp(info.filename, info.external_attr, data)
      common.ZipWriteStr(output_tf_zip, out_info, data)

    # A non-APK file; copy it verbatim.
    else:
      common.ZipWriteStr(output_tf_zip, out_info, data)

  if OPTIONS.replace_ota_keys:
    new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
    if new_recovery_keys:
      if system_root_image:
        recovery_keys_location = "BOOT/RAMDISK/res/keys"
      else:
        recovery_keys_location = "RECOVERY/RAMDISK/res/keys"
      # The "new_recovery_keys" has been already written into the output_tf_zip
      # while calling ReplaceOtaKeys(). We're just putting the same copy to
      # tmpdir in case we need to regenerate the recovery-from-boot patch.
      write_to_temp(recovery_keys_location, 0o755 << 16, new_recovery_keys)

  # Replace the keyid string in META/misc_info.txt.
  if OPTIONS.replace_verity_private_key:
    ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info,
                            OPTIONS.replace_verity_private_key[1])

  if OPTIONS.replace_verity_public_key:
    if system_root_image:
      dest = "ROOT/verity_key"
    else:
      dest = "BOOT/RAMDISK/verity_key"
    # We are replacing the one in boot image only, since the one under
    # recovery won't ever be needed.
    new_data = ReplaceVerityPublicKey(
        output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
    write_to_temp(dest, 0o755 << 16, new_data)

  # Replace the keyid string in BOOT/cmdline.
  if OPTIONS.replace_verity_keyid:
    new_cmdline = ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
      OPTIONS.replace_verity_keyid[1])
    # Writing the new cmdline to tmpdir is redundant as the bootimage
    # gets build in the add_image_to_target_files and rebuild_recovery
    # is not exercised while building the boot image for the A/B
    # path
    write_to_temp("BOOT/cmdline", 0o755 << 16, new_cmdline)

  if rebuild_recovery:
    recovery_img = common.GetBootableImage(
        "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info)
    boot_img = common.GetBootableImage(
        "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info)

    def output_sink(fn, data):
      common.ZipWriteStr(output_tf_zip, "SYSTEM/" + fn, data)

    common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img,
                             info_dict=misc_info)

  shutil.rmtree(tmpdir)
示例#13
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map,
                       key_passwords, platform_api_level,
                       codename_to_api_level_map):

    maxsize = max([
        len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
        if i.filename.endswith('.apk')
    ])
    rebuild_recovery = False

    tmpdir = tempfile.mkdtemp()

    def write_to_temp(fn, attr, data):
        fn = os.path.join(tmpdir, fn)
        if fn.endswith("/"):
            fn = os.path.join(tmpdir, fn)
            os.mkdir(fn)
        else:
            d = os.path.dirname(fn)
            if d and not os.path.exists(d):
                os.makedirs(d)

            if attr >> 16 == 0xa1ff:
                os.symlink(data, fn)
            else:
                with open(fn, "wb") as f:
                    f.write(data)

    for info in input_tf_zip.infolist():
        if info.filename.startswith("IMAGES/"):
            continue

        data = input_tf_zip.read(info.filename)
        out_info = copy.copy(info)

        # Replace keys if requested.
        if (info.filename == "META/misc_info.txt"
                and OPTIONS.replace_verity_private_key):
            ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info,
                                    OPTIONS.replace_verity_private_key[1])
        elif (info.filename in ("BOOT/RAMDISK/verity_key", "BOOT/verity_key")
              and OPTIONS.replace_verity_public_key):
            new_data = ReplaceVerityPublicKey(
                output_tf_zip, info.filename,
                OPTIONS.replace_verity_public_key[1])
            write_to_temp(info.filename, info.external_attr, new_data)
        # Copy BOOT/, RECOVERY/, META/, ROOT/ to rebuild recovery patch.
        elif (info.filename.startswith("BOOT/")
              or info.filename.startswith("RECOVERY/")
              or info.filename.startswith("META/")
              or info.filename.startswith("ROOT/")
              or info.filename == "SYSTEM/etc/recovery-resource.dat"):
            write_to_temp(info.filename, info.external_attr, data)

        # Sign APKs.
        if info.filename.endswith(".apk"):
            name = os.path.basename(info.filename)
            key = apk_key_map[name]
            if key not in common.SPECIAL_CERT_STRINGS:
                print "    signing: %-*s (%s)" % (maxsize, name, key)
                signed_data = SignApk(data, key, key_passwords[key],
                                      platform_api_level,
                                      codename_to_api_level_map)
                common.ZipWriteStr(output_tf_zip, out_info, signed_data)
            else:
                # an APK we're not supposed to sign.
                print "NOT signing: %s" % (name, )
                common.ZipWriteStr(output_tf_zip, out_info, data)
        elif info.filename in ("SYSTEM/build.prop", "VENDOR/build.prop",
                               "BOOT/RAMDISK/default.prop",
                               "RECOVERY/RAMDISK/default.prop"):
            print "rewriting %s:" % (info.filename, )
            new_data = RewriteProps(data, misc_info)
            common.ZipWriteStr(output_tf_zip, out_info, new_data)
            if info.filename in ("BOOT/RAMDISK/default.prop",
                                 "RECOVERY/RAMDISK/default.prop"):
                write_to_temp(info.filename, info.external_attr, new_data)
        elif info.filename.endswith("mac_permissions.xml"):
            print "rewriting %s with new keys." % (info.filename, )
            new_data = ReplaceCerts(data)
            common.ZipWriteStr(output_tf_zip, out_info, new_data)
        elif info.filename in ("SYSTEM/recovery-from-boot.p",
                               "SYSTEM/etc/recovery.img",
                               "SYSTEM/bin/install-recovery.sh"):
            rebuild_recovery = True
        elif (OPTIONS.replace_ota_keys
              and info.filename in ("RECOVERY/RAMDISK/res/keys",
                                    "SYSTEM/etc/security/otacerts.zip")):
            # don't copy these files if we're regenerating them below
            pass
        elif (OPTIONS.replace_verity_private_key
              and info.filename == "META/misc_info.txt"):
            pass
        elif (OPTIONS.replace_verity_public_key and info.filename
              in ("BOOT/RAMDISK/verity_key", "BOOT/verity_key")):
            pass
        else:
            # a non-APK file; copy it verbatim
            common.ZipWriteStr(output_tf_zip, out_info, data)

    if OPTIONS.replace_ota_keys:
        new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip,
                                           misc_info)
        if new_recovery_keys:
            write_to_temp("RECOVERY/RAMDISK/res/keys", 0o755 << 16,
                          new_recovery_keys)

    if rebuild_recovery:
        recovery_img = common.GetBootableImage("recovery.img",
                                               "recovery.img",
                                               tmpdir,
                                               "RECOVERY",
                                               info_dict=misc_info)
        boot_img = common.GetBootableImage("boot.img",
                                           "boot.img",
                                           tmpdir,
                                           "BOOT",
                                           info_dict=misc_info)

        def output_sink(fn, data):
            common.ZipWriteStr(output_tf_zip, "SYSTEM/" + fn, data)

        common.MakeRecoveryPatch(tmpdir,
                                 output_sink,
                                 recovery_img,
                                 boot_img,
                                 info_dict=misc_info)

    shutil.rmtree(tmpdir)
    # Writing the new cmdline to tmpdir is redundant as the bootimage
    # gets build in the add_image_to_target_files and rebuild_recovery
    # is not exercised while building the boot image for the A/B
    # path
    write_to_temp("BOOT/cmdline", 0o755 << 16, new_cmdline)

  if rebuild_recovery:
    recovery_img = common.GetBootableImage(
        "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info)
    boot_img = common.GetBootableImage(
        "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info)

    def output_sink(fn, data):
      common.ZipWriteStr(output_tf_zip, "SYSTEM/" + fn, data)

    common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img,
                             info_dict=misc_info)

  shutil.rmtree(tmpdir)


def ReplaceCerts(data):
  """Given a string of data, replace all occurences of a set
  of X509 certs with a newer set of X509 certs and return
  the updated data string."""
  for old, new in OPTIONS.key_map.iteritems():
    try:
      if OPTIONS.verbose:
        print "    Replacing %s.x509.pem with %s.x509.pem" % (old, new)
      f = open(old + ".x509.pem")
      old_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower()
      f.close()
  """Turn the contents of SYSTEM into a system image and store it in
  output_zip."""

  prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "system.img")
  if os.path.exists(prebuilt_path):
    print("system.img already exists in %s, no need to rebuild..." % prefix)
    return

  def output_sink(fn, data):
    ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w")
    ofile.write(data)
    ofile.close()

  if rebuild_recovery:
    print("Building new recovery patch")
    common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
                             boot_img, info_dict=OPTIONS.info_dict)

  block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
  imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict,
                        block_list=block_list)
  common.ZipWrite(output_zip, imgname, prefix + "system.img")
  common.ZipWrite(output_zip, block_list, prefix + "system.map")


def BuildSystem(input_dir, info_dict, block_list=None):
  """Build the (sparse) system image and return the name of a temp
  file containing it."""
  return CreateImage(input_dir, info_dict, "system", block_list=block_list)


def AddVendor(output_zip, prefix="IMAGES/"):
        except IOError, e:
            print "no such file!"

    OPTIONS.info_dict = LoadInfoDict(input_dir)
    OPTIONS.info_dict["fstab"] = common.LoadRecoveryFSTab(read_helper, 2)
    OPTIONS.secure_boot = OPTIONS.info_dict.get("secure_boot", False)
    OPTIONS.secure_boot_tool = OPTIONS.info_dict.get("secure_boot_tool", None)
    OPTIONS.single_key = OPTIONS.info_dict.get("single_key", True)

    recovery_img = GetBootableImage("IMAGES/recovery.img", "recovery.img",
                                    input_dir)
    boot_img = GetBootableImage("IMAGES/boot.img", "boot.img", input_dir)

    if not recovery_img or not boot_img:
        sys.exit(0)

    def output_sink(fn, data):
        if fn == "etc/install-recovery.sh":
            fn = "bin/install-recovery.sh"
        if data:
            with open(os.path.join(output_dir, "system", *fn.split("/")),
                      "wb") as f:
                f.write(data)

    common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img,
                             OPTIONS.info_dict)


if __name__ == '__main__':
    main(sys.argv[1:])