Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 853cd306 authored by Michael Schwartz's avatar Michael Schwartz
Browse files

Add compatibility metadata to OTA package

Store the metadata in a archive within the OTA package so the collection
can be retrieved as a single unit by the device.

Bug: 36810913
Test: `make dist` marlin (ab) and angler (non-AB) for incremental and full OTA.
Change-Id: I94118e48a3c6ed5ff890b67d7dafbca02346aeea
parent ceeaa7be
Loading
Loading
Loading
Loading
+91 −2
Original line number Diff line number Diff line
@@ -316,6 +316,59 @@ def GetImage(which, tmpdir):
  return sparse_img.SparseImage(path, mappath, clobbered_blocks)


def AddCompatibilityArchive(target_zip, output_zip, system_included=True,
                            vendor_included=True):
  """Adds compatibility info from target files into the output zip.

  Metadata used for on-device compatibility verification is retrieved from
  target_zip then added to compatibility.zip which is added to the output_zip
  archive.

  Compatibility archive should only be included for devices with a vendor
  partition as checking provides value when system and vendor are independently
  versioned.

  Args:
    target_zip: Zip file containing the source files to be included for OTA.
    output_zip: Zip file that will be sent for OTA.
    system_included: If True, the system image will be updated and therefore
        its metadata should be included.
    vendor_included: If True, the vendor image will be updated and therefore
        its metadata should be included.
  """

  # Determine what metadata we need. Files are names relative to META/.
  compatibility_files = []
  vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
  system_metadata = ("system_manifest.xml", "system_matrix.xml")
  if vendor_included:
    compatibility_files += vendor_metadata
  if system_included:
    compatibility_files += system_metadata

  # Create new archive.
  compatibility_archive = tempfile.NamedTemporaryFile()
  compatibility_archive_zip = zipfile.ZipFile(compatibility_archive, "w",
      compression=zipfile.ZIP_DEFLATED)

  # Add metadata.
  for file_name in compatibility_files:
    target_file_name = "META/" + file_name

    if target_file_name in target_zip.namelist():
      data = target_zip.read(target_file_name)
      common.ZipWriteStr(compatibility_archive_zip, file_name, data)

  # Ensure files are written before we copy into output_zip.
  compatibility_archive_zip.close()

  # Only add the archive if we have any compatibility info.
  if compatibility_archive_zip.namelist():
    common.ZipWrite(output_zip, compatibility_archive.name,
                    arcname="compatibility.zip",
                    compress_type=zipfile.ZIP_STORED)


def WriteFullOTAPackage(input_zip, output_zip):
  # TODO: how to determine this?  We don't know what version it will
  # be installed on top of. For now, we expect the API just won't
@@ -446,6 +499,8 @@ else if get_stage("%(bcb_dev)s") == "3/3" then
    vendor_diff = common.BlockDifference("vendor", vendor_tgt)
    vendor_diff.WriteScript(script, output_zip)

    AddCompatibilityArchive(input_zip, output_zip)

  common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)

@@ -632,6 +687,10 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
                                         check_first_block,
                                         version=blockimgdiff_version,
                                         disable_imgdiff=disable_imgdiff)

    AddCompatibilityArchive(target_zip, output_zip,
                            system_src.TotalSha1() != system_tgt.TotalSha1(),
                            vendor_src.TotalSha1() != vendor_tgt.TotalSha1())
  else:
    vendor_diff = None

@@ -943,6 +1002,9 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
    if 'care_map.txt' in zip_file.namelist():
      offsets.append(ComputeEntryOffsetSize('care_map.txt'))

    if 'compatibility.zip' in zip_file.namelist():
      offsets.append(ComputeEntryOffsetSize('compatibility.zip'))

    # 'META-INF/com/android/metadata' is required. We don't know its actual
    # offset and length (as well as the values for other entries). So we
    # reserve 10-byte as a placeholder, which is to cover the space for metadata
@@ -1114,8 +1176,8 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,

  # If dm-verity is supported for the device, copy contents of care_map
  # into A/B OTA package.
  if OPTIONS.info_dict.get("verity") == "true":
  target_zip = zipfile.ZipFile(target_file, "r")
  if OPTIONS.info_dict.get("verity") == "true":
    care_map_path = "META/care_map.txt"
    namelist = target_zip.namelist()
    if care_map_path in namelist:
@@ -1124,6 +1186,33 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
          compress_type=zipfile.ZIP_STORED)
    else:
      print("Warning: cannot find care map file in target_file package")

  if HasVendorPartition(target_zip):
    update_vendor = True
    update_system = True

    # If incremental then figure out what is being updated so metadata only for
    # the updated image is included.
    if source_file is not None:
      input_tmp, input_zip = common.UnzipTemp(
          target_file, UNZIP_PATTERN)
      source_tmp, source_zip = common.UnzipTemp(
          source_file, UNZIP_PATTERN)

      vendor_src = GetImage("vendor", source_tmp)
      vendor_tgt = GetImage("vendor", input_tmp)
      system_src = GetImage("system", source_tmp)
      system_tgt = GetImage("system", input_tmp)

      update_system = system_src.TotalSha1() != system_tgt.TotalSha1()
      update_vendor = vendor_src.TotalSha1() != vendor_tgt.TotalSha1()

      input_zip.close()
      source_zip.close()

    target_zip = zipfile.ZipFile(target_file, "r")
    AddCompatibilityArchive(target_zip, output_zip, update_system,
                            update_vendor)
  common.ZipClose(target_zip)

  # Write the current metadata entry with placeholders.