Beispiel #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)
        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 AddImagesToTargetFiles(filename):
  """Creates and adds images (boot/recovery/system/...) to a target_files.zip.

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

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

  Args:
      filename: the target_files.zip, or the zip root directory.
  """
  if os.path.isdir(filename):
    OPTIONS.input_tmp = os.path.abspath(filename)
    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,product}.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,product}.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_product = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "PRODUCT")) or
                 os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                             "product.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

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

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

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

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

  banner("boot")
  # common.GetBootableImage() returns the image directly if present.
  boot_image = common.GetBootableImage(
      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
  # boot.img may be unavailable in some targets (e.g. aosp_arm64).
  if boot_image:
    partitions['boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
    if not os.path.exists(partitions['boot']):
      boot_image.WriteToDir(OPTIONS.input_tmp)
      if output_zip:
        boot_image.AddToZip(output_zip)

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

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

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

  if has_vendor:
    banner("vendor")
    partitions['vendor'] = AddVendor(output_zip)

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

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

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

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

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

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

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

    # 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.
    AddRadioImagesForAbOta(output_zip, ab_partitions)

    # Generate care_map.txt for system and vendor partitions (if present), then
    # write this file to target_files package.
    AddCareMapTxtForAbOta(output_zip, ab_partitions, partitions)

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

  if output_zip:
    common.ZipClose(output_zip)
    if OPTIONS.replace_updated_files_list:
      ReplaceUpdatedFiles(output_zip.filename,
                          OPTIONS.replace_updated_files_list)
Beispiel #3
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))

    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)

    # 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)
