Beispiel #1
0
def IncrementalOTA_InstallEnd(info):
    try:
        target_bootloader_img = info.target_zip.read("RADIO/bootloader.img")
        try:
            source_bootloader_img = info.source_zip.read(
                "RADIO/bootloader.img")
        except KeyError:
            source_bootloader_img = None

        if source_bootloader_img == target_bootloader_img:
            print "bootloader unchanged; skipping"
        else:
            common.ZipWriteStr(info.output_zip, "bootloader.img",
                               target_bootloader_img)
            info.script.Print("Writing bootloader...")
            info.script.WriteRawImage("/bootloader", "bootloader.img")

    except KeyError:
        print "no bootloader.img in target target_files; skipping install"

    tf = FindRadio(info.target_zip)
    if not tf:
        # failed to read TARGET radio image: don't include any radio in update.
        print "no radio.img in target target_files; skipping install"
    else:
        tf = common.File("radio.img", tf)

        sf = FindRadio(info.source_zip)
        if not sf:
            # failed to read SOURCE radio image: include the whole target
            # radio image.
            tf.AddToZip(info.output_zip)
            info.script.Print("Writing radio...")
            info.script.WriteRawImage("/radio", tf.name)
        else:
            sf = common.File("radio.img", sf)

            if tf.sha1 == sf.sha1:
                print "radio image unchanged; skipping"
            else:
                diff = common.Difference(tf, sf)
                common.ComputeDifferences([diff])
                _, _, d = diff.GetPatch()
                if d is None or len(
                        d) > tf.size * common.OPTIONS.patch_threshold:
                    # computing difference failed, or difference is nearly as
                    # big as the target:  simply send the target.
                    tf.AddToZip(info.output_zip)
                    info.script.Print("Writing radio...")
                    info.script.WriteRawImage("radio", tf.name)
                else:
                    common.ZipWriteStr(info.output_zip, "radio.img.p", d)
                    info.script.Print("Patching radio...")
                    radio_type, radio_device = common.GetTypeAndDevice(
                        "/radio", info.info_dict)
                    info.script.ApplyPatch(
                        "%s:%s:%d:%s:%d:%s" %
                        (radio_type, radio_device, sf.size, sf.sha1, tf.size,
                         tf.sha1), "-", tf.size, tf.sha1, sf.sha1,
                        "radio.img.p")
  def AddToOutputZip(self, output_zip, **kwargs):
    self.verbatim = kwargs.get("verbatim", self.verbatim)
    if self.update_flag:
      PartitionUpdater.AddToOutputZip(self, output_zip)
      if self.verbatim:
        # if verbatim, do not make patch, use whole file
        common.ZipWriteStr(output_zip, self.target.file_name, self.target.bin.data)
        print self.file_name + " changed; verbatim."

      else:
        d = common.Difference(self.target.bin, self.source.bin)
        _,_, d = d.ComputePatch()
        print "%-20s target: %d  source: %d  diff: %d" % (
            self.file_name, self.target.bin.size, self.source.bin.size, len(d))

        common.ZipWriteStr(output_zip, "patch/" + self.file_name + ".p", d)
        PartitionUpdater.need_cache_space = max(PartitionUpdater.need_cache_space, self.source.size)

        PartitionUpdater.total_verify_size += self.source.size

      PartitionUpdater.total_update_size += self.target.size

      print ("%-20s changed; including." % self.file_name)
    elif (self.target.bin):
      print ("%-20s unchanged; skipping." % self.file_name)
    else:
      print ("no target %s; skipping." % self.file_name)
