示例#1
0
  def GetIncrementalBlockDifferenceForPartition(name):
    if not HasPartition(source_zip, name):
      raise RuntimeError(
          "can't generate incremental that adds {}".format(name))

    partition_src = common.GetUserImage(name, OPTIONS.source_tmp, source_zip,
                                        info_dict=source_info,
                                        allow_shared_blocks=allow_shared_blocks)

    hashtree_info_generator = verity_utils.CreateHashtreeInfoGenerator(
        name, 4096, target_info)
    partition_tgt = common.GetUserImage(name, OPTIONS.target_tmp, target_zip,
                                        info_dict=target_info,
                                        allow_shared_blocks=allow_shared_blocks,
                                        hashtree_info_generator=hashtree_info_generator)

    # Check the first block of the source system partition for remount R/W only
    # if the filesystem is ext4.
    partition_source_info = source_info["fstab"]["/" + name]
    check_first_block = partition_source_info.fs_type == "ext4"
    # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
    # in zip formats. However with squashfs, a) all files are compressed in LZ4;
    # b) the blocks listed in block map may not contain all the bytes for a
    # given file (because they're rounded to be 4K-aligned).
    partition_target_info = target_info["fstab"]["/" + name]
    disable_imgdiff = (partition_source_info.fs_type == "squashfs" or
                       partition_target_info.fs_type == "squashfs")
    return common.BlockDifference(name, partition_tgt, partition_src,
                                  check_first_block,
                                  version=blockimgdiff_version,
                                  disable_imgdiff=disable_imgdiff)
示例#2
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))

  androidver = target_info.GetBuildProp("ro.build.version.release")
  buildid = target_info.GetBuildProp("ro.build.id")
  builddate = target_info.GetBuildProp("ro.build.date")
  securep = target_info.GetBuildProp("ro.build.version.security_patch")
  name = target_info.GetBuildProp("ro.product.name")
  model = target_info.GetBuildProp("ro.product.model")
  manufacturer = target_info.GetBuildProp("ro.product.manufacturer")
  builduser = target_info.GetBuildProp("ro.build.user")
  buildsdk = target_info.GetBuildProp("ro.build.version.sdk")

  # Start output
  script.Print("----------------------------------------------")
  script.Print("           _____ _   _             _   _ ___ ")
  script.Print("  _____  _|_   _| | | |_ __ ___   | | | |_ _|")
  script.Print(" / _ \ \/ / | | | |_| | '_ ` _ \  | | | || |")
  script.Print("|  __/>  <  | | |  _  | | | | | | | |_| || |")
  script.Print(" \___/_/\_\ |_| |_| |_|_| |_| |_|  \___/|___|")
  script.Print("")
  script.Print("         extended TouHou modified UI")
  script.Print("            Based on AOSP")
  script.Print("----------------------------------------------")
  script.Print("ROM Information    :")
  script.Print("Build Date         : %s"%(builddate))
  script.Print("Android Version    : %s"%(androidver))
  script.Print("exTHmUI Version    : %s"%(buildid))
  script.Print("SDK Version        : %s"%(buildsdk))
  script.Print("Security Patch Date: %s"%(securep))
  script.Print("----------------------------------------------")
  script.Print("Device Information :")
  script.Print("Manufacturer       : %s"%(manufacturer))
  script.Print("Name               : %s"%(name))
  script.Print("Model              : %s"%(model))
  script.Print("----------------------------------------------")
  script.Print("Installing exTHmUI to your device...")
  script.Print("")
  device_specific.FullOTA_InstallBegin()

  CopyInstallTools(output_zip)
  script.UnpackPackageDir("install", "/tmp/install")
  script.SetPermissionsRecursive("/tmp/install", 0, 0, 0o755, 0o644, None, None)
  script.SetPermissionsRecursive("/tmp/install/bin", 0, 0, 0o755, 0o755, None, None)

  if target_info.get("system_root_image") == "true":
    sysmount = "/"
  else:
    sysmount = "/system"

  if OPTIONS.backuptool:
    script.RunBackup("backup", sysmount, target_info.get('use_dynamic_partitions') == "true")

  # 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()

  if OPTIONS.backuptool:
    script.ShowProgress(0.02, 10)
    script.RunBackup("restore", sysmount, target_info.get('use_dynamic_partitions') == "true")

  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)