Beispiel #4
0
def main(argv):

  key_mapping_options = []

  def option_handler(o, a):
    if o in ("-e", "--extra_apks"):
      names, key = a.split("=")
      names = names.split(",")
      for n in names:
        OPTIONS.extra_apks[n] = key
    elif o == "--extra_apex_payload_key":
      apex_name, key = a.split("=")
      OPTIONS.extra_apex_payload_keys[apex_name] = key
    elif o == "--skip_apks_with_path_prefix":
      # Check the prefix, which must be in all upper case.
      prefix = a.split('/')[0]
      if not prefix or prefix != prefix.upper():
        raise ValueError("Invalid path prefix '%s'" % (a,))
      OPTIONS.skip_apks_with_path_prefix.add(a)
    elif o in ("-d", "--default_key_mappings"):
      key_mapping_options.append((None, a))
    elif o in ("-k", "--key_mapping"):
      key_mapping_options.append(a.split("=", 1))
    elif o in ("-o", "--replace_ota_keys"):
      OPTIONS.replace_ota_keys = True
    elif o in ("-t", "--tag_changes"):
      new = []
      for i in a.split(","):
        i = i.strip()
        if not i or i[0] not in "-+":
          raise ValueError("Bad tag change '%s'" % (i,))
        new.append(i[0] + i[1:].strip())
      OPTIONS.tag_changes = tuple(new)
    elif o == "--replace_verity_public_key":
      OPTIONS.replace_verity_public_key = (True, a)
    elif o == "--replace_verity_private_key":
      OPTIONS.replace_verity_private_key = (True, a)
    elif o == "--replace_verity_keyid":
      OPTIONS.replace_verity_keyid = (True, a)
    elif o == "--remove_avb_public_keys":
      OPTIONS.remove_avb_public_keys = a.split(",")
    elif o == "--avb_vbmeta_key":
      OPTIONS.avb_keys['vbmeta'] = a
    elif o == "--avb_vbmeta_algorithm":
      OPTIONS.avb_algorithms['vbmeta'] = a
    elif o == "--avb_vbmeta_extra_args":
      OPTIONS.avb_extra_args['vbmeta'] = a
    elif o == "--avb_boot_key":
      OPTIONS.avb_keys['boot'] = a
    elif o == "--avb_boot_algorithm":
      OPTIONS.avb_algorithms['boot'] = a
    elif o == "--avb_boot_extra_args":
      OPTIONS.avb_extra_args['boot'] = a
    elif o == "--avb_dtbo_key":
      OPTIONS.avb_keys['dtbo'] = a
    elif o == "--avb_dtbo_algorithm":
      OPTIONS.avb_algorithms['dtbo'] = a
    elif o == "--avb_dtbo_extra_args":
      OPTIONS.avb_extra_args['dtbo'] = a
    elif o == "--avb_system_key":
      OPTIONS.avb_keys['system'] = a
    elif o == "--avb_system_algorithm":
      OPTIONS.avb_algorithms['system'] = a
    elif o == "--avb_system_extra_args":
      OPTIONS.avb_extra_args['system'] = a
    elif o == "--avb_system_other_key":
      OPTIONS.avb_keys['system_other'] = a
    elif o == "--avb_system_other_algorithm":
      OPTIONS.avb_algorithms['system_other'] = a
    elif o == "--avb_system_other_extra_args":
      OPTIONS.avb_extra_args['system_other'] = a
    elif o == "--avb_vendor_key":
      OPTIONS.avb_keys['vendor'] = a
    elif o == "--avb_vendor_algorithm":
      OPTIONS.avb_algorithms['vendor'] = a
    elif o == "--avb_vendor_extra_args":
      OPTIONS.avb_extra_args['vendor'] = a
    elif o == "--avb_vbmeta_system_key":
      OPTIONS.avb_keys['vbmeta_system'] = a
    elif o == "--avb_vbmeta_system_algorithm":
      OPTIONS.avb_algorithms['vbmeta_system'] = a
    elif o == "--avb_vbmeta_system_extra_args":
      OPTIONS.avb_extra_args['vbmeta_system'] = a
    elif o == "--avb_vbmeta_vendor_key":
      OPTIONS.avb_keys['vbmeta_vendor'] = a
    elif o == "--avb_vbmeta_vendor_algorithm":
      OPTIONS.avb_algorithms['vbmeta_vendor'] = a
    elif o == "--avb_vbmeta_vendor_extra_args":
      OPTIONS.avb_extra_args['vbmeta_vendor'] = a
    elif o == "--avb_apex_extra_args":
      OPTIONS.avb_extra_args['apex'] = a
    elif o == "--avb_extra_custom_image_key":
      partition, key = a.split("=")
      OPTIONS.avb_keys[partition] = key
    elif o == "--avb_extra_custom_image_algorithm":
      partition, algorithm = a.split("=")
      OPTIONS.avb_algorithms[partition] = algorithm
    elif o == "--avb_extra_custom_image_extra_args":
      # Setting the maxsplit parameter to one, which will return a list with
      # two elements. e.g., the second '=' should not be splitted for
      # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
      partition, extra_args = a.split("=", 1)
      OPTIONS.avb_extra_args[partition] = extra_args
    else:
      return False
    return True

  args = common.ParseOptions(
      argv, __doc__,
      extra_opts="e:d:k:ot:",
      extra_long_opts=[
          "extra_apks=",
          "extra_apex_payload_key=",
          "skip_apks_with_path_prefix=",
          "default_key_mappings=",
          "key_mapping=",
          "replace_ota_keys",
          "tag_changes=",
          "replace_verity_public_key=",
          "replace_verity_private_key=",
          "replace_verity_keyid=",
          "remove_avb_public_keys=",
          "avb_apex_extra_args=",
          "avb_vbmeta_algorithm=",
          "avb_vbmeta_key=",
          "avb_vbmeta_extra_args=",
          "avb_boot_algorithm=",
          "avb_boot_key=",
          "avb_boot_extra_args=",
          "avb_dtbo_algorithm=",
          "avb_dtbo_key=",
          "avb_dtbo_extra_args=",
          "avb_system_algorithm=",
          "avb_system_key=",
          "avb_system_extra_args=",
          "avb_system_other_algorithm=",
          "avb_system_other_key=",
          "avb_system_other_extra_args=",
          "avb_vendor_algorithm=",
          "avb_vendor_key=",
          "avb_vendor_extra_args=",
          "avb_vbmeta_system_algorithm=",
          "avb_vbmeta_system_key=",
          "avb_vbmeta_system_extra_args=",
          "avb_vbmeta_vendor_algorithm=",
          "avb_vbmeta_vendor_key=",
          "avb_vbmeta_vendor_extra_args=",
          "avb_extra_custom_image_key=",
          "avb_extra_custom_image_algorithm=",
          "avb_extra_custom_image_extra_args=",
      ],
      extra_option_handler=option_handler)

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

  common.InitLogging()

  input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
  output_zip = zipfile.ZipFile(args[1], "w",
                               compression=zipfile.ZIP_DEFLATED,
                               allowZip64=True)

  misc_info = common.LoadInfoDict(input_zip)

  BuildKeyMap(misc_info, key_mapping_options)

  apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
  apk_keys = GetApkCerts(apk_keys_info)

  apex_keys_info = ReadApexKeysInfo(input_zip)
  apex_keys = GetApexKeys(apex_keys_info, apk_keys)

  # TODO(xunchang) check for the apks inside the apex files, and abort early if
  # the keys are not available.
  CheckApkAndApexKeysAvailable(
      input_zip,
      set(apk_keys.keys()) | set(apex_keys.keys()),
      compressed_extension,
      apex_keys)

  key_passwords = common.GetKeyPasswords(
      set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
  platform_api_level, _ = GetApiLevelAndCodename(input_zip)
  codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)

  ProcessTargetFiles(input_zip, output_zip, misc_info,
                     apk_keys, apex_keys, key_passwords,
                     platform_api_level, codename_to_api_level_map,
                     compressed_extension)

  common.ZipClose(input_zip)
  common.ZipClose(output_zip)

  # Skip building userdata.img and cache.img when signing the target files.
  new_args = ["--is_signing"]
  # add_img_to_target_files builds the system image from scratch, so the
  # recovery patch is guaranteed to be regenerated there.
  if OPTIONS.rebuild_recovery:
    new_args.append("--rebuild_recovery")
  new_args.append(args[1])
  add_img_to_target_files.main(new_args)

  print("done.")