Beispiel #3
0
def ComputeFWUpdatePatches(source_tfp_dir, target_tfp_dir, variant=None,
                             existing_ota_zip=None):
    patch_list = None
    verbatim = None
    output_files = None

    # In case an already "fixed up" ota package is passed - Do nothing
    if existing_ota_zip and patch_or_verbatim_exists("fwu_image.bin", existing_ota_zip):
        return verbatim, patch_list, output_files

    src_fwupdate_data = readfile_from_provdata(source_tfp_dir, "fwu_image.bin", variant)
    if not src_fwupdate_data:
        return verbatim, patch_list, output_files

    tgt_fwupdate_data = readfile_from_provdata(target_tfp_dir, "fwu_image.bin", variant)
    if not tgt_fwupdate_data:
        return verbatim, patch_list, output_files

    src_fwupdate = common.File("fwu_image.bin", src_fwupdate_data)
    tgt_fwupdate = common.File("fwu_image.bin", tgt_fwupdate_data)

    diffs = [common.Difference(tgt_fwupdate, src_fwupdate)]
    common.ComputeDifferences(diffs)

    tf, sf, d = diffs[0].GetPatch()
    verbatim = False
    # If the patch size is almost as big as the actual file
    # the fwu_image will be included in the OTA verbatim.
    if d is None or len(d) > tf.size * 0.95:
        print("Firmware update image will be included verbatim")
        verbatim = True
    else:
        patch_list = (tf,sf)
        output_files = d
    return verbatim, patch_list, output_files
def WriteRadio(info, target_radio_img, source_radio_img=None):
    tf = common.File("radio.img", target_radio_img)
    if source_radio_img is None:
        tf.AddToZip(info.output_zip)
        info.script.Print("Writing radio...")
        info.script.WriteRawImage("/radio", tf.name)
    else:
        sf = common.File("radio.img", source_radio_img)
        if tf.sha1 == sf.sha1:
            print "radio image unchanged; skipping"
        else:
            diff = common.Difference(tf, sf, diff_program="bsdiff")
            common.ComputeDifferences([diff])
            _, _, d = diff.GetPatch()
            if d is None or len(d) > tf.size * common.OPTIONS.patch_threshold:
                # computing difference failed, or difference is nearly as
                # big as the target:  simply send the target.
                tf.AddToZip(info.output_zip)
                info.script.Print("Writing radio...")
                info.script.WriteRawImage("/radio", tf.name)
            else:
                common.ZipWriteStr(info.output_zip, "radio.img.p", d)
                info.script.Print("Patching radio...")
                radio_type, radio_device = common.GetTypeAndDevice(
                    "/radio", info.info_dict)
                info.script.ApplyPatch(
                    "%s:%s:%d:%s:%d:%s" % (radio_type, radio_device, sf.size,
                                           sf.sha1, tf.size, tf.sha1), "-",
                    tf.size, tf.sha1, sf.sha1, "radio.img.p")
Beispiel #5
0
def IncrementalOTA_InstallEnd(info):
    try:
        target_bootloader_img = info.target_zip.read("RADIO/bootloader.img")
        try:
            source_bootloader_img = info.source_zip.read(
                "RADIO/bootloader.img")
        except KeyError:
            source_bootloader_img = None

        if source_bootloader_img == target_bootloader_img:
            print "bootloader unchanged; skipping"
        else:
            WriteBootloader(info, target_bootloader_img)
    except KeyError:
        print "no bootloader.img in target target_files; skipping install"

    tf = FindRadio(info.target_zip)
    if not tf:
        # failed to read TARGET radio image: don't include any radio in update.
        print "no radio.img in target target_files; skipping install"
        # we have checked the existence of the radio image in
        # IncrementalOTA_VerifyEnd(), so it won't reach here.
        assert common.OPTIONS.full_radio == False
    else:
        tf = common.File("radio.img", tf)

        sf = FindRadio(info.source_zip)
        if not sf or common.OPTIONS.full_radio:
            # failed to read SOURCE radio image or one has specified the option to
            # include the whole target radio image.
            print(
                "no radio image in source target_files or full_radio specified; "
                "installing complete image")
            WriteRadio(info, tf.data)
        else:
            sf = common.File("radio.img", sf)

            if tf.sha1 == sf.sha1:
                print "radio image unchanged; skipping"
            else:
                diff = common.Difference(tf, sf, diff_program="bsdiff")
                common.ComputeDifferences([diff])
                _, _, d = diff.GetPatch()
                if d is None or len(
                        d) > tf.size * common.OPTIONS.patch_threshold:
                    # computing difference failed, or difference is nearly as
                    # big as the target:  simply send the target.
                    WriteRadio(info, tf.data)
                else:
                    common.ZipWriteStr(info.output_zip, "radio.img.p", d)
                    info.script.Print("Patching radio...")
                    radio_type, radio_device = common.GetTypeAndDevice(
                        "/radio", info.info_dict)
                    info.script.ApplyPatch(
                        "%s:%s:%d:%s:%d:%s" %
                        (radio_type, radio_device, sf.size, sf.sha1, tf.size,
                         tf.sha1), "-", tf.size, tf.sha1, sf.sha1,
                        "radio.img.p")
