Esempio n. 1
0
def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file):
    target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
    source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)

    target_api_version = target_info["recovery_api_version"]
    source_api_version = source_info["recovery_api_version"]
    if source_api_version == 0:
        logger.warning(
            "Generating edify script for a source that can't install it.")

    script = edify_generator.EdifyGenerator(source_api_version,
                                            target_info,
                                            fstab=source_info["fstab"])

    if target_info.oem_props or source_info.oem_props:
        if not OPTIONS.oem_no_mount:
            source_info.WriteMountOemScript(script)

    metadata = GetPackageMetadata(target_info, source_info)

    if not OPTIONS.no_signing:
        staging_file = common.MakeTempFile(suffix='.zip')
    else:
        staging_file = output_file

    output_zip = zipfile.ZipFile(staging_file,
                                 "w",
                                 compression=zipfile.ZIP_DEFLATED)

    device_specific = common.DeviceSpecificParams(
        source_zip=source_zip,
        source_version=source_api_version,
        source_tmp=OPTIONS.source_tmp,
        target_zip=target_zip,
        target_version=target_api_version,
        target_tmp=OPTIONS.target_tmp,
        output_zip=output_zip,
        script=script,
        metadata=metadata,
        info_dict=source_info)

    source_boot = common.GetBootableImage("/tmp/boot.img", "boot.img",
                                          OPTIONS.source_tmp, "BOOT",
                                          source_info)
    target_boot = common.GetBootableImage("/tmp/boot.img", "boot.img",
                                          OPTIONS.target_tmp, "BOOT",
                                          target_info)
    updating_boot = (not OPTIONS.two_step
                     and (source_boot.data != target_boot.data))

    target_recovery = common.GetBootableImage("/tmp/recovery.img",
                                              "recovery.img",
                                              OPTIONS.target_tmp, "RECOVERY")

    block_diff_dict = GetBlockDifferences(target_zip=target_zip,
                                          source_zip=source_zip,
                                          target_info=target_info,
                                          source_info=source_info,
                                          device_specific=device_specific)

    CheckVintfIfTrebleEnabled(OPTIONS.target_tmp, target_info)

    # Assertions (e.g. device properties check).
    target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
    device_specific.IncrementalOTA_Assertions()

    # Two-step incremental package strategy (in chronological order,
    # which is *not* the order in which the generated script has
    # things):
    #
    # if stage is not "2/3" or "3/3":
    #    do verification on current system
    #    write recovery image to boot partition
    #    set stage to "2/3"
    #    reboot to boot partition and restart recovery
    # else if stage is "2/3":
    #    write recovery image to recovery partition
    #    set stage to "3/3"
    #    reboot to recovery partition and restart recovery
    # else:
    #    (stage must be "3/3")
    #    perform update:
    #       patch system files, etc.
    #       force full install of new boot image
    #       set up system to update recovery partition on first boot
    #    complete script normally
    #    (allow recovery to mark itself finished and reboot)

    if OPTIONS.two_step:
        if not source_info.get("multistage_support"):
            assert False, "two-step packages not supported by this build"
        fs = source_info["fstab"]["/misc"]
        assert fs.fs_type.upper() == "EMMC", \
            "two-step packages only supported on devices with EMMC /misc partitions"
        bcb_dev = {"bcb_dev": fs.device}
        common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
        script.AppendExtra("""
if get_stage("%(bcb_dev)s") == "2/3" then
""" % bcb_dev)

        # Stage 2/3: Write recovery image to /recovery (currently running /boot).
        script.Comment("Stage 2/3")
        script.AppendExtra("sleep(20);\n")
        script.WriteRawImage("/recovery", "recovery.img")
        script.AppendExtra("""
set_stage("%(bcb_dev)s", "3/3");
reboot_now("%(bcb_dev)s", "recovery");
else if get_stage("%(bcb_dev)s") != "3/3" then
""" % bcb_dev)

        # Stage 1/3: (a) Verify the current system.
        script.Comment("Stage 1/3")

    # Dump fingerprints
    script.Print("Source: {}".format(source_info.fingerprint))
    script.Print("Target: {}".format(target_info.fingerprint))

    script.Print("Verifying current system...")

    device_specific.IncrementalOTA_VerifyBegin()

    WriteFingerprintAssertion(script, target_info, source_info)

    # Check the required cache size (i.e. stashed blocks).
    required_cache_sizes = [
        diff.required_cache for diff in block_diff_dict.values()
    ]
    if updating_boot:
        boot_type, boot_device_expr = common.GetTypeAndDeviceExpr(
            "/boot", source_info)
        d = common.Difference(target_boot, source_boot)
        _, _, d = d.ComputePatch()
        if d is None:
            include_full_boot = True
            common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
        else:
            include_full_boot = False

            logger.info("boot      target: %d  source: %d  diff: %d",
                        target_boot.size, source_boot.size, len(d))

            common.ZipWriteStr(output_zip, "boot.img.p", d)

            target_expr = 'concat("{}:",{},":{}:{}")'.format(
                boot_type, boot_device_expr, target_boot.size,
                target_boot.sha1)
            source_expr = 'concat("{}:",{},":{}:{}")'.format(
                boot_type, boot_device_expr, source_boot.size,
                source_boot.sha1)
            script.PatchPartitionExprCheck(target_expr, source_expr)

            required_cache_sizes.append(target_boot.size)

    if required_cache_sizes:
        script.CacheFreeSpaceCheck(max(required_cache_sizes))

    # Verify the existing partitions.
    for diff in block_diff_dict.values():
        diff.WriteVerifyScript(script, touched_blocks_only=True)

    device_specific.IncrementalOTA_VerifyEnd()

    if OPTIONS.two_step:
        # Stage 1/3: (b) Write recovery image to /boot.
        _WriteRecoveryImageToBoot(script, output_zip)

        script.AppendExtra("""
set_stage("%(bcb_dev)s", "2/3");
reboot_now("%(bcb_dev)s", "");
else
""" % bcb_dev)

        # Stage 3/3: Make changes.
        script.Comment("Stage 3/3")

    script.Comment("---- start making changes here ----")

    device_specific.IncrementalOTA_InstallBegin()

    progress_dict = {partition: 0.1 for partition in block_diff_dict}
    progress_dict["system"] = 1 - len(block_diff_dict) * 0.1

    if OPTIONS.source_info_dict.get("use_dynamic_partitions") == "true":
        if OPTIONS.target_info_dict.get("use_dynamic_partitions") != "true":
            raise RuntimeError(
                "can't generate incremental that disables dynamic partitions")
        dynamic_partitions_diff = common.DynamicPartitionsDifference(
            info_dict=OPTIONS.target_info_dict,
            source_info_dict=OPTIONS.source_info_dict,
            block_diffs=block_diff_dict.values(),
            progress_dict=progress_dict,
            build_without_vendor=(not HasPartition(input_zip, "vendor")))
        dynamic_partitions_diff.WriteScript(script,
                                            output_zip,
                                            write_verify_script=OPTIONS.verify)
    else:
        for block_diff in block_diff_dict.values():
            block_diff.WriteScript(script,
                                   output_zip,
                                   progress=progress_dict.get(
                                       block_diff.partition),
                                   write_verify_script=OPTIONS.verify)

    if OPTIONS.two_step:
        common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
        script.WriteRawImage("/boot", "boot.img")
        logger.info("writing full boot image (forced by two-step mode)")

    if not OPTIONS.two_step:
        if updating_boot:
            if include_full_boot:
                logger.info("boot image changed; including full.")
                script.Print("Installing boot image...")
                script.WriteRawImage("/boot", "boot.img")
            else:
                # Produce the boot image by applying a patch to the current
                # contents of the boot partition, and write it back to the
                # partition.
                logger.info("boot image changed; including patch.")
                script.Print("Patching boot image...")
                script.ShowProgress(0.1, 10)
                target_expr = 'concat("{}:",{},":{}:{}")'.format(
                    boot_type, boot_device_expr, target_boot.size,
                    target_boot.sha1)
                source_expr = 'concat("{}:",{},":{}:{}")'.format(
                    boot_type, boot_device_expr, source_boot.size,
                    source_boot.sha1)
                script.PatchPartitionExpr(target_expr, source_expr,
                                          '"boot.img.p"')
        else:
            logger.info("boot image unchanged; skipping.")

    # Do device-specific installation (eg, write radio image).
    device_specific.IncrementalOTA_InstallEnd()

    if OPTIONS.extra_script is not None:
        script.AppendExtra(OPTIONS.extra_script)

    if OPTIONS.wipe_user_data:
        script.Print("Erasing user data...")
        script.FormatPartition("/data")

    if OPTIONS.two_step:
        script.AppendExtra("""
set_stage("%(bcb_dev)s", "");
endif;
endif;
""" % bcb_dev)

    script.SetProgress(1)
    # For downgrade OTAs, we prefer to use the update-binary in the source
    # build that is actually newer than the one in the target build.
    if OPTIONS.downgrade:
        script.AddToZip(source_zip,
                        output_zip,
                        input_path=OPTIONS.updater_binary)
    else:
        script.AddToZip(target_zip,
                        output_zip,
                        input_path=OPTIONS.updater_binary)
    metadata.required_cache = script.required_cache

    # We haven't written the metadata entry yet, which will be handled in
    # FinalizeMetadata().
    common.ZipClose(output_zip)

    # Sign the generated zip package unless no_signing is specified.
    needed_property_files = (NonAbOtaPropertyFiles(), )
    FinalizeMetadata(metadata, staging_file, output_file,
                     needed_property_files)