Beispiel #5
0
def AddImagesToTargetFiles(filename):
  """Creates and adds images (boot/recovery/system/...) to a target_files.zip.

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

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

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

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

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

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

  # {vendor,odm,product,product_services}.img are 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,product,product_services}.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_odm = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "ODM")) or
             os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                         "odm.img")))
  has_product = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "PRODUCT")) or
                 os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                             "product.img")))
  has_product_services = (os.path.isdir(os.path.join(OPTIONS.input_tmp,
                                                     "PRODUCT_SERVICES")) or
                          os.path.exists(os.path.join(OPTIONS.input_tmp,
                                                      "IMAGES",
                                                      "product_services.img")))
  has_system_other = os.path.isdir(os.path.join(OPTIONS.input_tmp,
                                                "SYSTEM_OTHER"))

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

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

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

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

  banner("boot")
  # common.GetBootableImage() returns the image directly if present.
  boot_image = common.GetBootableImage(
      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
  # boot.img may be unavailable in some targets (e.g. aosp_arm64).
  if boot_image:
    partitions['boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
    if not os.path.exists(partitions['boot']):
      boot_image.WriteToDir(OPTIONS.input_tmp)
      if output_zip:
        boot_image.AddToZip(output_zip)

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

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

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

  if has_vendor:
    banner("vendor")
    partitions['vendor'] = AddVendor(output_zip)

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

  if has_product_services:
    banner("product_services")
    partitions['product_services'] = AddProductServices(output_zip)

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

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

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

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

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

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

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

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

    banner("vbmeta")
    AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)

  if OPTIONS.info_dict.get("lpmake_args"):
    banner("super_empty")
    AddSuperEmpty(output_zip)

    if OPTIONS.info_dict.get("dynamic_partition_retrofit") == "true":
      banner("super split images")
      AddSuperSplit(output_zip)
    # TODO(b/119322123): Add super.img to target_files for non-retrofit

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

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

    # Generate care_map.pb for ab_partitions, then write this file to
    # target_files package.
    AddCareMapForAbOta(output_zip, ab_partitions, partitions)

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

  if output_zip:
    common.ZipClose(output_zip)
    if OPTIONS.replace_updated_files_list:
      ReplaceUpdatedFiles(output_zip.filename,
                          OPTIONS.replace_updated_files_list)
def AddImagesToTargetFiles(filename):
    """Creates and adds images (boot/recovery/system/...) to a target_files.zip.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    AddApexInfo(output_zip)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    AddVbmetaDigest(output_zip)

    if output_zip:
        common.ZipClose(output_zip)
        if OPTIONS.replace_updated_files_list:
            ReplaceUpdatedFiles(output_zip.filename,
                                OPTIONS.replace_updated_files_list)
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

  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")

  def banner(s):
    print "\n\n++++ " + s + " ++++\n\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)

  banner("system")
  AddSystem(output_zip, recovery_img=recovery_image, boot_img=boot_image)
  if has_vendor:
    banner("vendor")
    AddVendor(output_zip)
  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 line in lines:
      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

  common.ZipClose(output_zip)
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.

    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")

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

    # 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
Beispiel #9
0
def AddImagesToTargetFiles(filename):
  """Creates and adds images (boot/recovery/system/...) to a target_files.zip.

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

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

  Args:
      filename: the target_files.zip, or the zip root directory.
  """
  if os.path.isdir(filename):
    OPTIONS.input_tmp = os.path.abspath(filename)
    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

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

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

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

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

  banner("boot")
  # common.GetBootableImage() returns the image directly if present.
  boot_image = common.GetBootableImage(
      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
  # boot.img may be unavailable in some targets (e.g. aosp_arm64).
  if boot_image:
    partitions['boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
    if not os.path.exists(partitions['boot']):
      boot_image.WriteToDir(OPTIONS.input_tmp)
      if output_zip:
        boot_image.AddToZip(output_zip)

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

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

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

  if has_vendor:
    banner("vendor")
    partitions['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("cache")
    AddCache(output_zip)

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

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

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

  # 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)
      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:
        img_vendor_dir = os.path.join(OPTIONS.input_tmp, "VENDOR_IMAGES")
        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 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

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

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

    def banner(s):
        print "\n\n++++ " + s + " ++++\n\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)

    banner("recovery")
    recovery_image = None
    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)

    banner("system")
    AddSystem(output_zip, recovery_img=recovery_image, boot_img=boot_image)
    if has_vendor:
        banner("vendor")
        AddVendor(output_zip)
    banner("userdata")
    AddUserdata(output_zip)
    banner("extrauserdata")
    AddUserdataExtra(output_zip)
    banner("cache")
    AddCache(output_zip)

    common.ZipClose(output_zip)
Beispiel #11
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:
    common.ZipWrite(certs_zip, k)
  common.ZipClose(certs_zip)
  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
                     temp_file.getvalue())

  return new_recovery_keys
Beispiel #12
0
def main(argv):
    bootable_only = [False]

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

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

    bootable_only = bootable_only[0]

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

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

    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 image in images:
                    if bootable_only and image not in ("boot.img",
                                                       "recovery.img"):
                        continue
                    if not image.endswith(".img"):
                        continue
                    common.ZipWrite(output_zip,
                                    os.path.join(images_path, image), image)
                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
                try:
                    input_zip.getinfo("CUSTOM/")
                    banner("AddCustom")
                    add_img_to_target_files.AddCustom(output_zip, prefix="")
                except KeyError:
                    pass  # no custom 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..."
        common.ZipClose(output_zip)
        shutil.rmtree(OPTIONS.input_tmp)

    print "done."
def main(argv):

    key_mapping_options = []

    def option_handler(o, a):
        if o in ("-e", "--extra_apks"):
            names, key = a.split("=")
            names = names.split(",")
            for n in names:
                OPTIONS.extra_apks[n] = key
        elif o in ("-d", "--default_key_mappings"):
            key_mapping_options.append((None, a))
        elif o in ("-k", "--key_mapping"):
            key_mapping_options.append(a.split("=", 1))
        elif o in ("-o", "--replace_ota_keys"):
            OPTIONS.replace_ota_keys = True
        elif o in ("-t", "--tag_changes"):
            new = []
            for i in a.split(","):
                i = i.strip()
                if not i or i[0] not in "-+":
                    raise ValueError("Bad tag change '%s'" % (i, ))
                new.append(i[0] + i[1:].strip())
            OPTIONS.tag_changes = tuple(new)
        elif o == "--replace_verity_public_key":
            OPTIONS.replace_verity_public_key = (True, a)
        elif o == "--replace_verity_private_key":
            OPTIONS.replace_verity_private_key = (True, a)
        elif o == "--replace_verity_keyid":
            OPTIONS.replace_verity_keyid = (True, a)
        elif o == "--avb_vbmeta_key":
            OPTIONS.avb_keys['vbmeta'] = a
        elif o == "--avb_vbmeta_algorithm":
            OPTIONS.avb_algorithms['vbmeta'] = a
        elif o == "--avb_vbmeta_extra_args":
            OPTIONS.avb_extra_args['vbmeta'] = a
        elif o == "--avb_boot_key":
            OPTIONS.avb_keys['boot'] = a
        elif o == "--avb_boot_algorithm":
            OPTIONS.avb_algorithms['boot'] = a
        elif o == "--avb_boot_extra_args":
            OPTIONS.avb_extra_args['boot'] = a
        elif o == "--avb_dtbo_key":
            OPTIONS.avb_keys['dtbo'] = a
        elif o == "--avb_dtbo_algorithm":
            OPTIONS.avb_algorithms['dtbo'] = a
        elif o == "--avb_dtbo_extra_args":
            OPTIONS.avb_extra_args['dtbo'] = a
        elif o == "--avb_system_key":
            OPTIONS.avb_keys['system'] = a
        elif o == "--avb_system_algorithm":
            OPTIONS.avb_algorithms['system'] = a
        elif o == "--avb_system_extra_args":
            OPTIONS.avb_extra_args['system'] = a
        elif o == "--avb_vendor_key":
            OPTIONS.avb_keys['vendor'] = a
        elif o == "--avb_vendor_algorithm":
            OPTIONS.avb_algorithms['vendor'] = a
        elif o == "--avb_vendor_extra_args":
            OPTIONS.avb_extra_args['vendor'] = a
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="e:d:k:ot:",
                               extra_long_opts=[
                                   "extra_apks=",
                                   "default_key_mappings=",
                                   "key_mapping=",
                                   "replace_ota_keys",
                                   "tag_changes=",
                                   "replace_verity_public_key=",
                                   "replace_verity_private_key=",
                                   "replace_verity_keyid=",
                                   "avb_vbmeta_algorithm=",
                                   "avb_vbmeta_key=",
                                   "avb_vbmeta_extra_args=",
                                   "avb_boot_algorithm=",
                                   "avb_boot_key=",
                                   "avb_boot_extra_args=",
                                   "avb_dtbo_algorithm=",
                                   "avb_dtbo_key=",
                                   "avb_dtbo_extra_args=",
                                   "avb_system_algorithm=",
                                   "avb_system_key=",
                                   "avb_system_extra_args=",
                                   "avb_vendor_algorithm=",
                                   "avb_vendor_key=",
                                   "avb_vendor_extra_args=",
                               ],
                               extra_option_handler=option_handler)

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

    input_zip = zipfile.ZipFile(args[0], "r")
    output_zip = zipfile.ZipFile(args[1],
                                 "w",
                                 compression=zipfile.ZIP_DEFLATED,
                                 allowZip64=True)

    misc_info = common.LoadInfoDict(input_zip)

    BuildKeyMap(misc_info, key_mapping_options)

    certmap, compressed_extension = common.ReadApkCerts(input_zip)
    apk_key_map = GetApkCerts(certmap)
    CheckAllApksSigned(input_zip, apk_key_map, compressed_extension)

    key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
    platform_api_level, _ = GetApiLevelAndCodename(input_zip)
    codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)

    ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map,
                       key_passwords, platform_api_level,
                       codename_to_api_level_map, compressed_extension)

    common.ZipClose(input_zip)
    common.ZipClose(output_zip)

    # Skip building userdata.img and cache.img when signing the target files.
    new_args = ["--is_signing"]
    # add_img_to_target_files builds the system image from scratch, so the
    # recovery patch is guaranteed to be regenerated there.
    if OPTIONS.rebuild_recovery:
        new_args.append("--rebuild_recovery")
    new_args.append(args[1])
    add_img_to_target_files.main(new_args)

    print("done.")
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

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

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

    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")

    def banner(s):
        print("\n\n++++ " + s + " ++++\n\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)

            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)