Beispiel #6
0
def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
    """Generate a binary patch that creates the recovery image starting
  with the boot image.  (Most of the space in these images is just the
  kernel, which is identical for the two, so the resulting patch
  should be efficient.)  Add it to the output zip, along with a shell
  script that is run from init.rc on first boot to actually do the
  patching and install the new recovery image.

  recovery_img and boot_img should be File objects for the
  corresponding images.  info should be the dictionary returned by
  common.LoadInfoDict() on the input target_files.

  Returns an Item for the shell script, which must be made
  executable.
  """

    diff_program = ["imgdiff"]
    path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
    if os.path.exists(path):
        diff_program.append("-b")
        diff_program.append(path)
        bonus_args = "-b /system/etc/recovery-resource.dat"
    else:
        bonus_args = ""

    d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
    _, _, patch = d.ComputePatch()
    common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
    Item.Get("system/recovery-from-boot.p", dir=False)

    boot_type, boot_device = common.GetTypeAndDevice("/boot",
                                                     OPTIONS.info_dict)
    recovery_type, recovery_device = common.GetTypeAndDevice(
        "/recovery", OPTIONS.info_dict)

    sh = """#!/system/bin/sh
if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
  log -t recovery "Installing new recovery image"
  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
else
  log -t recovery "Recovery image already installed"
fi
""" % {
        'boot_size': boot_img.size,
        'boot_sha1': boot_img.sha1,
        'recovery_size': recovery_img.size,
        'recovery_sha1': recovery_img.sha1,
        'boot_type': boot_type,
        'boot_device': boot_device,
        'recovery_type': recovery_type,
        'recovery_device': recovery_device,
        'bonus_args': bonus_args,
    }
    common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
    return Item.Get("system/etc/install-recovery.sh", dir=False)
Beispiel #7
0
def ComputeBootloaderPatch(source_tfp_dir, target_tfp_dir, variant=None,
                           base_variant=None, existing_ota_zip=None):
    target_data = LoadBootloaderFiles(target_tfp_dir, variant=variant, base_variant=base_variant)
    source_data = LoadBootloaderFiles(source_tfp_dir, variant=variant, base_variant=base_variant)

    diffs = []

    # List of files that will be included in the OTA verbatim because
    # they are either new or the patch is > 95% in size of the original
    # file. If this isn't empty you just need to call edify generator
    # UnpackPackageDir("bootloader", "/bootloader")
    verbatim_targets = []

    # Returned list of common.File objects that need to be added to
    # the OTA archive, for each one call AddToZip()
    output_files = []

    # Returned list of patches to be created.
    # Each element is a tuple of the form (path, target File object,
    # source File object, target file size)
    patch_list = []

    for fn in sorted(target_data.keys()):
        filepath = os.path.join('bootloader', fn)
        if existing_ota_zip and patch_or_verbatim_exists(filepath, existing_ota_zip):
            continue

        tf = target_data[fn]
        sf = source_data.get(fn, None)

        if sf is None:
            verbatim_targets.append(fn)
            output_files.append(tf)
        elif tf.sha1 != sf.sha1:
            diffs.append(common.Difference(tf, sf))

    common.ComputeDifferences(diffs)

    for diff in diffs:
        tf, sf, d = diff.GetPatch()
        if d is None or len(d) > tf.size * 0.95:
            output_files.append(tf)
            verbatim_targets.append(tf.name)
        else:
            output_files.append(common.File("patch/" + tf.name + ".p", d))
            patch_list.append((tf, sf))

    # output list of files that need to be deleted, pass this to
    # edify generator DeleteFiles in InstallEnd
    delete_files = ["/bootloader/"+i for i in sorted(source_data) if i not in target_data]

    return (output_files, delete_files, patch_list, verbatim_targets)