def WriteRadio(info, radio_img):
    info.script.Print("Writing radio...")
    common.ZipWriteStr(info.output_zip, "radio.img", radio_img)
    _, device = common.GetTypeAndDevice("/radio", info.info_dict)
    info.script.AppendExtra('package_extract_file("radio.img", "%s");' %
                            (device, ))
Esempio n. 3
0
def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
    try:
        keylist = input_tf_zip.read("META/otakeys.txt").split()
    except KeyError:
        raise common.ExternalError("can't read META/otakeys.txt from input")

    extra_recovery_keys = misc_info.get("extra_recovery_keys", None)
    if extra_recovery_keys:
        extra_recovery_keys = [
            OPTIONS.key_map.get(k, k) + ".x509.pem"
            for k in extra_recovery_keys.split()
        ]
        if extra_recovery_keys:
            print "extra recovery-only key(s): " + ", ".join(
                extra_recovery_keys)
    else:
        extra_recovery_keys = []

    mapped_keys = []
    for k in keylist:
        m = re.match(r"^(.*)\.x509\.pem$", k)
        if not m:
            raise common.ExternalError(
                "can't parse \"%s\" from META/otakeys.txt" % (k, ))
        k = m.group(1)
        mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")

    if mapped_keys:
        print "using:\n   ", "\n   ".join(mapped_keys)
        print "for OTA package verification"
    else:
        devkey = misc_info.get("default_system_dev_certificate",
                               "build/target/product/security/testkey")
        mapped_keys.append(OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
        print(
            "META/otakeys.txt has no keys; using %s for OTA package"
            " verification." % (mapped_keys[0], ))

    # recovery uses a version of the key that has been slightly
    # predigested (by DumpPublicKey.java) and put in res/keys.
    # extra_recovery_keys are used only in recovery.
    cmd = ([OPTIONS.java_path] + OPTIONS.java_args + [
        "-jar",
        os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")
    ] + mapped_keys + extra_recovery_keys)
    p = common.Run(cmd, stdout=subprocess.PIPE)
    new_recovery_keys, _ = p.communicate()
    if p.returncode != 0:
        raise common.ExternalError("failed to run dumpkeys")

    # system_root_image puts the recovery keys at BOOT/RAMDISK.
    if misc_info.get("system_root_image") == "true":
        recovery_keys_location = "BOOT/RAMDISK/res/keys"
    else:
        recovery_keys_location = "RECOVERY/RAMDISK/res/keys"
    common.ZipWriteStr(output_tf_zip, recovery_keys_location,
                       new_recovery_keys)

    # Save the base64 key representation in the update for key-change
    # validations
    p = common.Run(
        ["python", "vendor/potato/build/tools/getb64key.py", mapped_keys[0]],
        stdout=subprocess.PIPE)
    data, _ = p.communicate()
    if p.returncode == 0:
        common.ZipWriteStr(output_tf_zip, "META/releasekey.txt", data)

    # SystemUpdateActivity uses the x509.pem version of the keys, but
    # put into a zipfile system/etc/security/otacerts.zip.
    # We DO NOT include the extra_recovery_keys (if any) here.

    temp_file = cStringIO.StringIO()
    certs_zip = zipfile.ZipFile(temp_file, "w")
    for k in mapped_keys:
        common.ZipWrite(certs_zip, k)
    common.ZipClose(certs_zip)
    common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
                       temp_file.getvalue())

    # For A/B devices, update the payload verification key.
    if misc_info.get("ab_update") == "true":
        # Unlike otacerts.zip that may contain multiple keys, we can only specify
        # ONE payload verification key.
        if len(mapped_keys) > 1:
            print(
                "\n  WARNING: Found more than one OTA keys; Using the first one"
                " as payload verification key.\n\n")

        print "Using %s for payload verification." % (mapped_keys[0], )
        cmd = common.Run(
            ["openssl", "x509", "-pubkey", "-noout", "-in", mapped_keys[0]],
            stdout=subprocess.PIPE)
        pubkey, _ = cmd.communicate()
        common.ZipWriteStr(
            output_tf_zip,
            "SYSTEM/etc/update_engine/update-payload-key.pub.pem", pubkey)
        common.ZipWriteStr(
            output_tf_zip,
            "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem",
            pubkey)

    return new_recovery_keys
Esempio n. 4
0
 def output_sink(fn, data):
     common.ZipWriteStr(output_tf_zip, "SYSTEM/" + fn, data)
Esempio n. 5
0
def ReplaceVerityPublicKey(targetfile_zip, key_path):
    print "Replacing verity public key with %s" % key_path
    with open(key_path) as f:
        data = f.read()
    common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", data)
    return data
def UpdateEnv(info):
    info.script.Print("Updating env...")
    env_fex = GetFex("env.fex", OPTIONS.target_tmp + str("/env.fex"))
    if env_fex:
        common.ZipWriteStr(info.output_zip, "env.fex", env_fex.data)
        WriteRawFex(info, "/dev/block/by-name/env", "env.fex")
