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

Commit 307dbb62 authored by David Anderson's avatar David Anderson
Browse files

Remove retrofit dynamic partition support from otatools.

Bug: 406251416
Test: m otapackage
      m dist
      m target-files-package
Change-Id: I68b2cbbd750f6b670c0c812f3556301f0921ac35
parent ef1e7c0e
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -1146,12 +1146,6 @@ def AddImagesToTargetFiles(filename):
      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")
+6 −18
Original line number Diff line number Diff line
@@ -30,11 +30,9 @@ input_file: one of the following:
      and super split images), a list of "*_image" should be paths of each
      source images.

output_dir_or_file:
    If a single super image is built (for super_empty.img, or super.img for
output_file:
    If a super image is built (for super_empty.img, or super.img for
    launch devices), this argument is the output file.
    If a collection of split images are built (for retrofit devices), this
    argument is the output directory.
"""

from __future__ import print_function
@@ -77,19 +75,14 @@ def BuildSuperImageFromDict(info_dict, output):

  ab_update = info_dict.get("ab_update") == "true"
  virtual_ab = info_dict.get("virtual_ab") == "true"
  retrofit = info_dict.get("dynamic_partition_retrofit") == "true"
  block_devices = shlex.split(info_dict.get("super_block_devices", "").strip())
  groups = shlex.split(info_dict.get("super_partition_groups", "").strip())

  if ab_update and retrofit:
    cmd += ["--metadata-slots", "2"]
  elif ab_update:
  if ab_update:
    cmd += ["--metadata-slots", "3"]
  else:
    cmd += ["--metadata-slots", "2"]

  if ab_update and retrofit:
    cmd.append("--auto-slot-suffixing")
  if virtual_ab:
    cmd.append("--virtual-ab")

@@ -97,11 +90,10 @@ def BuildSuperImageFromDict(info_dict, output):
    size = info_dict["super_{}_device_size".format(device)]
    cmd += ["--device", "{}:{}".format(device, size)]

  append_suffix = ab_update and not retrofit
  has_image = False
  for group in groups:
    group_size = info_dict["super_{}_group_size".format(group)]
    if append_suffix:
    if ab_update:
      cmd += ["--group", "{}_a:{}".format(group, group_size),
              "--group", "{}_b:{}".format(group, group_size)]
    else:
@@ -115,7 +107,7 @@ def BuildSuperImageFromDict(info_dict, output):
      if image:
        has_image = True

      if not append_suffix:
      if not ab_update:
        cmd += GetArgumentsForImage(partition, group, image)
        continue

@@ -139,11 +131,7 @@ def BuildSuperImageFromDict(info_dict, output):

  common.RunAndCheckOutput(cmd)

  if retrofit and has_image:
    logger.info("Done writing images to directory %s", output)
  else:
  logger.info("Done writing image %s", output)

  return True


+1 −17
Original line number Diff line number Diff line
@@ -105,15 +105,12 @@ class DeviceType(object):
# Dynamic partition feature flags
class Dap(object):
  NONE = 0
  RDAP = 1
  DAP = 2
  DAP = 1

  @staticmethod
  def Get(info_dict):
    if info_dict.get("use_dynamic_partitions") != "true":
      return Dap.NONE
    if info_dict.get("dynamic_partition_retrofit") == "true":
      return Dap.RDAP
    return Dap.DAP


@@ -176,13 +173,6 @@ class DynamicPartitionSizeChecker(object):
      raise RuntimeError("check_partition_sizes should only be executed on "
                         "builds with dynamic partitions enabled")

    # Retrofit dynamic partitions: 1 slot per "super", 2 "super"s on the device
    if dap == Dap.RDAP:
      if slot != DeviceType.AB:
        raise RuntimeError("Device with retrofit dynamic partitions must use "
                           "regular (non-Virtual) A/B")
      return 1

    # Launch DAP: 1 super on the device
    assert dap == Dap.DAP

@@ -250,10 +240,6 @@ class DynamicPartitionSizeChecker(object):
      max_size = Expression(
          "BOARD_SUPER_PARTITION_SIZE{}".format(size_limit_suffix),
          int(info_dict["super_partition_size"]) // num_slots)
      # Retrofit DAP will build metadata as part of super image.
      if Dap.Get(info_dict) == Dap.RDAP:
        sum_size.CheckLe(max_size)
        return

      sum_size.CheckLt(max_size)
      # Display a warning if group size + 1M >= super size
@@ -267,8 +253,6 @@ class DynamicPartitionSizeChecker(object):

  def Run(self):
    self._CheckAllPartitionSizes()
    if self.info_dict.get("dynamic_partition_retrofit") == "true":
      self._CheckSuperPartitionSize()


def CheckPartitionSizes(inp):
+2 −27
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ OPTIONS.put_super = None
OPTIONS.put_bootloader = None
OPTIONS.dynamic_partition_list = None
OPTIONS.super_device_list = None
OPTIONS.retrofit_dap = None
OPTIONS.build_super = None
OPTIONS.sparse_userimages = None
OPTIONS.use_fastboot_info = True
@@ -83,7 +82,6 @@ def LoadOptions(input_file):
                                            '').strip().split()
  OPTIONS.super_device_list = info.get('super_block_devices',
                                       '').strip().split()
  OPTIONS.retrofit_dap = info.get('dynamic_partition_retrofit') == 'true'
  OPTIONS.build_super = info.get('build_super_partition') == 'true'
  OPTIONS.sparse_userimages = bool(info.get('extfs_sparse_flag'))

@@ -122,7 +120,7 @@ def EntriesForUserImages(input_file):
  dynamic_images = [p + '.img' for p in OPTIONS.dynamic_partition_list]

  # Filter out system_other for launch DAP devices because it is in super image.
  if not OPTIONS.retrofit_dap and 'system' in OPTIONS.dynamic_partition_list:
  if 'system' in OPTIONS.dynamic_partition_list:
    dynamic_images.append('system_other.img')

  entries = [
@@ -167,24 +165,6 @@ def EntriesForUserImages(input_file):
  return entries


def EntriesForSplitSuperImages(input_file):
  """Returns the entries for split super images.

  This is only done for retrofit dynamic partition devices.

  Args:
    input_file: Path to the input target_files zip file.
  """
  with zipfile.ZipFile(input_file) as input_zip:
    namelist = input_zip.namelist()
  entries = []
  for device in OPTIONS.super_device_list:
    image = 'OTA/super_{}.img'.format(device)
    assert image in namelist, 'Failed to find {}'.format(image)
    entries.append('{}:{}'.format(image, os.path.basename(image)))
  return entries


def RebuildAndWriteSuperImages(input_file, output_file):
  """Builds and writes super images to the output file."""
  logger.info('Building super image...')
@@ -233,13 +213,8 @@ def ImgFromTargetFiles(input_file, output_file):
  # Entries to be copied into the output file.
  entries = EntriesForUserImages(input_file)

  # Only for devices that retrofit dynamic partitions there're split super
  # images available in the target_files.zip.
  rebuild_super = False
  if OPTIONS.build_super and OPTIONS.put_super:
    if OPTIONS.retrofit_dap:
      entries += EntriesForSplitSuperImages(input_file)
    else:
    rebuild_super = True

  # Any additional entries provided by caller.
+6 −100
Original line number Diff line number Diff line
@@ -64,13 +64,6 @@ Common options that apply to both of non-A/B and A/B OTAs
      Generate an OTA package that will wipe the user data partition when
      installed.

  --retrofit_dynamic_partitions
      Generates an OTA package that updates a device to support dynamic
      partitions (default False). This flag is implied when generating
      an incremental OTA where the base build does not support dynamic
      partitions but the target build does. For A/B, when this flag is set,
      --skip_postinstall is implied.

  --skip_compatibility_check
      Skip checking compatibility of the input target files package.

@@ -353,7 +346,6 @@ AB_PARTITIONS = 'META/ab_partitions.txt'
TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
                                'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*',
                                'VENDOR_DLKM/*', 'ODM_DLKM/*', 'SYSTEM_DLKM/*']
RETROFIT_DAP_UNZIP_PATTERN = ['OTA/super_*.img', AB_PARTITIONS]

# Images to be excluded from secondary payload. We essentially only keep
# 'system_other' and bootloader partitions.
@@ -693,77 +685,6 @@ def GetTargetFilesZipForPartialUpdates(input_file, ab_partitions):
  return input_file


def GetTargetFilesZipForRetrofitDynamicPartitions(input_file,
                                                  super_block_devices,
                                                  dynamic_partition_list):
  """Returns a target-files.zip for retrofitting dynamic partitions.

  This allows brillo_update_payload to generate an OTA based on the exact
  bits on the block devices. Postinstall is disabled.

  Args:
    input_file: The input target-files.zip filename.
    super_block_devices: The list of super block devices
    dynamic_partition_list: The list of dynamic partitions

  Returns:
    The filename of target-files.zip with *.img replaced with super_*.img for
    each block device in super_block_devices.
  """
  assert super_block_devices, "No super_block_devices are specified."

  replace = {'OTA/super_{}.img'.format(dev): 'IMAGES/{}.img'.format(dev)
             for dev in super_block_devices}

  # Remove partitions from META/ab_partitions.txt that is in
  # dynamic_partition_list but not in super_block_devices so that
  # brillo_update_payload won't generate update for those logical partitions.
  ab_partitions_lines = common.ReadFromInputFile(
      input_file, AB_PARTITIONS).split("\n")
  ab_partitions = [line.strip() for line in ab_partitions_lines]
  # Assert that all super_block_devices are in ab_partitions
  super_device_not_updated = [partition for partition in super_block_devices
                              if partition not in ab_partitions]
  assert not super_device_not_updated, \
      "{} is in super_block_devices but not in {}".format(
          super_device_not_updated, AB_PARTITIONS)
  # ab_partitions -= (dynamic_partition_list - super_block_devices)
  to_delete = [AB_PARTITIONS]

  # Always skip postinstall for a retrofit update.
  to_delete += [POSTINSTALL_CONFIG]

  # Delete dynamic_partitions_info.txt so that brillo_update_payload thinks this
  # is a regular update on devices without dynamic partitions support.
  to_delete += [DYNAMIC_PARTITION_INFO]

  # Remove the existing partition images as well as the map files.
  to_delete += list(replace.values())
  to_delete += ['IMAGES/{}.map'.format(dev) for dev in super_block_devices]
  for item in to_delete:
    os.unlink(os.path.join(input_file, item))

  # Write super_{foo}.img as {foo}.img.
  for src, dst in replace.items():
    assert DoesInputFileContain(input_file, src), \
        'Missing {} in {}; {} cannot be written'.format(src, input_file, dst)
    source_path = os.path.join(input_file, *src.split("/"))
    target_path = os.path.join(input_file, *dst.split("/"))
    os.rename(source_path, target_path)

  # Write new ab_partitions.txt file
  new_ab_partitions = os.path.join(input_file, AB_PARTITIONS)
  with open(new_ab_partitions, 'w') as f:
    for partition in ab_partitions:
      if (partition in dynamic_partition_list and
              partition not in super_block_devices):
        logger.info("Dropping %s from ab_partitions.txt", partition)
        continue
      f.write(partition + "\n")

  return input_file


def GetTargetFilesZipForCustomImagesUpdates(input_file, custom_images: dict):
  """Returns a target-files.zip for custom partitions update.

@@ -1045,11 +966,7 @@ def GenerateAbOtaPackage(target_file, output_file, source_file=None):
    target_file = GetTargetFilesZipForCustomImagesUpdates(
        target_file, OPTIONS.custom_images)

  if OPTIONS.retrofit_dynamic_partitions:
    target_file = GetTargetFilesZipForRetrofitDynamicPartitions(
        target_file, target_info.get("super_block_devices").strip().split(),
        target_info.get("dynamic_partition_list").strip().split())
  elif OPTIONS.partial:
  if OPTIONS.partial:
    target_file = GetTargetFilesZipForPartialUpdates(target_file,
                                                     OPTIONS.partial)
  if vabc_compression_param != target_info.vabc_compression_param:
@@ -1266,7 +1183,7 @@ def main(argv):
    elif o == "--skip_postinstall":
      OPTIONS.skip_postinstall = True
    elif o == "--retrofit_dynamic_partitions":
      OPTIONS.retrofit_dynamic_partitions = True
      raise ValueError("Retrofit dynamic partitions is no longer supported")
    elif o == "--skip_compatibility_check":
      OPTIONS.skip_compatibility_check = True
    elif o == "--output_metadata_path":
@@ -1372,7 +1289,6 @@ def main(argv):
                                 "log_diff=",
                                 "extracted_input_target_files=",
                                 "skip_postinstall",
                                 "retrofit_dynamic_partitions",
                                 "skip_compatibility_check",
                                 "output_metadata_path=",
                                 "disable_fec_computation",
@@ -1429,7 +1345,7 @@ def main(argv):
  if OPTIONS.incremental_source is None and OPTIONS.downgrade:
    raise ValueError("Cannot generate downgradable full OTAs")

  # TODO(xunchang) for retrofit and partial updates, maybe we should rebuild the
  # TODO(xunchang) for partial updates, maybe we should rebuild the
  # target-file and reload the info_dict. So the info will be consistent with
  # the modified target-file.

@@ -1459,22 +1375,12 @@ def main(argv):
  # Load OEM dicts if provided.
  OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)

  # Assume retrofitting dynamic partitions when base build does not set
  # use_dynamic_partitions but target build does.
  if (OPTIONS.source_info_dict and
      OPTIONS.source_info_dict.get("use_dynamic_partitions") != "true" and
          OPTIONS.target_info_dict.get("use_dynamic_partitions") == "true"):
    if OPTIONS.target_info_dict.get("dynamic_partition_retrofit") != "true":
    logger.error("Retrofitting dynamic partitions is no longer supported.")
    raise common.ExternalError(
          "Expect to generate incremental OTA for retrofitting dynamic "
          "partitions, but dynamic_partition_retrofit is not set in target "
          "build.")
    logger.info("Implicitly generating retrofit incremental OTA.")
    OPTIONS.retrofit_dynamic_partitions = True

  # Skip postinstall for retrofitting dynamic partitions.
  if OPTIONS.retrofit_dynamic_partitions:
    OPTIONS.skip_postinstall = True
        "Both source and target builds must have dynamic partition support")

  ab_update = OPTIONS.info_dict.get("ab_update") == "true"
  allow_non_ab = OPTIONS.info_dict.get("allow_non_ab") == "true"
Loading