def IncrementalOTA_InstallEnd(info):
    tf = FindRadio(info.target_zip)
    if not tf:
        # failed to read TARGET radio image: don't include any radio in update.
        print "no radio.img in target target_files; skipping install"
    else:
        tf = common.File("uboot.bin", tf)

        sf = FindRadio(info.source_zip)
        if not sf:
            # failed to read SOURCE radio image: include the whole target
            # radio image.
            WriteRadio(info, tf.data)
        else:
            sf = common.File("uboot.bin", sf)

            if tf.sha1 == sf.sha1:
                print "u-boot-with-spl-mbr-gpt.bin unchanged; skipping"
            else:
                diff = common.Difference(tf, sf, diff_program="bsdiff")
                common.ComputeDifferences([diff])
                _, _, d = diff.GetPatch()
                if d is None or len(
                        d) > tf.size * common.OPTIONS.patch_threshold:
                    # computing difference failed, or difference is nearly as
                    # big as the target:  simply send the target.
                    WriteRadio(info, tf.data)
                else:
                    common.ZipWriteStr(info.output_zip,
                                       "u-boot-with-spl-mbr-gpt.bin.p", d)
                    info.script.Print("Patching uboot...")
                    uboot_type, uboot_device = common.GetTypeAndDevice(
                        "/uboot", info.info_dict)

                    info.script.PatchCheck("%s:%s:%d:%s:%d:%s" %
                                           (uboot_type, uboot_device, sf.size,
                                            sf.sha1, tf.size, tf.sha1))

                    info.script.ApplyPatch(
                        "%s:%s:%d:%s:%d:%s" %
                        (uboot_type, uboot_device, sf.size, sf.sha1, tf.size,
                         tf.sha1), "-", tf.size, tf.sha1, sf.sha1,
                        "u-boot-with-spl-mbr-gpt.bin.p")
Beispiel #9
0
def ComputeBinOrImgPatches(source_tfp_dir, target_tfp_dir, filename=None, variant=None,
                             existing_ota_zip=None):
    patch_list = []
    verbatim = None
    output_files = None

    if filename is None:
        print("Error input, no filename ")
        return [None, None, None]

    source_loader_filepath = os.path.join(source_tfp_dir, "RADIO", filename)
    if not os.path.exists(source_loader_filepath):
        print("Source:Can't find ", source_loader_filepath)
        return [None, None, None]
    source_loader_file = open(source_loader_filepath)
    source_loader_data = source_loader_file.read()
    source_loader_file.close()

    target_loader_filepath = os.path.join(target_tfp_dir, "RADIO", filename)
    if not os.path.exists(target_loader_filepath):
        print("Target Can't find ", target_loader_filepath)
        return [None, None, None]
    target_loader_file = open(target_loader_filepath)
    target_loader_data = target_loader_file.read()
    target_loader_file.close()

    src_bin = common.File(filename, source_loader_data)
    tgt_bin = common.File(filename, target_loader_data)

    diffs = [common.Difference(tgt_bin, src_bin)]
    common.ComputeDifferences(diffs)
    tf, sf, d = diffs[0].GetPatch()
    verbatim = False
    # If the patch size is almost as big as the actual file
    # the image will be included in the OTA verbatim.
    if d is None or len(d) > tf.size * 0.95:
        print(filename, "update will be included verbatim")
        verbatim = True
    else:
        patch_list = (tf,sf)
        output_files = d
    return verbatim, patch_list, output_files
def IncrementalEspUpdateInit(info):
    global target_data
    global source_data
    global delete_files
    global bootloader_update

    target_data = LoadBootloaderFiles(OPTIONS.target_tmp)
    source_data = LoadBootloaderFiles(OPTIONS.source_tmp)

    diffs = []

    for fn in sorted(target_data.keys()):
        tf = target_data[fn]
        sf = source_data.get(fn, None)

        if sf is None:
            tf.AddToZip(info.output_zip)
            verbatim_targets.append(fn)
        elif tf.sha1 != sf.sha1:
            diffs.append(common.Difference(tf, sf))

    common.ComputeDifferences(diffs)

    for diff in diffs:
        tf, sf, d = diff.GetPatch()
        if d is None or len(d) > tf.size * 0.95:
            tf.AddToZip(info.output_zip)
            verbatim_targets.append(tf.name)
        else:
            common.ZipWriteStr(info.output_zip, "patch/" + tf.name + ".p", d)
            patch_list.append(
                (tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))

    delete_files = (
        ["/" + i[0] for i in verbatim_targets] +
        ["/" + i for i in sorted(source_data) if i not in target_data])

    if (delete_files or patch_list or verbatim_targets
            or os.path.exists(os.path.join(OPTIONS.target_tmp, sfu_path))):
        print "EFI System Partition will be updated"
        bootloader_update = True
def update_raw_image_verify(info, in_img, out_img, node, inc):
    if inc:
        src = get_image(info.source_zip, in_img)
        tgt = get_image(info.target_zip, in_img)
    else:
        src = None
        tgt = get_image(info.input_zip, in_img)

    if not tgt:
        return

    imgtype, imgdev = common.GetTypeAndDevice(node, info.info_dict)

    if src:
        if src.data == tgt.data:
            print "%s images identical, not patching" % (in_img, )
            return
        else:
            print "%s images differ, will patch" % (in_img, )
        d = common.Difference(tgt, src)
        _, _, d = d.ComputePatch()
        print "%s      target: %d  source: %d  diff: %d" % (out_img, tgt.size,
                                                            src.size, len(d))
        out_img = "patch/%s.p" % (out_img, )
        common.ZipWriteStr(info.output_zip, out_img, d)
        info.script.PatchCheck(
            "%s:%s:%d:%s:%d:%s" %
            (imgtype, imgdev, src.size, src.sha1, tgt.size, tgt.sha1))
        info.script.CacheFreeSpaceCheck(src.size)

    img[node] = {}
    img[node]["out_img"] = out_img
    img[node]["src"] = src
    img[node]["tgt"] = tgt
    img[node]["type"] = imgtype
    img[node]["dev"] = imgdev
Beispiel #12
0
def IncrementalOTA_VerifyEnd(info):
  global patchinfo

  print "Calculating fwupdate patch information"
  src_fwupdate = get_file_data(OPTIONS.source_tmp, "fwu_image.bin")
  tgt_fwupdate = get_file_data(OPTIONS.target_tmp, "fwu_image.bin")

  diffs = [common.Difference(tgt_fwupdate, src_fwupdate)]
  common.ComputeDifferences(diffs)

  tf, sf, d = diffs[0].GetPatch()
  # If the patch size is almost as big as the actual file don't bother
  if d is None or len(d) > tf.size * 0.95:
    print "Firmware update image will be included verbatim"
    return

  common.ZipWriteStr(info.output_zip, "patch/fwu_image.bin.p", d)
  fwu_type, fwu_device = common.GetTypeAndDevice("/fwupdate", OPTIONS.info_dict)
  # This check ensure fwupdate partition is in an expected state before
  # the OTA system makes any changes
  info.script.PatchCheck("%s:%s:%d:%s:%d:%s" %
                         (fwu_type, fwu_device, sf.size,
                          sf.sha1, tf.size, tf.sha1))
  patchinfo = (fwu_type, fwu_device, sf, tf)
Beispiel #13
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)
    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)
Beispiel #14
0
def OTA_VerifyEnd(info, api_version, target_zip, source_zip=None):
    if api_version < 3:
        print "warning radio-update: no support for api_version less than 3"
        return False

    print "Loading radio filesmap..."
    filesmap = LoadFilesMap(target_zip)
    if filesmap == {}:
        print "warning radio-update: no or invalid filesmap file found"
        return False

    print "Loading radio target..."
    tgt_files = GetRadioFiles(target_zip)
    if tgt_files == {}:
        print "warning radio-update: no radio images in input target_files"
        return False

    src_files = None
    if source_zip is not None:
        print "Loading radio source..."
        src_files = GetRadioFiles(source_zip)

    update_list = {}
    largest_source_size = 0

    if info.type == 'MMC':
        part = "EMMC"
    else:
        part = "MTD"

    print "Preparing radio-update files..."
    for fn in tgt_files:
        dest, destBak = GetFileDestination(fn, filesmap)
        if dest is None:
            continue

        tf = tgt_files[fn]
        sf = None
        if src_files is not None:
            sf = src_files.get(fn, None)

        full = sf is None or fn.endswith('.enc')
        if not full:
            # no difference - skip this file
            if tf.sha1 == sf.sha1:
                continue
            d = common.Difference(tf, sf)
            _, _, d = d.ComputePatch()
            # no difference - skip this file
            if d is None:
                continue
            # if patch is almost as big as the file - don't bother patching
            full = len(d) > tf.size * common.OPTIONS.patch_threshold
            if not full:
                f = "patch/firmware-update/" + fn + ".p"
                common.ZipWriteStr(info.output_zip, f, d)
                update_list[f] = (dest, destBak, tf, sf)
                largest_source_size = max(largest_source_size, sf.size)
        if full:
            f = "firmware-update/" + fn
            common.ZipWriteStr(info.output_zip, f, tf.data)
            update_list[f] = (dest, destBak, None, None)

    global bootImages
    global binImages
    global fwImages
    bootImages, binImages, fwImages = SplitFwTypes(update_list)

    # If there are incremental patches verify them
    if largest_source_size != 0:
        info.script.Comment("---- radio update verification ----")
        info.script.Print("Verifying radio-update...")

        for f in bootImages:
            dest, destBak, tf, sf = bootImages[f]
            # Not incremental
            if sf is None:
                continue
            info.script.PatchCheck(
                "%s:%s:%d:%s:%d:%s" %
                (part, dest, sf.size, sf.sha1, tf.size, tf.sha1))
            if destBak is not None:
                info.script.PatchCheck(
                    "%s:%s:%d:%s:%d:%s" %
                    (part, destBak, sf.size, sf.sha1, tf.size, tf.sha1))
        for f in binImages:
            dest, destBak, tf, sf = binImages[f]
            # Not incremental
            if sf is None:
                continue
            info.script.PatchCheck(
                "%s:%s:%d:%s:%d:%s" %
                (part, dest, sf.size, sf.sha1, tf.size, tf.sha1))

        last_mounted = ""
        for f in fwImages:
            dest, destBak, tf, sf = fwImages[f]
            # Not incremental
            if sf is None:
                continue
            # Get the filename without the path and the patch (.p) extention
            f = f.split("/")[-1][:-2]
            # Parse filesmap destination paths for "/dev/" pattern in the beginng.
            # This would mean that the file must be written to block device -
            # fs mount needed
            if dest.startswith("/dev/"):
                if last_mounted != dest:
                    info.script.AppendExtra('unmount("/firmware");')
                    info.script.AppendExtra(
                        'mount("vfat", "%s", "%s", "/firmware");' %
                        (part, dest))
                    last_mounted = dest
                dest = "/firmware/image/" + f
            else:
                dest = dest + "/" + f
            info.script.PatchCheck(dest, tf.sha1, sf.sha1)

        info.script.CacheFreeSpaceCheck(largest_source_size)
    return True
Beispiel #15
0
def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
    source_version = OPTIONS.source_info_dict["recovery_api_version"]
    target_version = OPTIONS.target_info_dict["recovery_api_version"]

    if source_version == 0:
        print(
            "WARNING: generating edify script for a source that "
            "can't install it.")
    script = edify_generator.EdifyGenerator(source_version,
                                            OPTIONS.target_info_dict)

    if OPTIONS.override_prop:
        metadata = {
            "post-timestamp":
            GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict),
        }
    else:
        metadata = {
            "pre-device":
            GetBuildProp("ro.product.device", OPTIONS.source_info_dict),
            "post-timestamp":
            GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict),
        }

    device_specific = common.DeviceSpecificParams(
        source_zip=source_zip,
        source_version=source_version,
        target_zip=target_zip,
        target_version=target_version,
        output_zip=output_zip,
        script=script,
        metadata=metadata,
        info_dict=OPTIONS.info_dict)

    print "Loading target..."
    target_data = LoadSystemFiles(target_zip)
    print "Loading source..."
    source_data = LoadSystemFiles(source_zip)

    verbatim_targets = []
    patch_list = []
    diffs = []
    renames = {}
    largest_source_size = 0

    matching_file_cache = {}
    for fn in source_data.keys():
        sf = source_data[fn]
        assert fn == sf.name
        matching_file_cache["path:" + fn] = sf
        # Only allow eligability for filename/sha matching
        # if there isn't a perfect path match.
        if target_data.get(sf.name) is None:
            matching_file_cache["file:" + fn.split("/")[-1]] = sf
            matching_file_cache["sha:" + sf.sha1] = sf

    for fn in sorted(target_data.keys()):
        tf = target_data[fn]
        assert fn == tf.name
        sf = ClosestFileMatch(tf, matching_file_cache, renames)
        if sf is not None and sf.name != tf.name:
            print "File has moved from " + sf.name + " to " + tf.name
            renames[sf.name] = tf

        if sf is None or fn in OPTIONS.require_verbatim:
            # This file should be included verbatim
            if fn in OPTIONS.prohibit_verbatim:
                raise common.ExternalError("\"%s\" must be sent verbatim" %
                                           (fn, ))
            print "send", fn, "verbatim"
            tf.AddToZip(output_zip)
            verbatim_targets.append((fn, tf.size))
        elif tf.sha1 != sf.sha1:
            # File is different; consider sending as a patch
            diffs.append(common.Difference(tf, sf))
        else:
            # Target file data identical to source (may still be renamed)
            pass


