brillo_update_payload: Extract partition images in parallel.
unzipping and converting sparse image to raw could take a while for
large partitions like system and vendor, this CL move them into a
separate function and run them in background.
Bug: 77817425
Test: brillo_update_payload generate
Test: brillo_update_payload verify
Change-Id: Ic55b9e35eb3c275533a7231d2b57722aa89c96a5
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index a4c3f91..7c1a6ce 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -392,6 +392,64 @@
done
}
+# extract_partition_brillo <target_files.zip> <partitions_array> <partition>
+# <part_file> <part_map_file>
+#
+# Extract the <partition> from target_files zip file into <part_file> and its
+# map file into <part_map_file>.
+extract_partition_brillo() {
+ local image="$1"
+ local partitions_array="$2"
+ local part="$3"
+ local part_file="$4"
+ local part_map_file="$5"
+
+ # For each partition, we in turn look for its image file under IMAGES/ and
+ # RADIO/ in the given target_files zip file.
+ local path path_in_zip
+ for path in IMAGES RADIO; do
+ if unzip -l "${image}" "${path}/${part}.img" >/dev/null; then
+ path_in_zip="${path}"
+ break
+ fi
+ done
+ [[ -n "${path_in_zip}" ]] || die "Failed to find ${part}.img"
+ unzip -p "${image}" "${path_in_zip}/${part}.img" >"${part_file}"
+
+ # If the partition is stored as an Android sparse image file, we need to
+ # convert them to a raw image for the update.
+ local magic=$(head --bytes=4 "${part_file}" | hexdump -e '1/1 "%.2x"')
+ if [[ "${magic}" == "3aff26ed" ]]; then
+ local temp_sparse=$(create_tempfile "${part}.sparse.XXXXXX")
+ echo "Converting Android sparse image ${part}.img to RAW."
+ mv "${part_file}" "${temp_sparse}"
+ simg2img "${temp_sparse}" "${part_file}"
+ rm -f "${temp_sparse}"
+ fi
+
+ # Extract the .map file (if one is available).
+ unzip -p "${image}" "${path_in_zip}/${part}.map" >"${part_map_file}" \
+ 2>/dev/null || true
+
+ # delta_generator only supports images multiple of 4 KiB. For target images
+ # we pad the data with zeros if needed, but for source images we truncate
+ # down the data since the last block of the old image could be padded on
+ # disk with unknown data.
+ local filesize=$(stat -c%s "${part_file}")
+ if [[ $(( filesize % 4096 )) -ne 0 ]]; then
+ if [[ "${partitions_array}" == "SRC_PARTITIONS" ]]; then
+ echo "Rounding DOWN partition ${part}.img to a multiple of 4 KiB."
+ : $(( filesize = filesize & -4096 ))
+ else
+ echo "Rounding UP partition ${part}.img to a multiple of 4 KiB."
+ : $(( filesize = (filesize + 4095) & -4096 ))
+ fi
+ truncate_file "${part_file}" "${filesize}"
+ fi
+
+ echo "Extracted ${partitions_array}[${part}]: ${filesize} bytes"
+}
+
# extract_image_brillo <target_files.zip> <partitions_array> [partitions_order]
#
# Extract the A/B updated partitions from a Brillo target_files zip file into
@@ -417,7 +475,7 @@
else
warn "No ab_partitions.txt found. Using default."
fi
- echo "List of A/B partitions: ${partitions[@]}"
+ echo "List of A/B partitions for ${partitions_array}: ${partitions[@]}"
if [[ -n "${partitions_order}" ]]; then
eval "${partitions_order}=(${partitions[@]})"
@@ -458,67 +516,32 @@
fi
fi
- local part part_file temp_raw filesize
+ local part
for part in "${partitions[@]}"; do
- part_file=$(create_tempfile "${part}.img.XXXXXX")
- CLEANUP_FILES+=("${part_file}")
-
- # For each partition, we in turn look for its image file under IMAGES/ and
- # RADIO/ in the given target_files zip file.
- local path path_in_zip
- for path in IMAGES RADIO; do
- if unzip -l "${image}" "${path}/${part}.img" >/dev/null; then
- path_in_zip="${path}"
- break
- fi
- done
- [[ -n "${path_in_zip}" ]] || die "Failed to find ${part}.img"
- unzip -p "${image}" "${path_in_zip}/${part}.img" >"${part_file}"
-
- # If the partition is stored as an Android sparse image file, we need to
- # convert them to a raw image for the update.
- local magic=$(head --bytes=4 "${part_file}" | hexdump -e '1/1 "%.2x"')
- if [[ "${magic}" == "3aff26ed" ]]; then
- temp_raw=$(create_tempfile "${part}.raw.XXXXXX")
- CLEANUP_FILES+=("${temp_raw}")
- echo "Converting Android sparse image ${part}.img to RAW."
- simg2img "${part_file}" "${temp_raw}"
- # At this point, we can drop the contents of the old part_file file, but
- # we can't delete the file because it will be deleted in cleanup.
- true >"${part_file}"
- part_file="${temp_raw}"
- fi
-
- # Extract the .map file (if one is available).
- part_map_file=$(create_tempfile "${part}.map.XXXXXX")
- CLEANUP_FILES+=("${part_map_file}")
- unzip -p "${image}" "${path_in_zip}/${part}.map" >"${part_map_file}" || \
- part_map_file=""
-
- # delta_generator only supports images multiple of 4 KiB. For target images
- # we pad the data with zeros if needed, but for source images we truncate
- # down the data since the last block of the old image could be padded on
- # disk with unknown data.
- filesize=$(stat -c%s "${part_file}")
- if [[ $(( filesize % 4096 )) -ne 0 ]]; then
- if [[ "${partitions_array}" == "SRC_PARTITIONS" ]]; then
- echo "Rounding DOWN partition ${part}.img to a multiple of 4 KiB."
- : $(( filesize = filesize & -4096 ))
- if [[ ${filesize} == 0 ]]; then
- echo "Source partition ${part}.img is empty after rounding down," \
- "skipping."
- continue
- fi
- else
- echo "Rounding UP partition ${part}.img to a multiple of 4 KiB."
- : $(( filesize = (filesize + 4095) & -4096 ))
- fi
- truncate_file "${part_file}" "${filesize}"
- fi
-
+ local part_file=$(create_tempfile "${part}.img.XXXXXX")
+ local part_map_file=$(create_tempfile "${part}.map.XXXXXX")
+ CLEANUP_FILES+=("${part_file}" "${part_map_file}")
+ # Extract partitions in background.
+ extract_partition_brillo "${image}" "${partitions_array}" "${part}" \
+ "${part_file}" "${part_map_file}" &
eval "${partitions_array}[\"${part}\"]=\"${part_file}\""
eval "${partitions_array}_MAP[\"${part}\"]=\"${part_map_file}\""
- echo "Extracted ${partitions_array}[${part}]: ${filesize} bytes"
+ done
+}
+
+# cleanup_partition_array <partitions_array>
+#
+# Remove all empty files in <partitions_array>.
+cleanup_partition_array() {
+ local partitions_array="$1"
+ # Have to use eval to iterate over associative array keys with variable array
+ # names, we should change it to use nameref once bash 4.3 is available
+ # everywhere.
+ for part in $(eval "echo \${!${partitions_array}[@]}"); do
+ local path="${partitions_array}[$part]"
+ if [[ ! -s "${!path}" ]]; then
+ eval "unset ${partitions_array}[${part}]"
+ fi
done
}
@@ -530,6 +553,12 @@
extract_image "${FLAGS_source_image}" SRC_PARTITIONS
fi
extract_image "${FLAGS_target_image}" DST_PARTITIONS PARTITIONS_ORDER
+ # Wait for all subprocesses.
+ wait
+ cleanup_partition_array SRC_PARTITIONS
+ cleanup_partition_array SRC_PARTITIONS_MAP
+ cleanup_partition_array DST_PARTITIONS
+ cleanup_partition_array DST_PARTITIONS_MAP
}
get_payload_type() {
@@ -549,17 +578,8 @@
}
cmd_generate() {
- local payload_type="delta"
- if [[ -z "${FLAGS_source_image}" ]]; then
- payload_type="full"
- fi
-
- echo "Extracting images for ${payload_type} update."
-
- extract_image "${FLAGS_target_image}" DST_PARTITIONS PARTITIONS_ORDER
- if [[ "${payload_type}" == "delta" ]]; then
- extract_image "${FLAGS_source_image}" SRC_PARTITIONS
- fi
+ local payload_type=$(get_payload_type)
+ extract_payload_images ${payload_type}
echo "Generating ${payload_type} update."
# Common payload args: