Allow ota_from_target_file to work entirely on directories

When building android, build system will first zip target_file directory
into a .zip file, and then invoke ota_from_target_files. We
ota_from_target_files can work directly on top of directories, we can
parallelize OTA generation and target_file zipping, making builds
faster.

Bug: 227848550
Bug: 277028723
Test: th
Change-Id: Id72bd7cca708af0e1bae2db754f39b27777cd601
This commit is contained in:
Kelvin Zhang
2023-04-17 16:38:08 -07:00
parent 67ca3c05c7
commit 9dbe2ce40f
3 changed files with 79 additions and 32 deletions

View File

@@ -717,26 +717,46 @@ class BuildInfo(object):
script.AssertOemProperty(prop, values, oem_no_mount)
def ReadFromInputFile(input_file, fn):
"""Reads the contents of fn from input zipfile or directory."""
def DoesInputFileContain(input_file, fn):
"""Check whether the input target_files.zip contain an entry `fn`"""
if isinstance(input_file, zipfile.ZipFile):
return input_file.read(fn).decode()
return fn in input_file.namelist()
elif zipfile.is_zipfile(input_file):
with zipfile.ZipFile(input_file, "r", allowZip64=True) as zfp:
return zfp.read(fn).decode()
return fn in zfp.namelist()
else:
if not os.path.isdir(input_file):
raise ValueError(
"Invalid input_file, accepted inputs are ZipFile object, path to .zip file on disk, or path to extracted directory. Actual: " + input_file)
path = os.path.join(input_file, *fn.split("/"))
return os.path.exists(path)
def ReadBytesFromInputFile(input_file, fn):
"""Reads the bytes of fn from input zipfile or directory."""
if isinstance(input_file, zipfile.ZipFile):
return input_file.read(fn)
elif zipfile.is_zipfile(input_file):
with zipfile.ZipFile(input_file, "r", allowZip64=True) as zfp:
return zfp.read(fn)
else:
if not os.path.isdir(input_file):
raise ValueError(
"Invalid input_file, accepted inputs are ZipFile object, path to .zip file on disk, or path to extracted directory. Actual: " + input_file)
path = os.path.join(input_file, *fn.split("/"))
try:
with open(path) as f:
with open(path, "rb") as f:
return f.read()
except IOError as e:
if e.errno == errno.ENOENT:
raise KeyError(fn)
def ReadFromInputFile(input_file, fn):
"""Reads the str contents of fn from input zipfile or directory."""
return ReadBytesFromInputFile(input_file, fn).decode()
def ExtractFromInputFile(input_file, fn):
"""Extracts the contents of fn from input zipfile or directory into a file."""
if isinstance(input_file, zipfile.ZipFile):
@@ -1540,7 +1560,8 @@ def BuildVBMeta(image_path, partitions, name, needed_partitions):
custom_partitions = OPTIONS.info_dict.get(
"avb_custom_images_partition_list", "").strip().split()
custom_avb_partitions = ["vbmeta_" + part for part in OPTIONS.info_dict.get("avb_custom_vbmeta_images_partition_list", "").strip().split()]
custom_avb_partitions = ["vbmeta_" + part for part in OPTIONS.info_dict.get(
"avb_custom_vbmeta_images_partition_list", "").strip().split()]
for partition, path in partitions.items():
if partition not in needed_partitions:
@@ -1906,7 +1927,7 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir,
data = _BuildBootableImage(prebuilt_name, os.path.join(unpack_dir, tree_subdir),
os.path.join(unpack_dir, fs_config),
os.path.join(unpack_dir, 'META/ramdisk_node_list')
if dev_nodes else None,
if dev_nodes else None,
info_dict, has_ramdisk, two_step_image)
if data:
return File(name, data)
@@ -2966,7 +2987,6 @@ def ZipDelete(zip_filename, entries, force=False):
cmd.append(entry)
RunAndCheckOutput(cmd)
os.replace(new_zipfile, zip_filename)
@@ -4071,6 +4091,7 @@ def IsSparseImage(filepath):
# https://source.android.com/devices/bootloader/images
return fp.read(4) == b'\x3A\xFF\x26\xED'
def ParseUpdateEngineConfig(path: str):
"""Parse the update_engine config stored in file `path`
Args
@@ -4092,4 +4113,4 @@ def ParseUpdateEngineConfig(path: str):
if not minor:
raise ValueError(
f"{path} is an invalid update_engine config, missing PAYLOAD_MINOR_VERSION {data}")
return (int(major.group(1)), int(minor.group(1)))
return (int(major.group(1)), int(minor.group(1)))