def main(argv):
    bootable_only = [False]

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

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

    bootable_only = bootable_only[0]

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

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

    try:
        done = False
        images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
        if os.path.exists(images_path):
            # If this is a new target-files, it already contains the images,
            # and all we have to do is copy them to the output zip.
            # Skip oem.img files since they are not needed in fastboot images.
            images = os.listdir(images_path)
            if images:
                for image in images:
                    if bootable_only and image not in ("boot.img",
                                                       "recovery.img"):
                        continue
                    if not image.endswith(".img"):
                        continue
                    if image == "oem.img":
                        continue
                    common.ZipWrite(output_zip,
                                    os.path.join(images_path, image), image)
                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,
                                                    OPTIONS.input_tmp)

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

            if OPTIONS.info_dict.get("no_recovery") != "true":
                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("AddUserdataExtra")
                add_img_to_target_files.AddUserdataExtra(output_zip, prefix="")
                banner("AddCache")
                add_img_to_target_files.AddCache(output_zip, prefix="")

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

    print("done.")
Beispiel #16
0
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
    # account for devices with recovery as boot
    boot_target = "recovery" if not has_recovery else "boot"

    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",
                compressor=("lzma" if boot_target in OPTIONS.lzma_targets else
                            "minigzip"))
    else:
        banner("boot")
        boot_image = common.GetBootableImage(
            "IMAGES/boot.img",
            "boot.img",
            OPTIONS.input_tmp,
            "BOOT",
            compressor=("lzma" if boot_target in OPTIONS.lzma_targets else
                        "minigzip"))
        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",
                    compressor=("lzma" if "recovery" in OPTIONS.lzma_targets
                                else "minigzip"))
        else:
            recovery_image = common.GetBootableImage(
                "IMAGES/recovery.img",
                "recovery.img",
                OPTIONS.input_tmp,
                "RECOVERY",
                compressor=("lzma" if "recovery" in OPTIONS.lzma_targets else
                            "minigzip"))
            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("cache")
        AddCache(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)