示例#3
0
def GetBlockDifferences(target_zip, source_zip, target_info, source_info,
                        device_specific):
  """Returns a ordered dict of block differences with partition name as key."""

  def GetIncrementalBlockDifferenceForPartition(name):
    if not HasPartition(source_zip, name):
      raise RuntimeError(
          "can't generate incremental that adds {}".format(name))

    partition_src = common.GetUserImage(name, OPTIONS.source_tmp, source_zip,
                                        info_dict=source_info,
                                        allow_shared_blocks=allow_shared_blocks)

    hashtree_info_generator = verity_utils.CreateHashtreeInfoGenerator(
        name, 4096, target_info)
    partition_tgt = common.GetUserImage(name, OPTIONS.target_tmp, target_zip,
                                        info_dict=target_info,
                                        allow_shared_blocks=allow_shared_blocks,
                                        hashtree_info_generator=hashtree_info_generator)

    # Check the first block of the source system partition for remount R/W only
    # if the filesystem is ext4.
    partition_source_info = source_info["fstab"]["/" + name]
    check_first_block = partition_source_info.fs_type == "ext4"
    # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
    # in zip formats. However with squashfs, a) all files are compressed in LZ4;
    # b) the blocks listed in block map may not contain all the bytes for a
    # given file (because they're rounded to be 4K-aligned).
    partition_target_info = target_info["fstab"]["/" + name]
    disable_imgdiff = (partition_source_info.fs_type == "squashfs" or
                       partition_target_info.fs_type == "squashfs")
    return common.BlockDifference(name, partition_tgt, partition_src,
                                  check_first_block,
                                  version=blockimgdiff_version,
                                  disable_imgdiff=disable_imgdiff)

  if source_zip:
    # See notes in common.GetUserImage()
    allow_shared_blocks = (source_info.get('ext4_share_dup_blocks') == "true" or
                           target_info.get('ext4_share_dup_blocks') == "true")
    blockimgdiff_version = max(
        int(i) for i in target_info.get(
            "blockimgdiff_versions", "1").split(","))
    assert blockimgdiff_version >= 3

  block_diff_dict = collections.OrderedDict()
  partition_names = ["system", "vendor", "product", "odm", "system_ext",
                     "vendor_dlkm", "odm_dlkm"]
  for partition in partition_names:
    if not HasPartition(target_zip, partition):
      continue
    # Full OTA update.
    if not source_zip:
      tgt = common.GetUserImage(partition, OPTIONS.input_tmp, target_zip,
                                info_dict=target_info,
                                reset_file_map=True)
      block_diff_dict[partition] = common.BlockDifference(partition, tgt,
                                                          src=None)
    # Incremental OTA update.
    else:
      block_diff_dict[partition] = GetIncrementalBlockDifferenceForPartition(
          partition)
  assert "system" in block_diff_dict

  # Get the block diffs from the device specific script. If there is a
  # duplicate block diff for a partition, ignore the diff in the generic script
  # and use the one in the device specific script instead.
  if source_zip:
    device_specific_diffs = device_specific.IncrementalOTA_GetBlockDifferences()
    function_name = "IncrementalOTA_GetBlockDifferences"
  else:
    device_specific_diffs = device_specific.FullOTA_GetBlockDifferences()
    function_name = "FullOTA_GetBlockDifferences"

  if device_specific_diffs:
    assert all(isinstance(diff, common.BlockDifference)
               for diff in device_specific_diffs), \
        "{} is not returning a list of BlockDifference objects".format(
            function_name)
    for diff in device_specific_diffs:
      if diff.partition in block_diff_dict:
        logger.warning("Duplicate block difference found. Device specific block"
                       " diff for partition '%s' overrides the one in generic"
                       " script.", diff.partition)
      block_diff_dict[diff.partition] = diff

  return block_diff_dict
示例#4
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)