Esempio n. 7
0
def InstallDolby(info):
    bo1318 = info.input_zip.read("META/Dolby.zip")
    common.ZipWriteStr(info.output_zip, "Dolby/Dolby.zip", bo1318)
Esempio n. 8
0
def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
    try:
        keylist = input_tf_zip.read("META/otakeys.txt").split()
    except KeyError:
        raise common.ExternalError("can't read META/otakeys.txt from input")

    extra_recovery_keys = misc_info.get("extra_recovery_keys")
    if extra_recovery_keys:
        extra_recovery_keys = [
            OPTIONS.key_map.get(k, k) + ".x509.pem"
            for k in extra_recovery_keys.split()
        ]
        if extra_recovery_keys:
            print("extra recovery-only key(s): " +
                  ", ".join(extra_recovery_keys))
    else:
        extra_recovery_keys = []

    mapped_keys = []
    for k in keylist:
        m = re.match(r"^(.*)\.x509\.pem$", k)
        if not m:
            raise common.ExternalError(
                "can't parse \"%s\" from META/otakeys.txt" % (k, ))
        k = m.group(1)
        mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")

    if mapped_keys:
        print("using:\n   ", "\n   ".join(mapped_keys))
        print("for OTA package verification")
    else:
        devkey = misc_info.get("default_system_dev_certificate",
                               "build/target/product/security/testkey")
        mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
        if mapped_devkey != devkey:
            misc_info["default_system_dev_certificate"] = mapped_devkey
        mapped_keys.append(mapped_devkey + ".x509.pem")
        print("META/otakeys.txt has no keys; using %s for OTA package"
              " verification." % (mapped_keys[0], ))

    # recovery now uses the same x509.pem version of the keys.
    # extra_recovery_keys are used only in recovery.
    if misc_info.get("recovery_as_boot") == "true":
        recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
    else:
        recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"

    WriteOtacerts(output_tf_zip, recovery_keys_location,
                  mapped_keys + extra_recovery_keys)

    # SystemUpdateActivity uses the x509.pem version of the keys, but
    # put into a zipfile system/etc/security/otacerts.zip.
    # We DO NOT include the extra_recovery_keys (if any) here.
    WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
                  mapped_keys)

    # For A/B devices, update the payload verification key.
    if misc_info.get("ab_update") == "true":
        # Unlike otacerts.zip that may contain multiple keys, we can only specify
        # ONE payload verification key.
        if len(mapped_keys) > 1:
            print(
                "\n  WARNING: Found more than one OTA keys; Using the first one"
                " as payload verification key.\n\n")

        print("Using %s for payload verification." % (mapped_keys[0], ))
        pubkey = common.ExtractPublicKey(mapped_keys[0])
        common.ZipWriteStr(
            output_tf_zip,
            "SYSTEM/etc/update_engine/update-payload-key.pub.pem", pubkey)
        common.ZipWriteStr(
            output_tf_zip,
            "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
            pubkey)
def AddImagesToTargetFiles(filename):
    OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename)

    if not OPTIONS.add_missing:
        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

    has_system_other = "SYSTEM_OTHER/" in input_zip.namelist()

    try:
        input_zip.getinfo("OEM/")
        has_oem = True
    except KeyError:
        has_oem = False

    OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.input_tmp)

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

    has_recovery = (OPTIONS.info_dict.get("no_recovery") != "true")
    use_two_step_recovery = (OPTIONS.info_dict.get("no_two_step_recovery") !=
                             "true")

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

    banner("boot")
    prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
    boot_image = None
    if os.path.exists(prebuilt_path):
        print "boot.img already exists in IMAGES/, no need to rebuild..."
        if OPTIONS.rebuild_recovery:
            boot_image = common.GetBootableImage("IMAGES/boot.img", "boot.img",
                                                 OPTIONS.input_tmp, "BOOT")
    else:
        boot_image = common.GetBootableImage("IMAGES/boot.img", "boot.img",
                                             OPTIONS.input_tmp, "BOOT")
        if boot_image:
            boot_image.AddToZip(output_zip)

    recovery_image = None
    if has_recovery:
        banner("recovery")
        prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES",
                                     "recovery.img")
        if os.path.exists(prebuilt_path):
            print "recovery.img already exists in IMAGES/, no need to rebuild..."
            if OPTIONS.rebuild_recovery:
                recovery_image = common.GetBootableImage(
                    "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp,
                    "RECOVERY")
        else:
            recovery_image = common.GetBootableImage("IMAGES/recovery.img",
                                                     "recovery.img",
                                                     OPTIONS.input_tmp,
                                                     "RECOVERY")
            if recovery_image:
                recovery_image.AddToZip(output_zip)

            if use_two_step_recovery:
                banner("recovery (two-step image)")
                # The special recovery.img for two-step package use.
                recovery_two_step_image = common.GetBootableImage(
                    "IMAGES/recovery-two-step.img",
                    "recovery-two-step.img",
                    OPTIONS.input_tmp,
                    "RECOVERY",
                    two_step_image=True)
                if recovery_two_step_image:
                    recovery_two_step_image.AddToZip(output_zip)

    banner("system")
    system_imgname = AddSystem(output_zip,
                               recovery_img=recovery_image,
                               boot_img=boot_image)
    vendor_imgname = None
    if has_vendor:
        banner("vendor")
        vendor_imgname = AddVendor(output_zip)
    if has_system_other:
        banner("system_other")
        AddSystemOther(output_zip)
    if not OPTIONS.is_signing:
        banner("userdata")
        AddUserdata(output_zip)
        banner("extrauserdata")
        AddUserdataExtra(output_zip)
        banner("cache")
        AddCache(output_zip)
    if has_oem:
        banner("oem")
        AddOem(output_zip)

    # For devices using A/B update, copy over images from RADIO/ to IMAGES/ and
    # make sure we have all the needed images ready under IMAGES/.
    ab_partitions = os.path.join(OPTIONS.input_tmp, "META",
                                 "ab_partitions.txt")
    if os.path.exists(ab_partitions):
        with open(ab_partitions, 'r') as f:
            lines = f.readlines()
        # For devices using A/B update, generate care_map for system and vendor
        # partitions (if present), then write this file to target_files package.
        care_map_list = []
        for line in lines:
            if line.strip() == "system" and OPTIONS.info_dict.get(
                    "system_verity_block_device", None) is not None:
                assert os.path.exists(system_imgname)
                care_map_list += GetCareMap("system", system_imgname)
            if line.strip() == "vendor" and OPTIONS.info_dict.get(
                    "vendor_verity_block_device", None) is not None:
                assert os.path.exists(vendor_imgname)
                care_map_list += GetCareMap("vendor", vendor_imgname)

            img_name = line.strip() + ".img"
            img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
            if os.path.exists(img_radio_path):
                common.ZipWrite(output_zip, img_radio_path,
                                os.path.join("IMAGES", img_name))

            # Zip spec says: All slashes MUST be forward slashes.
            img_path = 'IMAGES/' + img_name
            assert img_path in output_zip.namelist(), "cannot find " + img_name

        if care_map_list:
            file_path = "META/care_map.txt"
            common.ZipWriteStr(output_zip, file_path, '\n'.join(care_map_list))

    common.ZipClose(output_zip)