Beispiel #17
0
def main(argv):

    key_mapping_options = []

    def option_handler(o, a):
        if o in ("-e", "--extra_apks"):
            names, key = a.split("=")
            names = names.split(",")
            for n in names:
                OPTIONS.extra_apks[n] = key
        elif o in ("-d", "--default_key_mappings"):
            key_mapping_options.append((None, a))
        elif o in ("-k", "--key_mapping"):
            key_mapping_options.append(a.split("=", 1))
        elif o in ("-o", "--replace_ota_keys"):
            OPTIONS.replace_ota_keys = True
        elif o in ("-t", "--tag_changes"):
            new = []
            for i in a.split(","):
                i = i.strip()
                if not i or i[0] not in "-+":
                    raise ValueError("Bad tag change '%s'" % (i, ))
                new.append(i[0] + i[1:].strip())
            OPTIONS.tag_changes = tuple(new)
        elif o == "--replace_verity_public_key":
            OPTIONS.replace_verity_public_key = (True, a)
        elif o == "--replace_verity_private_key":
            OPTIONS.replace_verity_private_key = (True, a)
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts="e:d:k:ot:",
                               extra_long_opts=[
                                   "extra_apks=", "default_key_mappings=",
                                   "key_mapping=", "replace_ota_keys",
                                   "tag_changes=",
                                   "replace_verity_public_key=",
                                   "replace_verity_private_key="
                               ],
                               extra_option_handler=option_handler)

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

    input_zip = zipfile.ZipFile(args[0], "r")
    output_zip = zipfile.ZipFile(args[1], "w")

    misc_info = common.LoadInfoDict(input_zip)

    BuildKeyMap(misc_info, key_mapping_options)

    apk_key_map = GetApkCerts(input_zip)
    CheckAllApksSigned(input_zip, apk_key_map)

    key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
    ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map,
                       key_passwords)

    common.ZipClose(input_zip)
    common.ZipClose(output_zip)

    add_img_to_target_files.AddImagesToTargetFiles(args[1])

    print "done."
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)

  has_vendor = os.path.isdir(os.path.join(OPTIONS.input_tmp, "VENDOR"))
  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")

  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("cache")
    AddCache(output_zip)
  if OPTIONS.info_dict.get("board_bpt_enable", None) == "true":
    banner("partition-table")
    AddPartitionTable(output_zip)
  if OPTIONS.info_dict.get("board_avb_enable", None) == "true":
    banner("vbmeta")
    boot_contents = boot_image.WriteToTemp()
    AddVBMeta(output_zip, boot_contents.name, system_img_path)

  # 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 OPTIONS.info_dict.get(
          "system_verity_block_device", None) is not None:
        assert os.path.exists(system_img_path)
        care_map_list += GetCareMap("system", system_img_path)
      if line.strip() == "vendor" and OPTIONS.info_dict.get(
          "vendor_verity_block_device", None) is not None:
        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:
      file_path = "META/care_map.txt"
      if output_zip:
        common.ZipWriteStr(output_zip, file_path, '\n'.join(care_map_list))
      else:
        with open(os.path.join(OPTIONS.input_tmp, file_path), 'w') as fp:
          fp.write('\n'.join(care_map_list))

  if output_zip:
    common.ZipClose(output_zip)
