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

Commit 37bc304a authored by Kelvin Zhang's avatar Kelvin Zhang
Browse files

Allow build_image.py to build vbmeta partition

Cuttlefish needs to rebuild vbmeta at runtime, instead of duplicating
logic in cuttlefish tooling, re-use these logic in release tools.

Test: build_image $OUT misc_info.txt /tmp/vbmeta.img /tmp/otatols
Bug: 149866755
Change-Id: I2050f9e2dd7eed9b81a49a8442ec199147041d20
parent b1cf7a7e
Loading
Loading
Loading
Loading
+71 −7
Original line number Diff line number Diff line
@@ -232,11 +232,13 @@ def CheckHeadroom(ext4fs_output, prop_dict):
            mount_point, total_blocks, used_blocks, headroom_blocks,
            adjusted_blocks))


def CalculateSizeAndReserved(prop_dict, size):
  fs_type = prop_dict.get("fs_type", "")
  partition_headroom = int(prop_dict.get("partition_headroom", 0))
  # If not specified, give us 16MB margin for GetDiskUsage error ...
  reserved_size = int(prop_dict.get("partition_reserved_size", BYTES_IN_MB * 16))
  reserved_size = int(prop_dict.get(
      "partition_reserved_size", BYTES_IN_MB * 16))

  if fs_type == "erofs":
    reserved_size = int(prop_dict.get("partition_reserved_size", 0))
@@ -249,6 +251,7 @@ def CalculateSizeAndReserved(prop_dict, size):

  return size + reserved_size


def BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config):
  """Builds a pure image for the files under in_dir and writes it to out_file.

@@ -522,7 +525,8 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
    # If partition_size is not defined, use output of `du' + reserved_size.
    # For compressed file system, it's better to use the compressed size to avoid wasting space.
    if fs_type.startswith("erofs"):
      mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
      mkfs_output = BuildImageMkfs(
          in_dir, prop_dict, out_file, target_out, fs_config)
      if "erofs_sparse_flag" in prop_dict and not disable_sparse:
        image_path = UnsparseImage(out_file, replace=False)
        size = GetDiskUsage(image_path)
@@ -612,7 +616,8 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
    prop_dict["image_size"] = str(max_image_size)

  if not mkfs_output:
    mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
    mkfs_output = BuildImageMkfs(
        in_dir, prop_dict, out_file, target_out, fs_config)

  # Update the image (eg filesystem size). This can be different eg if mkfs
  # rounds the requested size down due to alignment.
@@ -629,6 +634,7 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
  if verity_image_builder:
    verity_image_builder.Build(out_file)


def ImagePropFromGlobalDict(glob_dict, mount_point):
  """Build an image property dictionary from the global dictionary.

@@ -793,6 +799,7 @@ def LoadGlobalDict(filename):

def GlobalDictFromImageProp(image_prop, mount_point):
  d = {}

  def copy_prop(src_p, dest_p):
    if src_p in image_prop:
      d[dest_p] = image_prop[src_p]
@@ -820,6 +827,56 @@ def GlobalDictFromImageProp(image_prop, mount_point):
  return d


def BuildVBMeta(in_dir, glob_dict, output_path):
  """Creates a VBMeta image.

  It generates the requested VBMeta image. The requested image could be for
  top-level or chained VBMeta image, which is determined based on the name.

  Args:
    output_path: Path to generated vbmeta.img
    partitions: A dict that's keyed by partition names with image paths as
        values. Only valid partition names are accepted, as partitions listed
        in common.AVB_PARTITIONS and custom partitions listed in
        OPTIONS.info_dict.get("avb_custom_images_partition_list")
    name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
    needed_partitions: Partitions whose descriptors should be included into the
        generated VBMeta image.

  Returns:
    Path to the created image.

  Raises:
    AssertionError: On invalid input args.
  """
  vbmeta_partitions = common.AVB_PARTITIONS[:]
  name = os.path.basename(output_path).rstrip(".img")
  vbmeta_system = glob_dict.get("avb_vbmeta_system", "").strip()
  vbmeta_vendor = glob_dict.get("avb_vbmeta_vendor", "").strip()
  if "vbmeta_system" in name:
    vbmeta_partitions = vbmeta_system.split()
  elif "vbmeta_vendor" in name:
    vbmeta_partitions = vbmeta_vendor.split()
  else:
    if vbmeta_system:
      vbmeta_partitions = [
          item for item in vbmeta_partitions
          if item not in vbmeta_system.split()]
      vbmeta_partitions.append("vbmeta_system")

    if vbmeta_vendor:
      vbmeta_partitions = [
          item for item in vbmeta_partitions
          if item not in vbmeta_vendor.split()]
      vbmeta_partitions.append("vbmeta_vendor")


  partitions = {part: os.path.join(in_dir, part + ".img")
                for part in vbmeta_partitions}
  partitions = {part:path for (part, path) in partitions.items() if os.path.exists(path)}
  common.BuildVBMeta(output_path, partitions, name, vbmeta_partitions)


def main(argv):
  args = common.ParseOptions(argv, __doc__)

@@ -866,13 +923,20 @@ def main(argv):
      mount_point = "product"
    elif image_filename == "system_ext.img":
      mount_point = "system_ext"
    elif "vbmeta" in image_filename:
      mount_point = "vbmeta"
    else:
      logger.error("Unknown image file name %s", image_filename)
      sys.exit(1)

    if "vbmeta" != mount_point:
      image_properties = ImagePropFromGlobalDict(glob_dict, mount_point)

  try:
    if "vbmeta" in os.path.basename(out_file):
      OPTIONS.info_dict = glob_dict
      BuildVBMeta(in_dir, glob_dict, out_file)
    else:
      BuildImage(in_dir, image_properties, out_file, target_out)
  except:
    logger.error("Failed to build %s from %s", out_file, in_dir)