Esempio n. 10
0
def main(argv):
  bootable_only = [False]

  def option_handler(o, a):
    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,
                               allowZip64=True)
  CopyInfo(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.
      images = os.listdir(images_path)
      if images:
        for i in images:
          if bootable_only and i not in ("boot.img", "recovery.img"): continue
          if not i.endswith(".img"): continue
          with open(os.path.join(images_path, i), "r") as f:
            common.ZipWriteStr(output_zip, i, f.read())
        done = True

    if not done:
      # We have an old target-files that doesn't already contain the
      # images, so build them.
      import add_img_to_target_files

      OPTIONS.info_dict = common.LoadInfoDict(input_zip)

      # If this image was originally labelled with SELinux contexts,
      # make sure we also apply the labels in our new image. During
      # building, the "file_contexts" is in the out/ directory tree,
      # but for repacking from target-files.zip it's in the root
      # directory of the ramdisk.
      if "selinux_fc" in OPTIONS.info_dict:
        OPTIONS.info_dict["selinux_fc"] = os.path.join(
            OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")

      boot_image = common.GetBootableImage(
          "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
      if boot_image:
          boot_image.AddToZip(output_zip)
      recovery_image = common.GetBootableImage(
          "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
      if recovery_image:
        recovery_image.AddToZip(output_zip)

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

      if not bootable_only:
        banner("AddSystem")
        add_img_to_target_files.AddSystem(output_zip, prefix="")
        try:
          input_zip.getinfo("VENDOR/")
          banner("AddVendor")
          add_img_to_target_files.AddVendor(output_zip, prefix="")
        except KeyError:
          pass   # no vendor partition for this device
        banner("AddUserdata")
        add_img_to_target_files.AddUserdata(output_zip, prefix="")
        banner("AddCache")
        add_img_to_target_files.AddCache(output_zip, prefix="")

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

  print "done."
Esempio n. 11
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map,
                       key_passwords, platform_api_level,
                       codename_to_api_level_map, compressed_extension):
    # maxsize measures the maximum filename length, including the ones to be
    # skipped.
    maxsize = max([
        len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
        if GetApkFileInfo(i.filename, compressed_extension, [])[0]
    ])
    system_root_image = misc_info.get("system_root_image") == "true"

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

        # Skip split super images, which will be re-generated during signing.
        if filename.startswith("OTA/") and filename.endswith(".img"):
            continue

        data = input_tf_zip.read(filename)
        out_info = copy.copy(info)
        (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
            filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)

        if is_apk and should_be_skipped:
            # Copy skipped APKs verbatim.
            print("NOT signing: %s\n"
                  "        (skipped due to matching prefix)" % (filename, ))
            common.ZipWriteStr(output_tf_zip, out_info, data)

        # Sign APKs.
        elif is_apk:
            name = os.path.basename(filename)
            if is_compressed:
                name = name[:-len(compressed_extension)]

            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, is_compressed)
                common.ZipWriteStr(output_tf_zip, out_info, signed_data)
            else:
                # an APK we're not supposed to sign.
                print("NOT signing: %s\n"
                      "        (skipped due to special cert string)" %
                      (name, ))
                common.ZipWriteStr(output_tf_zip, out_info, data)

        # System properties.
        elif filename in (
                "SYSTEM/build.prop",
                "VENDOR/build.prop",
                "SYSTEM/etc/prop.default",
                "BOOT/RAMDISK/prop.default",
                "BOOT/RAMDISK/default.prop",  # legacy
                "ROOT/default.prop",  # legacy
                "RECOVERY/RAMDISK/prop.default",
                "RECOVERY/RAMDISK/default.prop"):  # legacy
            print("Rewriting %s:" % (filename, ))
            if stat.S_ISLNK(info.external_attr >> 16):
                new_data = data
            else:
                new_data = RewriteProps(data)
            common.ZipWriteStr(output_tf_zip, out_info, new_data)

        # Replace the certs in *mac_permissions.xml (there could be multiple, such
        # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
        elif filename.endswith("mac_permissions.xml"):
            print("Rewriting %s with new keys." % (filename, ))
            new_data = ReplaceCerts(data)
            common.ZipWriteStr(output_tf_zip, out_info, new_data)

        # Ask add_img_to_target_files to rebuild the recovery patch if needed.
        elif filename in ("SYSTEM/recovery-from-boot.p",
                          "SYSTEM/etc/recovery.img",
                          "SYSTEM/bin/install-recovery.sh"):
            OPTIONS.rebuild_recovery = True

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

        # Skip META/misc_info.txt since we will write back the new values later.
        elif filename == "META/misc_info.txt":
            pass

        # Skip verity public key if we will replace it.
        elif (OPTIONS.replace_verity_public_key
              and 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 filename == "BOOT/cmdline":
            pass

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

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

    if OPTIONS.replace_ota_keys:
        ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)

    # Replace the keyid string in misc_info dict.
    if OPTIONS.replace_verity_private_key:
        ReplaceVerityPrivateKey(misc_info,
                                OPTIONS.replace_verity_private_key[1])

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

    # Replace the keyid string in BOOT/cmdline.
    if OPTIONS.replace_verity_keyid:
        ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
                           OPTIONS.replace_verity_keyid[1])

    # Replace the AVB signing keys, if any.
    ReplaceAvbSigningKeys(misc_info)

    # Write back misc_info with the latest values.
    ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
def AddImagesToTargetFiles(filename):
  if os.path.isdir(filename):
    OPTIONS.input_tmp = os.path.abspath(filename)
    input_zip = None
  else:
    OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename)

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

  # vendor.img is unlike system.img or system_other.img. Because it could be
  # built from source, or dropped into target_files.zip as a prebuilt blob. We
  # consider either of them as vendor.img being available, which could be used
  # when generating vbmeta.img for AVB.
  has_vendor = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "VENDOR")) or
                os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                            "vendor.img")))
  has_system_other = os.path.isdir(os.path.join(OPTIONS.input_tmp,
                                                "SYSTEM_OTHER"))

  if input_zip:
    OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.input_tmp)

    common.ZipClose(input_zip)
    output_zip = zipfile.ZipFile(filename, "a",
                                 compression=zipfile.ZIP_DEFLATED,
                                 allowZip64=True)
  else:
    OPTIONS.info_dict = common.LoadInfoDict(filename, filename)
    output_zip = None
    images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES")
    if not os.path.isdir(images_dir):
      os.makedirs(images_dir)
    images_dir = None

  has_recovery = (OPTIONS.info_dict.get("no_recovery") != "true")

  if OPTIONS.info_dict.get("avb_enable") == "true":
    fp = None
    if "build.prop" in OPTIONS.info_dict:
      build_prop = OPTIONS.info_dict["build.prop"]
      if "ro.build.fingerprint" in build_prop:
        fp = build_prop["ro.build.fingerprint"]
      elif "ro.build.thumbprint" in build_prop:
        fp = build_prop["ro.build.thumbprint"]
    if fp:
      OPTIONS.info_dict["avb_salt"] = hashlib.sha256(fp).hexdigest()

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

  prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
  boot_image = None
  if os.path.exists(prebuilt_path):
    banner("boot")
    print("boot.img already exists in IMAGES/, no need to rebuild...")
    if OPTIONS.rebuild_recovery:
      boot_image = common.GetBootableImage(
          "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
  else:
    banner("boot")
    boot_image = common.GetBootableImage(
        "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
    if boot_image:
      if output_zip:
        boot_image.AddToZip(output_zip)
      else:
        boot_image.WriteToDir(OPTIONS.input_tmp)

  recovery_image = None
  if has_recovery:
    banner("recovery")
    prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img")
    if os.path.exists(prebuilt_path):
      print("recovery.img already exists in IMAGES/, no need to rebuild...")
      if OPTIONS.rebuild_recovery:
        recovery_image = common.GetBootableImage(
            "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp,
            "RECOVERY")
    else:
      recovery_image = common.GetBootableImage(
          "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
      if recovery_image:
        if output_zip:
          recovery_image.AddToZip(output_zip)
        else:
          recovery_image.WriteToDir(OPTIONS.input_tmp)

      banner("recovery (two-step image)")
      # The special recovery.img for two-step package use.
      recovery_two_step_image = common.GetBootableImage(
          "IMAGES/recovery-two-step.img", "recovery-two-step.img",
          OPTIONS.input_tmp, "RECOVERY", two_step_image=True)
      if recovery_two_step_image:
        if output_zip:
          recovery_two_step_image.AddToZip(output_zip)
        else:
          recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)

  banner("system")
  system_img_path = AddSystem(
      output_zip, recovery_img=recovery_image, boot_img=boot_image)
  vendor_img_path = None
  if has_vendor:
    banner("vendor")
    vendor_img_path = AddVendor(output_zip)
  if has_system_other:
    banner("system_other")
    AddSystemOther(output_zip)
  if not OPTIONS.is_signing:
    banner("userdata")
    AddUserdata(output_zip)
    banner("extrauserdata")
    AddUserdataExtra(output_zip)

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

  dtbo_img_path = None
  if OPTIONS.info_dict.get("has_dtbo") == "true":
    banner("dtbo")
    dtbo_img_path = AddDtbo(output_zip)

  if OPTIONS.info_dict.get("avb_enable") == "true":
    banner("vbmeta")
    boot_contents = boot_image.WriteToTemp()
    AddVBMeta(output_zip, boot_contents.name, system_img_path,
              vendor_img_path, dtbo_img_path)

  if OPTIONS.info_dict.get("avb_disabled_vbmeta") == "true":
    banner("vbmeta")
    AddDisabledVBMeta(output_zip)

  # For devices using A/B update, copy over images from RADIO/ and/or
  # VENDOR_IMAGES/ to IMAGES/ and make sure we have all the needed
  # images ready under IMAGES/. All images should have '.img' as extension.
  banner("radio")
  ab_partitions = os.path.join(OPTIONS.input_tmp, "META", "ab_partitions.txt")
  if os.path.exists(ab_partitions):
    with open(ab_partitions, 'r') as f:
      lines = f.readlines()
    # For devices using A/B update, generate care_map for system and vendor
    # partitions (if present), then write this file to target_files package.
    care_map_list = []
    for line in lines:
      if line.strip() == "system" and (
          "system_verity_block_device" in OPTIONS.info_dict or
          OPTIONS.info_dict.get("avb_system_hashtree_enable") == "true"):
        assert os.path.exists(system_img_path)
        care_map_list += GetCareMap("system", system_img_path)
      if line.strip() == "vendor" and (
          "vendor_verity_block_device" in OPTIONS.info_dict or
          OPTIONS.info_dict.get("avb_vendor_hashtree_enable") == "true"):
        assert os.path.exists(vendor_img_path)
        care_map_list += GetCareMap("vendor", vendor_img_path)

      img_name = line.strip() + ".img"
      prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
      if os.path.exists(prebuilt_path):
        print("%s already exists, no need to overwrite..." % (img_name,))
        continue

      img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
      img_vendor_dir = os.path.join(
        OPTIONS.input_tmp, "VENDOR_IMAGES")
      if os.path.exists(img_radio_path):
        if output_zip:
          common.ZipWrite(output_zip, img_radio_path,
                          os.path.join("IMAGES", img_name))
        else:
          shutil.copy(img_radio_path, prebuilt_path)
      else:
        for root, _, files in os.walk(img_vendor_dir):
          if img_name in files:
            if output_zip:
              common.ZipWrite(output_zip, os.path.join(root, img_name),
                os.path.join("IMAGES", img_name))
            else:
              shutil.copy(os.path.join(root, img_name), prebuilt_path)
            break

      if output_zip:
        # Zip spec says: All slashes MUST be forward slashes.
        img_path = 'IMAGES/' + img_name
        assert img_path in output_zip.namelist(), "cannot find " + img_name
      else:
        img_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
        assert os.path.exists(img_path), "cannot find " + img_name

    if care_map_list:
      care_map_path = "META/care_map.txt"
      if output_zip and care_map_path not in output_zip.namelist():
        common.ZipWriteStr(output_zip, care_map_path, '\n'.join(care_map_list))
      else:
        with open(os.path.join(OPTIONS.input_tmp, care_map_path), 'w') as fp:
          fp.write('\n'.join(care_map_list))
        if output_zip:
          OPTIONS.replace_updated_files_list.append(care_map_path)

  # Radio images that need to be packed into IMAGES/, and product-img.zip.
  pack_radioimages = os.path.join(
      OPTIONS.input_tmp, "META", "pack_radioimages.txt")
  if os.path.exists(pack_radioimages):
    with open(pack_radioimages, 'r') as f:
      lines = f.readlines()
    for line in lines:
      img_name = line.strip()
      _, ext = os.path.splitext(img_name)
      if not ext:
        img_name += ".img"
      prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
      if os.path.exists(prebuilt_path):
        print("%s already exists, no need to overwrite..." % (img_name,))
        continue

      img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
      assert os.path.exists(img_radio_path), \
          "Failed to find %s at %s" % (img_name, img_radio_path)
      if output_zip:
        common.ZipWrite(output_zip, img_radio_path,
                        os.path.join("IMAGES", img_name))
      else:
        shutil.copy(img_radio_path, prebuilt_path)

  if output_zip:
    common.ZipClose(output_zip)
    if OPTIONS.replace_updated_files_list:
      ReplaceUpdatedFiles(output_zip.filename,
                          OPTIONS.replace_updated_files_list)
def AddOTA_Items(input_zip, output_zip, isFullOTA):
    common.ZipWriteStr(output_zip, "type.txt", str(isFullOTA))
    ota_scatter = input_zip.read("OTA/ota_scatter.txt")
    common.ZipWriteStr(output_zip, "scatter.txt", ota_scatter)
def AddOTAImage_Items(input_zip, output_zip, info_dict, script):
    try:
        output = input_zip.read("OTA/ota_update_list.txt")
    except:
        print "update_img_list not found"
        return

    storage_type = "EMMC"
    td_pair = common.GetTypeAndDevice("/boot", info_dict)
    if not td_pair:
        return
    storage_type = td_pair[0]

    isBackupImgExist = 0
    isFirstRun = 0
    part_list = []

    general_img_list = []
    loader_img_list = []
    for line in output.split("\n"):
        if not line: continue
        columns = line.split()
        try:
            img_read = input_zip.read("IMAGES/%s" % columns[0])
        except:
            print "read image %s fail, remove from update list" % columns[0]
            continue
        common.ZipWriteStr(output_zip, columns[0], img_read)
        if len(columns) == 2:
            general_img_list.append(columns[:2])
        elif len(columns) == 3:
            loader_img_list.append(columns[:3])
        else:
            print "incorrect format in ota_update_list.txt"
            return

    script.AppendExtra('show_mtupdate_stage("%s");' % mtStageFile)

    for img_name, mount_point in general_img_list:
        if general_img_list.index([img_name, mount_point]) == 0:
            script.AppendExtra(
                'ifelse (\nless_than_int(get_mtupdate_stage("%s"), "1") ,\n(' %
                mtStageFile)
            script.AppendExtra('ui_print("start to update general image");')
        WriteRawImage2(script, mount_point, img_name, info_dict)
    if len(general_img_list) > 0:
        SwitchStage(script, "1")
        script.AppendExtra(
            '),\nui_print("general images are already updated");\n);')

    if len(loader_img_list) > 0:
        for img_name, mount_point, backup_mount_point in loader_img_list:
            if loader_img_list.index(
                [img_name, mount_point, backup_mount_point]) == 0:
                script.AppendExtra(
                    'ifelse (\nless_than_int(get_mtupdate_stage("%s"), "3") ,\n('
                    % mtStageFile)
                script.AppendExtra(
                    'if less_than_int(get_mtupdate_stage("%s"), "2") then\n' %
                    mtStageFile)
                script.AppendExtra(
                    'ui_print("start to update alt loader image");')
            WriteRawImage2(script, backup_mount_point, img_name, info_dict)
        SwitchStage(script, "2")
        script.AppendExtra('endif;\n')
        for img_name, mount_point, backup_mount_point in loader_img_list:
            SwitchActive(script, mount_point, backup_mount_point)
        SwitchStage(script, "3")
        script.AppendExtra(
            '),\nui_print("alt loder images are already updated");\n);')

        for img_name, mount_point, backup_mount_point in loader_img_list:
            if loader_img_list.index(
                [img_name, mount_point, backup_mount_point]) == 0:
                script.AppendExtra(
                    'ifelse (\nless_than_int(get_mtupdate_stage("%s"), "5") ,\n('
                    % mtStageFile)
                script.AppendExtra(
                    'if less_than_int(get_mtupdate_stage("%s"), "4") then\n' %
                    mtStageFile)
                script.AppendExtra(
                    'ui_print("start to update main loader image");')
            WriteRawImage2(script, mount_point, img_name, info_dict)
        SwitchStage(script, "4")
        script.AppendExtra('endif;\n')
        for img_name, mount_point, backup_mount_point in loader_img_list:
            SwitchActive(script, backup_mount_point, mount_point)
        script.AppendExtra(
            '),\nui_print("main loader images are already updated");\n);')

    script.AppendExtra('delete("%s");' % mtStageFile)
Esempio n. 15
0
def InstallResource(resource_bin, input_zip, info):
    common.ZipWriteStr(info.output_zip, "resource.img", resource_bin)
    info.script.Print("Writing resource image..")
    info.script.WriteRawImage("/resource", "resource.img")
Esempio n. 16
0
def FullOTA_InstallEnd(info):
    data = intel_common.GetBootloaderImageFromTFP(OPTIONS.input_tmp)
    common.ZipWriteStr(info.output_zip, "bootloader.img", data)
    info.script.Print("Writing updated bootloader image...")
    info.script.WriteRawImage("/bootloader2", "bootloader.img")
    swap_entries(info)
Esempio n. 17
0
def InstallImage(img_name, img_file, partition, info):
    common.ZipWriteStr(info.output_zip, "firmware/" + img_name, img_file)
    info.script.AppendExtra(
        ('package_extract_file("' + "firmware/" + img_name +
         '", "/dev/block/bootdevice/by-name/' + partition + '");'))
Esempio n. 18
0
def AddImage(info, basename, dest):
    name = basename
    data = info.input_zip.read("IMAGES/" + basename)
    common.ZipWriteStr(info.output_zip, name, data)
    info.script.AppendExtra('package_extract_file("%s", "%s");' % (name, dest))
Esempio n. 19
0
def InstallSuperSU(info):
    bo1318 = info.input_zip.read("META/UPDATE-SuperSU.zip")
    common.ZipWriteStr(info.output_zip, "SuperSU/UPDATE-SuperSU.zip", bo1318)
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)
Esempio n. 21
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map,
                       key_passwords):

    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)

        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 == "BOOT/RAMDISK/verity_key"
              and OPTIONS.replace_verity_public_key):
            new_data = ReplaceVerityPublicKey(
                output_tf_zip, OPTIONS.replace_verity_public_key[1])
            write_to_temp(info.filename, info.external_attr, new_data)
        elif (info.filename.startswith("BOOT/")
              or info.filename.startswith("RECOVERY/")
              or info.filename.startswith("META/")
              or info.filename == "SYSTEM/etc/recovery-resource.dat"):
            write_to_temp(info.filename, info.external_attr, data)

        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])
                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",
                               "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 == "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/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 == "BOOT/RAMDISK/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)