def SignApex(avbtool,
             apex_data,
             payload_key,
             container_key,
             container_pw,
             apk_keys,
             codename_to_api_level_map,
             no_hashtree,
             signing_args=None):
    """Signs the current APEX with the given payload/container keys.

  Args:
    apex_data: Raw APEX data.
    payload_key: The path to payload signing key (w/ extension).
    container_key: The path to container signing key (w/o extension).
    container_pw: The matching password of the container_key, or None.
    apk_keys: A dict that holds the signing keys for apk files.
    codename_to_api_level_map: A dict that maps from codename to API level.
    no_hashtree: Don't include hashtree in the signed APEX.
    signing_args: Additional args to be passed to the payload signer.

  Returns:
    The path to the signed APEX file.
  """
    apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
    with open(apex_file, 'wb') as apex_fp:
        apex_fp.write(apex_data)

    APEX_PAYLOAD_IMAGE = 'apex_payload.img'
    APEX_PUBKEY = 'apex_pubkey'

    # 1. Extract the apex payload image and sign the containing apk files. Repack
    # the apex file after signing.
    payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
    apk_signer = ApexApkSigner(apex_file, container_pw,
                               codename_to_api_level_map)
    apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key,
                                           payload_public_key, signing_args)

    # 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
    # payload_key.
    payload_dir = common.MakeTempDir(prefix='apex-payload-')
    with zipfile.ZipFile(apex_file) as apex_fd:
        payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)
        zip_items = apex_fd.namelist()

    payload_info = ParseApexPayloadInfo(avbtool, payload_file)
    SignApexPayload(avbtool, payload_file, payload_key,
                    payload_info['apex.key'], payload_info['Algorithm'],
                    payload_info['Salt'], no_hashtree, signing_args)

    # 2b. Update the embedded payload public key.

    common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
    if APEX_PUBKEY in zip_items:
        common.ZipDelete(apex_file, APEX_PUBKEY)
    apex_zip = zipfile.ZipFile(apex_file, 'a')
    common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
    common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
    common.ZipClose(apex_zip)

    # 3. Align the files at page boundary (same as in apexer).
    aligned_apex = common.MakeTempFile(prefix='apex-container-',
                                       suffix='.apex')
    common.RunAndCheckOutput(
        ['zipalign', '-f', '4096', apex_file, aligned_apex])

    # 4. Sign the APEX container with container_key.
    signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')

    # Specify the 4K alignment when calling SignApk.
    extra_signapk_args = OPTIONS.extra_signapk_args[:]
    extra_signapk_args.extend(['-a', '4096'])

    common.SignFile(aligned_apex,
                    signed_apex,
                    container_key,
                    container_pw,
                    codename_to_api_level_map=codename_to_api_level_map,
                    extra_signapk_args=extra_signapk_args)

    return signed_apex