#  common.ComputeDifferences(diffs)
#
#  for diff in diffs:
#    tf, sf, d = diff.GetPatch()
#    if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
#      # patch is almost as big as the file; don't bother patching
#      tf.AddToZip(output_zip)
#      verbatim_targets.append((tf.name, tf.size))
#    else:
#      common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
#      patch_list.append((sf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
#      largest_source_size = max(largest_source_size, sf.size)

    if not OPTIONS.override_prop:
        source_fp = GetBuildProp("ro.build.fingerprint",
                                 OPTIONS.source_info_dict)
        target_fp = GetBuildProp("ro.build.fingerprint",
                                 OPTIONS.target_info_dict)
        metadata["pre-build"] = source_fp
        metadata["post-build"] = target_fp

        script.Mount("/system")
        script.AssertSomeFingerprint(source_fp, target_fp)

    source_boot = common.GetBootableImage("/tmp/boot.img", "boot.img",
                                          OPTIONS.source_tmp, "BOOT",
                                          OPTIONS.source_info_dict)
    target_boot = common.GetBootableImage("/tmp/boot.img", "boot.img",
                                          OPTIONS.target_tmp, "BOOT")
    updating_boot = (source_boot.data != target_boot.data)

    #source_recovery = common.GetBootableImage(
    #    "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
    #    OPTIONS.source_info_dict)
    #target_recovery = common.GetBootableImage(
    #    "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
    #updating_recovery = (source_recovery.data != target_recovery.data)
    updating_recovery = False

    # Here's how we divide up the progress bar:
    #  0.1 for verifying the start state (PatchCheck calls)
    #  0.8 for applying patches (ApplyPatch calls)
    #  0.1 for unpacking verbatim files, symlinking, and doing the
    #      device-specific commands.

    AppendAssertions(script, OPTIONS.target_info_dict)
    device_specific.IncrementalOTA_Assertions()

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

    device_specific.IncrementalOTA_VerifyBegin()

    script.ShowProgress(0.1, 0)
    total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
    if updating_boot:
        total_verify_size += source_boot.size
    so_far = 0

    for fn, tf, sf, size, patch_sha in patch_list:
        script.PatchCheck("/" + fn, tf.sha1, sf.sha1)
        so_far += sf.size
        script.SetProgress(so_far / total_verify_size)

    if updating_boot:
        d = common.Difference(target_boot, source_boot)
        _, _, d = d.ComputePatch()
        print "boot      target: %d  source: %d  diff: %d" % (
            target_boot.size, source_boot.size, len(d))

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

        boot_type, boot_device = common.GetTypeAndDevice(
            "/boot", OPTIONS.info_dict)

        script.PatchCheck(
            "%s:%s:%d:%s:%d:%s" %
            (boot_type, boot_device, source_boot.size, source_boot.sha1,
             target_boot.size, target_boot.sha1))
        so_far += source_boot.size
        script.SetProgress(so_far / total_verify_size)

    if patch_list or updating_recovery or updating_boot:
        script.CacheFreeSpaceCheck(largest_source_size)

    device_specific.IncrementalOTA_VerifyEnd()

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

    device_specific.IncrementalOTA_InstallBegin()

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

    script.Print("Removing unneeded files...")
    script.DeleteFiles(["/" + i[0] for i in verbatim_targets] + [
        "/" + i for i in sorted(source_data)
        if i not in target_data and i not in renames
    ] + ["/system/recovery.img"])

    script.ShowProgress(0.8, 0)
    total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
    if updating_boot:
        total_patch_size += target_boot.size
    so_far = 0

    script.Print("Patching system files...")
    deferred_patch_list = []
    for item in patch_list:
        fn, tf, sf, size, _ = item
        if tf.name == "system/build.prop":
            deferred_patch_list.append(item)
            continue
        script.ApplyPatch("/" + fn, "-", tf.size, tf.sha1, sf.sha1,
                          "patch/" + fn + ".p")
        so_far += tf.size
        script.SetProgress(so_far / total_patch_size)

    if updating_boot:
        # Produce the boot image by applying a patch to the current
        # contents of the boot partition, and write it back to the
        # partition.
        script.Print("Patching boot image...")
        script.ApplyPatch(
            "%s:%s:%d:%s:%d:%s" %
            (boot_type, boot_device, source_boot.size, source_boot.sha1,
             target_boot.size, target_boot.sha1), "-", target_boot.size,
            target_boot.sha1, source_boot.sha1, "patch/boot.img.p")
        so_far += target_boot.size
        script.SetProgress(so_far / total_patch_size)
        print "boot image changed; including."
    else:
        print "boot image unchanged; skipping."

    if updating_recovery:
        # Recovery is generated as a patch using both the boot image
        # (which contains the same linux kernel as recovery) and the file
        # /system/etc/recovery-resource.dat (which contains all the images
        # used in the recovery UI) as sources.  This lets us minimize the
        # size of the patch, which must be included in every OTA package.
        #
        # For older builds where recovery-resource.dat is not present, we
        # use only the boot image as the source.

        MakeRecoveryPatch(OPTIONS.target_tmp, output_zip, target_recovery,
                          target_boot)
        script.DeleteFiles([
            "/system/recovery-from-boot.p", "/system/etc/install-recovery.sh"
        ])
        print "recovery image changed; including as patch from boot."
    else:
        print "recovery image unchanged; skipping."

    script.ShowProgress(0.1, 10)

    target_symlinks = CopySystemFiles(target_zip, None)

    target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
    temp_script = script.MakeTemporary()
    Item.GetMetadata(target_zip)
    Item.Get("system").SetPermissions(temp_script)

    # Note that this call will mess up the tree of Items, so make sure
    # we're done with it.
    source_symlinks = CopySystemFiles(source_zip, None)
    source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])

    # Delete all the symlinks in source that aren't in target.  This
    # needs to happen before verbatim files are unpacked, in case a
    # symlink in the source is replaced by a real file in the target.
    to_delete = []
    for dest, link in source_symlinks:
        if link not in target_symlinks_d:
            to_delete.append(link)
    script.DeleteFiles(to_delete)

    if verbatim_targets:
        script.Print("Unpacking new files...")
        script.UnpackPackageDir("system", "/system")

    #if updating_recovery:
    #  script.Print("Unpacking new recovery...")
    #  script.UnpackPackageDir("recovery", "/system")

    if len(renames) > 0:
        script.Print("Renaming files...")

    for src in renames:
        print "Renaming " + src + " to " + renames[src].name
        script.RenameFile(src, renames[src].name)

    script.Print("Symlinks and permissions...")

    # Create all the symlinks that don't already exist, or point to
    # somewhere different than what we want.  Delete each symlink before
    # creating it, since the 'symlink' command won't overwrite.
    to_create = []
    for dest, link in target_symlinks:
        if link in source_symlinks_d:
            if dest != source_symlinks_d[link]:
                to_create.append((dest, link))
        else:
            to_create.append((dest, link))
    script.DeleteFiles([i[1] for i in to_create])
    script.MakeSymlinks(to_create)

    # Now that the symlinks are created, we can set all the
    # permissions.
    script.AppendScript(temp_script)

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

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

    # Patch the build.prop file last, so if something fails but the
    # device can still come up, it appears to be the old build and will
    # get set the OTA package again to retry.
    script.Print("Patching remaining system files...")
    for item in deferred_patch_list:
        fn, tf, sf, size, _ = item
        script.ApplyPatch("/" + fn, "-", tf.size, tf.sha1, sf.sha1,
                          "patch/" + fn + ".p")
    script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)

    script.AddToZip(target_zip, output_zip)
    WriteMetadata(metadata, output_zip)