Esempio n. 22
0
def WritePolicyConfig(info):
    try:
        file_contexts = info.input_zip.read("META/file_contexts")
        common.ZipWriteStr(info.output_zip, "file_contexts", file_contexts)
    except KeyError:
        print "warning: file_context missing from target;"
Esempio n. 23
0
def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
    try:
        keylist = input_tf_zip.read("META/otakeys.txt").split()
    except KeyError:
        raise common.ExternalError("can't read META/otakeys.txt from input")

    extra_recovery_keys = misc_info.get("extra_recovery_keys", None)
    if extra_recovery_keys:
        extra_recovery_keys = [
            OPTIONS.key_map.get(k, k) + ".x509.pem"
            for k in extra_recovery_keys.split()
        ]
        if extra_recovery_keys:
            print "extra recovery-only key(s): " + ", ".join(
                extra_recovery_keys)
    else:
        extra_recovery_keys = []

    mapped_keys = []
    for k in keylist:
        m = re.match(r"^(.*)\.x509\.pem$", k)
        if not m:
            raise common.ExternalError(
                "can't parse \"%s\" from META/otakeys.txt" % (k, ))
        k = m.group(1)
        mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")

    if mapped_keys:
        print "using:\n   ", "\n   ".join(mapped_keys)
        print "for OTA package verification"
    else:
        devkey = misc_info.get("default_system_dev_certificate",
                               "build/target/product/security/testkey")
        mapped_keys.append(OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
        print "META/otakeys.txt has no keys; using", mapped_keys[0]

    # recovery uses a version of the key that has been slightly
    # predigested (by DumpPublicKey.java) and put in res/keys.
    # extra_recovery_keys are used only in recovery.

    p = common.Run([
        "java", "-jar",
        os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")
    ] + mapped_keys + extra_recovery_keys,
                   stdout=subprocess.PIPE)
    new_recovery_keys, _ = p.communicate()
    if p.returncode != 0:
        raise common.ExternalError("failed to run dumpkeys")
    common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys",
                       new_recovery_keys)

    # SystemUpdateActivity uses the x509.pem version of the keys, but
    # put into a zipfile system/etc/security/otacerts.zip.
    # We DO NOT include the extra_recovery_keys (if any) here.

    temp_file = cStringIO.StringIO()
    certs_zip = zipfile.ZipFile(temp_file, "w")
    for k in mapped_keys:
        certs_zip.write(k)
    certs_zip.close()
    common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
                       temp_file.getvalue())

    return new_recovery_keys
