def test_AddCareMapForAbOta_zipOutput_careMapEntryExists(self):
    """Tests the case with ZIP output which already has care_map entry."""
    image_paths = self._test_AddCareMapForAbOta()

    output_file = common.MakeTempFile(suffix='.zip')
    with zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip:
      # Create an existing META/care_map.pb entry.
      common.ZipWriteStr(output_zip, 'META/care_map.pb',
                         'fake care_map.pb')

      # Request to add META/care_map.pb again.
      AddCareMapForAbOta(output_zip, ['system', 'vendor'], image_paths)

    # The one under OPTIONS.input_tmp must have been replaced.
    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.fingerprint",
                "google/sailfish/678:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)

    # The existing entry should be scheduled to be replaced.
    self.assertIn('META/care_map.pb', OPTIONS.replace_updated_files_list)
  def test_AddCareMapForAbOta_withThumbprint(self):
    """Tests the case for partitions with thumbprint."""
    image_paths = self._test_AddCareMapForAbOta()
    OPTIONS.info_dict = {
        'extfs_sparse_flag': '-s',
        'system_image_size': 65536,
        'vendor_image_size': 40960,
        'system_verity_block_device': '/dev/block/system',
        'vendor_verity_block_device': '/dev/block/vendor',
        'system.build.prop': common.PartitionBuildProps.FromDictionary(
            'system', {
                'ro.system.build.thumbprint':
                'google/sailfish/123:user/dev-keys'}
        ),
        'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
            'vendor', {
                'ro.vendor.build.thumbprint':
                'google/sailfish/456:user/dev-keys'}
        ),
    }

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.thumbprint",
                "google/sailfish/123:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.thumbprint",
                "google/sailfish/456:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta_withAvb(self):
    """Tests the case for device using AVB."""
    image_paths = self._test_AddCareMapForAbOta()
    OPTIONS.info_dict = {
        'extfs_sparse_flag': '-s',
        'system_image_size': 65536,
        'vendor_image_size': 40960,
        'avb_system_hashtree_enable': 'true',
        'avb_vendor_hashtree_enable': 'true',
        'system.build.prop': common.PartitionBuildProps.FromDictionary(
            'system', {
                'ro.system.build.fingerprint':
                'google/sailfish/12345:user/dev-keys'}
        ),
        'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
            'vendor', {
                'ro.vendor.build.fingerprint':
                'google/sailfish/678:user/dev-keys'}
        ),
    }

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.fingerprint",
                "google/sailfish/678:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta_verityNotEnabled(self):
    """No care_map.pb should be generated if verity not enabled."""
    image_paths = self._test_AddCareMapForAbOta()
    OPTIONS.info_dict = {}
    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    self.assertFalse(os.path.exists(care_map_file))
  def test_AddCareMapForAbOta_skipAllPartitions(self):
    image_paths = self._test_AddCareMapForAbOta()

    # Remove the image_size properties for all the partitions.
    del OPTIONS.info_dict['system_image_size']
    del OPTIONS.info_dict['vendor_image_size']

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    self.assertFalse(os.path.exists(care_map_file))
  def test_AddCareMapForAbOta_skipPartition(self):
    image_paths = self._test_AddCareMapForAbOta()

    # Remove vendor_image_size to invalidate the care_map for vendor.img.
    del OPTIONS.info_dict['vendor_image_size']

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta(self):
    image_paths = self._test_AddCareMapForAbOta()

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.fingerprint",
                "google/sailfish/678:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta_withNonCareMapPartitions(self):
    """Partitions without care_map should be ignored."""
    image_paths = self._test_AddCareMapForAbOta()

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(
        care_map_file, ['boot', 'system', 'vendor', 'vbmeta'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.fingerprint",
                "google/sailfish/678:user/dev-keys"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta_noFingerprint(self):
    """Tests the case for partitions without fingerprint."""
    image_paths = self._test_AddCareMapForAbOta()
    OPTIONS.info_dict = {
        'extfs_sparse_flag' : '-s',
        'system_image_size' : 65536,
        'vendor_image_size' : 40960,
        'system_verity_block_device': '/dev/block/system',
        'vendor_verity_block_device': '/dev/block/vendor',
    }

    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
    AddCareMapForAbOta(care_map_file, ['system', 'vendor'], image_paths)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), "unknown",
                "unknown", 'vendor', RangeSet("0-9").to_string_raw(), "unknown",
                "unknown"]

    self._verifyCareMap(expected, care_map_file)
  def test_AddCareMapForAbOta_zipOutput(self):
    """Tests the case with ZIP output."""
    image_paths = self._test_AddCareMapForAbOta()

    output_file = common.MakeTempFile(suffix='.zip')
    with zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip:
      AddCareMapForAbOta(output_zip, ['system', 'vendor'], image_paths)

    care_map_name = "META/care_map.pb"
    temp_dir = common.MakeTempDir()
    with zipfile.ZipFile(output_file, 'r', allowZip64=True) as verify_zip:
      self.assertTrue(care_map_name in verify_zip.namelist())
      verify_zip.extract(care_map_name, path=temp_dir)

    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
                "ro.system.build.fingerprint",
                "google/sailfish/12345:user/dev-keys",
                'vendor', RangeSet("0-9").to_string_raw(),
                "ro.vendor.build.fingerprint",
                "google/sailfish/678:user/dev-keys"]
    self._verifyCareMap(expected, os.path.join(temp_dir, care_map_name))
Exemplo n.º 11
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"
    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())

    # Calculate the vbmeta digest and put the result in to META/
    boot_images = OPTIONS.info_dict.get("boot_images")
    # Disable the digest calculation if the target_file is used as a container
    # for boot images.
    boot_container = boot_images and len(boot_images.split()) >= 2
    if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container
            and OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"):
        avbtool = OPTIONS.info_dict["avb_avbtool"]
        digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool)
        vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META",
                                         "vbmeta_digest.txt")
        with open(vbmeta_digest_txt, 'w') as f:
            f.write(digest)

    if output_zip:
        common.ZipClose(output_zip)
        if OPTIONS.replace_updated_files_list:
            ReplaceUpdatedFiles(output_zip.filename,
                                OPTIONS.replace_updated_files_list)