def main(argv):

  key_mapping_options = []

  def option_handler(o, a):
    if o in ("-e", "--extra_apks"):
      names, key = a.split("=")
      names = names.split(",")
      for n in names:
        OPTIONS.extra_apks[n] = key
    elif o in ("-d", "--default_key_mappings"):
      key_mapping_options.append((None, a))
    elif o in ("-k", "--key_mapping"):
      key_mapping_options.append(a.split("=", 1))
    elif o in ("-o", "--replace_ota_keys"):
      OPTIONS.replace_ota_keys = True
    elif o in ("-t", "--tag_changes"):
      new = []
      for i in a.split(","):
        i = i.strip()
        if not i or i[0] not in "-+":
          raise ValueError("Bad tag change '%s'" % (i,))
        new.append(i[0] + i[1:].strip())
      OPTIONS.tag_changes = tuple(new)
    elif o == "--replace_verity_public_key":
      OPTIONS.replace_verity_public_key = (True, a)
    elif o == "--replace_verity_private_key":
      OPTIONS.replace_verity_private_key = (True, a)
    elif o == "--replace_verity_keyid":
      OPTIONS.replace_verity_keyid = (True, a)
    else:
      return False
    return True

  args = common.ParseOptions(argv, __doc__,
                             extra_opts="e:d:k:ot:",
                             extra_long_opts=["extra_apks=",
                                              "default_key_mappings=",
                                              "key_mapping=",
                                              "replace_ota_keys",
                                              "tag_changes=",
                                              "replace_verity_public_key=",
                                              "replace_verity_private_key=",
                                              "replace_verity_keyid="],
                             extra_option_handler=option_handler)

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

  input_zip = zipfile.ZipFile(args[0], "r")
  output_zip = zipfile.ZipFile(args[1], "w")

  misc_info = common.LoadInfoDict(input_zip)

  BuildKeyMap(misc_info, key_mapping_options)

  apk_key_map = GetApkCerts(input_zip)
  CheckAllApksSigned(input_zip, apk_key_map)

  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
  platform_api_level, platform_codename = GetApiLevelAndCodename(input_zip)
  codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
  # Android N will be API Level 24, but isn't yet.
  # TODO: Remove this workaround once Android N is officially API Level 24.
  if platform_api_level == 23 and platform_codename == "N":
    platform_api_level = 24

  ProcessTargetFiles(input_zip, output_zip, misc_info,
                     apk_key_map, key_passwords,
                     platform_api_level,
                     codename_to_api_level_map)

  common.ZipClose(input_zip)
  common.ZipClose(output_zip)

  # Skip building userdata.img and cache.img when signing the target files.
  new_args = ["--is_signing", args[1]]
  add_img_to_target_files.main(new_args)

  print "done."