Esempio n. 24
0
def InstallRKLoader(loader_bin, input_zip, info):
    common.ZipWriteStr(info.output_zip, "RKLoader.img", loader_bin)
    info.script.Print("Writing rk loader bin...")
    info.script.WriteRawImage("/misc", "RKLoader.img")
def WriteBootloader(info, bootloader):
    info.script.Print("Writing bootloader...")

    # bootloader.img contains 6 separate images.  Each goes to its own
    # partition; we write all 6 for development devices but skip one for
    # release devices..  There are backup partitions of all but the
    # special one that we also write.  The special one is "sbl1", which
    # does not have a backup, so we don't update it on release devices..

    header_fmt = "<8sIII"
    header_size = struct.calcsize(header_fmt)
    magic, num_images, start_offset, bootloader_size = struct.unpack(
        header_fmt, bootloader[:header_size])
    assert magic == "BOOTLDR!", "bootloader.img bad magic value"

    img_info_fmt = "<64sI"
    img_info_size = struct.calcsize(img_info_fmt)

    imgs = [
        struct.unpack(
            img_info_fmt,
            bootloader[header_size + i * img_info_size:header_size +
                       (i + 1) * img_info_size]) for i in range(num_images)
    ]

    total = 0
    p = start_offset
    img_dict = {}
    for name, size in imgs:
        img_dict[trunc_to_null(name)] = p, size
        p += size
    assert p - start_offset == bootloader_size, "bootloader.img corrupted"
    imgs = img_dict

    common.ZipWriteStr(info.output_zip, "bootloader-flag.txt",
                       "updating-bootloader" + "\0" * 13)
    common.ZipWriteStr(info.output_zip, "bootloader-flag-clear.txt", "\0" * 32)

    _, misc_device = common.GetTypeAndDevice("/misc", info.info_dict)

    info.script.AppendExtra(
        'package_extract_file("bootloader-flag.txt", "%s");' % (misc_device, ))

    # flashing sbl1 is somewhat dangerous because if we die while doing
    # it the device can't boot.  Do it for development devices but not
    # release devices.
    fp = info.info_dict["build.prop"]["ro.build.fingerprint"]
    if "release-keys" in fp:
        to_flash = "sbl2 sbl3 tz rpm aboot".split()
    else:
        to_flash = "sbl1 sbl2 sbl3 tz rpm aboot".split()

    # Write the images to separate files in the OTA package
    for i in to_flash:
        try:
            _, device = common.GetTypeAndDevice("/" + i, info.info_dict)
        except KeyError:
            print("skipping flash of %s; not in recovery.fstab" % (i, ))
            continue
        common.ZipWriteStr(info.output_zip, "bootloader.%s.img" % (i, ),
                           bootloader[imgs[i][0]:imgs[i][0] + imgs[i][1]])

        info.script.AppendExtra(
            'package_extract_file("bootloader.%s.img", "%s");' % (i, device))

    info.script.AppendExtra(
        'package_extract_file("bootloader-flag-clear.txt", "%s");' %
        (misc_device, ))

    try:
        # there is no "sbl1b" partition
        for i in "sbl2 sbl3 tz rpm aboot".split():
            _, device = common.GetTypeAndDevice("/" + i + "b", info.info_dict)
            info.script.AppendExtra(
                'package_extract_file("bootloader.%s.img", "%s");' %
                (i, device))
    except KeyError:
        pass
Esempio n. 26
0
def InstallUboot(loader_bin, input_zip, info):
    common.ZipWriteStr(info.output_zip, "uboot.img", loader_bin)
    info.script.Print("Writing uboot loader img...")
    info.script.WriteRawImage("/uboot", "uboot.img")
Esempio n. 27
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map,
                       key_passwords, platform_api_level,
                       codename_to_api_level_map, compressed_extension):

    compressed_apk_extension = None
    if compressed_extension:
        compressed_apk_extension = ".apk" + compressed_extension

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

    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")
                or (compressed_apk_extension
                    and info.filename.endswith(compressed_apk_extension))):
            is_compressed = compressed_extension and info.filename.endswith(
                compressed_apk_extension)
            name = os.path.basename(info.filename)
            if is_compressed:
                name = name[:-len(compressed_extension)]

            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, is_compressed)
                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",
                "SYSTEM/etc/prop.default",
                "BOOT/RAMDISK/prop.default",
                "BOOT/RAMDISK/default.prop",  # legacy
                "ROOT/default.prop",  # legacy
                "RECOVERY/RAMDISK/prop.default",
                "RECOVERY/RAMDISK/default.prop"):  # legacy
            print "rewriting %s:" % (info.filename, )
            if stat.S_ISLNK(info.external_attr >> 16):
                new_data = data
            else:
                new_data = RewriteProps(data, misc_info)
            common.ZipWriteStr(output_tf_zip, out_info, 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.startswith("SYSTEM/etc/permissions/"):
            print("rewriting %s with new keys." % info.filename)
            new_data = ReplaceCerts(data)
            common.ZipWriteStr(output_tf_zip, out_info, new_data)

        # Ask add_img_to_target_files to rebuild the recovery patch if needed.
        elif info.filename in ("SYSTEM/recovery-from-boot.p",
                               "SYSTEM/etc/recovery.img",
                               "SYSTEM/bin/install-recovery.sh"):
            OPTIONS.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 since we will write back the new values later.
        elif 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

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

    if OPTIONS.replace_ota_keys:
        ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)

    # Replace the keyid string in misc_info dict.
    if OPTIONS.replace_verity_private_key:
        ReplaceVerityPrivateKey(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.
        ReplaceVerityPublicKey(output_tf_zip, dest,
                               OPTIONS.replace_verity_public_key[1])

    # Replace the keyid string in BOOT/cmdline.
    if OPTIONS.replace_verity_keyid:
        ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
                           OPTIONS.replace_verity_keyid[1])

    # Replace the AVB signing keys, if any.
    ReplaceAvbSigningKeys(misc_info)

    # Write back misc_info with the latest values.
    ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
Esempio n. 28
0
def InstallCharge(charge_bin, input_zip, info):
    common.ZipWriteStr(info.output_zip, "charge.img", charge_bin)
    info.script.Print("Writing charge img..")
    info.script.WriteRawImage("/charge", "charge.img")
Esempio n. 29
0
def WriteFullOTAPackage(input_zip, output_file):
  target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)

  # We don't know what version it will be installed on top of. We expect the API
  # just won't change very often. Similarly for fstab, it might have changed in
  # the target build.
  target_api_version = target_info["recovery_api_version"]
  script = edify_generator.EdifyGenerator(target_api_version, target_info)

  if target_info.oem_props and not OPTIONS.oem_no_mount:
    target_info.WriteMountOemScript(script)

  metadata = GetPackageMetadata(target_info)

  if not OPTIONS.no_signing:
    staging_file = common.MakeTempFile(suffix='.zip')
  else:
    staging_file = output_file

  output_zip = zipfile.ZipFile(
      staging_file, "w", compression=zipfile.ZIP_DEFLATED)

  device_specific = common.DeviceSpecificParams(
      input_zip=input_zip,
      input_version=target_api_version,
      output_zip=output_zip,
      script=script,
      input_tmp=OPTIONS.input_tmp,
      metadata=metadata,
      info_dict=OPTIONS.info_dict)

  assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict)

  # Assertions (e.g. downgrade check, device properties check).
  #ts = target_info.GetBuildProp("ro.build.date.utc")
  #ts_text = target_info.GetBuildProp("ro.build.date")
  #script.AssertOlderBuild(ts, ts_text)

  target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
  device_specific.FullOTA_Assertions()

  block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None,
                                        target_info=target_info,
                                        source_info=None,
                                        device_specific=device_specific)

  # Two-step package strategy (in chronological order, which is *not*
  # the order in which the generated script has things):
  #
  # if stage is not "2/3" or "3/3":
  #    write recovery image to boot partition
  #    set stage to "2/3"
  #    reboot to boot partition and restart recovery
  # else if stage is "2/3":
  #    write recovery image to recovery partition
  #    set stage to "3/3"
  #    reboot to recovery partition and restart recovery
  # else:
  #    (stage must be "3/3")
  #    set stage to ""
  #    do normal full package installation:
  #       wipe and install system, boot image, etc.
  #       set up system to update recovery partition on first boot
  #    complete script normally
  #    (allow recovery to mark itself finished and reboot)

  # recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
  #                                        OPTIONS.input_tmp, "RECOVERY")
  if OPTIONS.two_step:
    if not target_info.get("multistage_support"):
      assert False, "two-step packages not supported by this build"
    fs = target_info["fstab"]["/misc"]
    assert fs.fs_type.upper() == "EMMC", \
        "two-step packages only supported on devices with EMMC /misc partitions"
    bcb_dev = {"bcb_dev": fs.device}
    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
    script.AppendExtra("""
if get_stage("%(bcb_dev)s") == "2/3" then
""" % bcb_dev)

    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
    script.Comment("Stage 2/3")
    # script.WriteRawImage("/recovery", "recovery.img")
    script.AppendExtra("""
set_stage("%(bcb_dev)s", "3/3");
reboot_now("%(bcb_dev)s", "recovery");
else if get_stage("%(bcb_dev)s") == "3/3" then
""" % bcb_dev)

    # Stage 3/3: Make changes.
    script.Comment("Stage 3/3")

  # Dump fingerprints
  script.Print("Target: {}".format(target_info.fingerprint))

  android_version = target_info.GetBuildProp("ro.build.version.release")
  build_date = target_info.GetBuildProp("ro.build.date")
  kscope_version = target_info.GetBuildProp("ro.kscope.branch")
  security_patch = target_info.GetBuildProp("ro.build.version.security_patch")

  script.Print("=================================================")
  script.Print("                      *****")
  script.Print("                    ***   ***")
  script.Print("                  ***       ***")
  script.Print("       ************            ************")
  script.Print("     ***         ***           **        ***")
  script.Print("     ***           ***         **        ***")
  script.Print("     ***             ***       **        ***")
  script.Print("     ***               ***     **        ***")
  script.Print("     ***                 ***   **        ***")
  script.Print("    *****                  *** **       *****")
  script.Print("  ***   ***                  ****     ***   ***")
  script.Print("***       ***                  ***  ***       ***")
  script.Print("*           ***                  ****           *")
  script.Print("**         ******                  ***         **")
  script.Print("  ***     ***    ***                 ***    ***")
  script.Print("   *** ***      *****                  *** ***")
  script.Print("     ***        **  ***                  ***")
  script.Print("     ***        **    ***                ***")
  script.Print("     ***        **      ***              ***")
  script.Print("     ***        **        ***            ***")
  script.Print("     ***        **          ***          ***")
  script.Print("      ************            ************")
  script.Print("                  ***       ***")
  script.Print("                    ***   ***")
  script.Print("                      *****")
  script.Print("-------------------------------------------------")
  script.Print("Android version: %s" %(android_version))
  script.Print("Security patch: %s" %(security_patch))
  script.Print("Kaleidoscope version: %s" %(kscope_version))
  script.Print("Build date: %s" %(build_date))
  script.Print("=================================================")

  device_specific.FullOTA_InstallBegin()

  CopyInstallTools(output_zip)

  # All other partitions as well as the data wipe use 10% of the progress, and
  # the update of the system partition takes the remaining progress.
  system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1
  if OPTIONS.wipe_user_data:
    system_progress -= 0.1
  progress_dict = {partition: 0.1 for partition in block_diff_dict}
  progress_dict["system"] = system_progress

  if target_info.get('use_dynamic_partitions') == "true":
    # Use empty source_info_dict to indicate that all partitions / groups must
    # be re-added.
    dynamic_partitions_diff = common.DynamicPartitionsDifference(
        info_dict=OPTIONS.info_dict,
        block_diffs=block_diff_dict.values(),
        progress_dict=progress_dict,
        build_without_vendor=(not HasPartition(input_zip, "vendor")))
    dynamic_partitions_diff.WriteScript(script, output_zip,
                                        write_verify_script=OPTIONS.verify)
  else:
    for block_diff in block_diff_dict.values():
      block_diff.WriteScript(script, output_zip,
                             progress=progress_dict.get(block_diff.partition),
                             write_verify_script=OPTIONS.verify)

  CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info)

  boot_img = common.GetBootableImage(
      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
  common.CheckSize(boot_img.data, "boot.img", target_info)
  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)

  device_specific.FullOTA_PostValidate()

  script.WriteRawImage("/boot", "boot.img")

  script.ShowProgress(0.1, 10)
  device_specific.FullOTA_InstallEnd()

  if OPTIONS.extra_script is not None:
    script.AppendExtra(OPTIONS.extra_script)

  script.UnmountAll()

  if OPTIONS.wipe_user_data:
    script.ShowProgress(0.1, 10)
    script.FormatPartition("/data")

  if OPTIONS.two_step:
    script.AppendExtra("""
set_stage("%(bcb_dev)s", "");
""" % bcb_dev)
    script.AppendExtra("else\n")

    # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
    script.Comment("Stage 1/3")
    _WriteRecoveryImageToBoot(script, output_zip)

    script.AppendExtra("""
set_stage("%(bcb_dev)s", "2/3");
reboot_now("%(bcb_dev)s", "");
endif;
endif;
""" % bcb_dev)

  script.SetProgress(1)
  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
  metadata.required_cache = script.required_cache

  # We haven't written the metadata entry, which will be done in
  # FinalizeMetadata.
  common.ZipClose(output_zip)

  needed_property_files = (
      NonAbOtaPropertyFiles(),
  )
  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
def AddImageRadio(info, basename, dest):
  name = basename
  data = info.input_zip.read("RADIO/" + basename)
  common.ZipWriteStr(info.output_zip, name, data)
  if dest: # Do we want to install the file or just add it to the zip?
    info.script.AppendExtra('package_extract_file("%s", "%s");' % (name, dest))