1#!/bin/bash -ex
2usage () {
3  echo "Create a Mixed Build archive with the given system and device archives."
4  echo
5  echo "Usage: $0 [-v <vendor_version>] [-m <modify_system_image_path>]"
6  echo "    [-t <prebuilt_otatools_path>] [-p <override_vbmeta_image_path>]"
7  echo "    [-b <override_boot_image_path>]"
8  echo "    [-s] [-d] system_build_dir device_build_dir out_dir"
9  echo
10  echo "Options -v, -m, -t, -p, -b, -s, -d must precede positional arguments."
11  echo
12  echo "vendor_version is the version of the vendor image when Keymaster v3"
13  echo "    related modifications to the system image is necessary. Optional."
14  echo "    eg. 8.1.0 for a mixed build of GSI and O-MR1 vendor image."
15  echo "modify_system_image_path is the path to the script that modifies the"
16  echo "    system image, needed for Keymaster v3. Optional."
17  echo "prebuilt_otatools_path is the path to otatools.zip file that has all"
18  echo "    required host binaries to modify system image. It also must include"
19  echo "    VINTF check tool to verify the compatibility of the given images."
20  echo "    Optional."
21  echo "override_vbmeta_image_path is the path to a vbmeta.img to use"
22  echo "    to override the existing vbmeta.img of device. Optional."
23  echo "override_boot_image_path is the path to a boot imgage to use to"
24  echo "    override the existing boot.img of device. Optional."
25  echo "-s is used to fetch and flash both product.img and system.img from"
26  echo "    the system_build_dir for devices with a product partition."
27  echo "    product.img will be removed if system_build_dir does not have"
28  echo "    product.img when -s option is declared."
29  echo "    By default, only system.img is flashed to the target device for"
30  echo "    independent system update. No parameter required. Optional"
31  echo "-d is used to skip vbmeta.img replacement in its entirety and the"
32  echo "    one from the device build (if exists) is left untouched"
33  echo "system_build_dir is the path to the system build"
34  echo "    eg. aosp_arm64_ab-userdebug."
35  echo "device_build_dir is the path to the device build"
36  echo "    eg. sailfish-user."
37  echo "out_dir is the path to where the new build will be placed."
38}
39
40# Print error message and exit.
41# Usage: exit_badparam message
42#
43# message is a string to be displayed before exit.
44exit_badparam () {
45  echo "ERROR: $1" >&2
46  usage
47  exit 1
48}
49
50cleanup_and_exit () {
51  readonly result="$?"
52  rm -rf "$TEMP_DIR"
53  exit "$result"
54}
55
56trap cleanup_and_exit EXIT
57
58while getopts :v:m:p:b:t:sd opt; do
59  case "$opt" in
60    v)
61      readonly VENDOR_VERSION="$OPTARG"
62      ;;
63    m)
64      readonly MODIFY_SYSTEM_SCRIPT="$OPTARG"
65      ;;
66    p)
67      readonly OVERRIDE_VBMETA_IMAGE_PATH="$OPTARG"
68      ;;
69    b)
70      readonly OVERRIDE_BOOT_IMAGE_PATH="$OPTARG"
71      ;;
72    t)
73      readonly OTATOOLS_ZIP="$OPTARG"
74      ;;
75    s)
76      readonly INCLUDE_PRODUCT=true
77      ;;
78    d)
79      readonly SKIP_VBMETA_REPLACE=true
80      ;;
81    \?)
82      exit_badparam "Invalid options: -"$OPTARG""
83      ;;
84    :)
85      exit_badparam "Option -"$OPTARG" requires an argument."
86      ;;
87  esac
88done
89
90if [[ -z "${VENDOR_VERSION+x}" && ! -z "${MODIFY_SYSTEM_SCRIPT+x}" ]] || \
91  [[ ! -z "${VENDOR_VERSION+x}" && -z "${MODIFY_SYSTEM_SCRIPT+x}" ]]; then
92  exit_badparam "Options -v and -m must be set together."
93fi
94
95shift "$((OPTIND-1))"
96
97if [[ $# -lt 3 ]]; then
98  exit_badparam "Unexpected number of arguments"
99fi
100
101readonly SYSTEM_DIR="$1"
102readonly DEVICE_DIR="$2"
103readonly DIST_DIR="$3"
104readonly TEMP_DIR="$(mktemp -d /tmp/"$(basename $0)"_XXXXXXXX)"
105
106readonly SYSTEM_TARGET_FILES_ARCHIVE="$(find "$SYSTEM_DIR" -name "*-target_files-*.zip" -print)"
107if [[ ! -f "$SYSTEM_TARGET_FILES_ARCHIVE" ]]; then
108  exit_badparam "Could not find system target files archive in $SYSTEM_DIR."
109fi
110
111readonly DEVICE_ARCHIVE="$(find "$DEVICE_DIR" -name "*-img-*.zip" -print)"
112if [[ ! -f "$DEVICE_ARCHIVE" ]]; then
113  exit_badparam "Could not find device img archive in $DEVICE_DIR."
114fi
115
116readonly DEVICE_TARGET_FILES_ARCHIVE="$(find "$DEVICE_DIR" -name "*-target_files-*.zip" -print)"
117if [[ ! -f "$DEVICE_TARGET_FILES_ARCHIVE" ]]; then
118  exit_badparam "Could not find device target_files archive in $DEVICE_DIR."
119fi
120
121if [[ ! -z "${MODIFY_SYSTEM_SCRIPT+x}" && ! -f "$MODIFY_SYSTEM_SCRIPT" ]]; then
122  exit_badparam "Script not found: "$MODIFY_SYSTEM_SCRIPT""
123fi
124
125if [[ ! -z "${OVERRIDE_VBMETA_IMAGE_PATH+x}" && ! -f "$OVERRIDE_VBMETA_IMAGE_PATH" ]]; then
126  exit_badparam "Specified vbmeta.img not found: "$OVERRIDE_VBMETA_IMAGE_PATH""
127fi
128
129if [[ ! -z "${OVERRIDE_BOOT_IMAGE_PATH+x}" && ! -f "$OVERRIDE_BOOT_IMAGE_PATH" ]]; then
130  exit_badparam "Specified boot image not found: "$OVERRIDE_BOOT_IMAGE_PATH""
131fi
132
133readonly DEVICE_ARTIFACTS_DIR="$TEMP_DIR"/device_archive_artifacts
134readonly DEVICE_IMAGES_DIR="$DEVICE_ARTIFACTS_DIR"/IMAGES
135readonly SYSTEM_ARTIFACTS_DIR="$TEMP_DIR"/system_artifacts
136readonly SYSTEM_IMAGES_DIR="$SYSTEM_ARTIFACTS_DIR"/IMAGES
137readonly OTATOOLS_DIR="$TEMP_DIR"/otatools
138
139readonly SPL_PROPERTY_NAME="ro.build.version.security_patch"
140readonly SYSTEM_BUILD_PROP="SYSTEM/build.prop"
141
142declare -a EXTRACT_SYSTEM_FILE_LIST
143EXTRACT_SYSTEM_FILE_LIST=(
144  IMAGES/system.img \
145  IMAGES/vbmeta.img \
146  "$SYSTEM_BUILD_PROP" \
147)
148
149declare -a EXTRACT_VINTF_SYSTEM_FILE_LIST
150EXTRACT_VINTF_SYSTEM_FILE_LIST=(
151  "$SYSTEM_BUILD_PROP" \
152)
153
154declare -a EXTRACT_DEVICE_FILE_LIST
155EXTRACT_DEVICE_FILE_LIST=(
156  */build.prop \
157  META/* \
158)
159
160declare -A SYSTEM_SEARCH_PATH
161SYSTEM_SEARCH_PATH=( \
162  [/system]="SYSTEM" \
163  [/product]="PRODUCT SYSTEM/product" \
164  [/system_ext]="SYSTEM_EXT SYSTEM/system_ext" \
165)
166
167declare -A DEVICE_SEARCH_PATH
168# Mixed build will not have /vendor to SYSTEM/vendor case
169DEVICE_SEARCH_PATH=( \
170  [/vendor]="VENDOR" \
171  [/odm]="ODM VENDOR/odm" \
172)
173
174###
175# Uncompress otatools.zip and get vintf file list.
176if [[ ! -f "$OTATOOLS_ZIP" ]]; then
177  echo "WARNING: otatools.zip is missing. Add \"-t otatools.zip\" to enable checkvintf"
178else
179  readonly OTATOOLS_AVAILABLE=true
180  # Uncompress otatools
181  mkdir -p "$OTATOOLS_DIR"
182  unzip "$OTATOOLS_ZIP" bin/* lib64/* -d "$OTATOOLS_DIR"
183  # Set paths for using prebuilt host binaries.
184  export PATH="$OTATOOLS_DIR"/bin:"$PATH"
185  export LD_LIBRARY_PATH="$OTATOOLS_DIR"/lib64:"$LD_LIBRARY_PATH"
186
187  # Add vintf file to extract file list
188  declare -a VINTF_DUMP_FILE_LIST
189  VINTF_DUMP_FILE_LIST=( "$(checkvintf --dump-file-list)" )
190
191  for vintf_file_list in ${VINTF_DUMP_FILE_LIST[*]}; do
192    if [[ "$vintf_file_list" == */ ]]; then
193      vintf_file_list="$vintf_file_list"\*
194      # Create system vintf file list for system target files archive
195      for system_dir in "${!SYSTEM_SEARCH_PATH[@]}"; do
196        if [[ "$vintf_file_list" == "$system_dir"/* ]]; then
197          for search_dir in ${SYSTEM_SEARCH_PATH["$system_dir"]}; do
198            search_file=${vintf_file_list/$system_dir/$search_dir}
199            unzip -l "$SYSTEM_TARGET_FILES_ARCHIVE" "$search_file" > /dev/null && \
200              EXTRACT_VINTF_SYSTEM_FILE_LIST+=( "$search_file" )
201          done
202          break
203        fi
204      done
205      # Create device vintf file list for device target files archive
206      for device_dir in "${!DEVICE_SEARCH_PATH[@]}"; do
207        if [[ "$vintf_file_list" == "$device_dir"/* ]]; then
208          for search_dir in ${DEVICE_SEARCH_PATH["$device_dir"]}; do
209            search_file=${vintf_file_list/$device_dir/$search_dir}
210            unzip -l "$DEVICE_TARGET_FILES_ARCHIVE" "$search_file" > /dev/null && \
211              EXTRACT_DEVICE_FILE_LIST+=( "$search_file" )
212          done
213          break
214        fi
215      done
216     fi
217  done
218fi
219
220###
221# Uncompress the system archives.
222if [[ "$INCLUDE_PRODUCT" == true ]]; then
223  unzip -l "$SYSTEM_TARGET_FILES_ARCHIVE" | grep -q IMAGES/product.img &&
224  EXTRACT_SYSTEM_FILE_LIST+=(IMAGES/product.img)
225fi
226
227mkdir -p "$SYSTEM_ARTIFACTS_DIR"
228# Get system images.
229unzip "$SYSTEM_TARGET_FILES_ARCHIVE" "${EXTRACT_SYSTEM_FILE_LIST[@]}" \
230  -d "$SYSTEM_ARTIFACTS_DIR"
231
232###
233# Uncompress the device archives.
234mkdir -p "$DEVICE_IMAGES_DIR"
235# Get device images.
236unzip "$DEVICE_ARCHIVE" -d "$DEVICE_IMAGES_DIR"
237# Get the device meta data.
238unzip "$DEVICE_TARGET_FILES_ARCHIVE" "${EXTRACT_DEVICE_FILE_LIST[@]}" \
239  -d "$DEVICE_ARTIFACTS_DIR"
240
241###
242# Modify system.img if vendor version is provided.
243if [[ ! -z "${VENDOR_VERSION+x}" ]]; then
244  # Create copy of system target files package that can be modified
245  # since the original $SYSTEM_TARGET_FILES_ARCHIVE is a symlink to
246  # prebuilt files in cache
247  cp "$SYSTEM_TARGET_FILES_ARCHIVE" "$TEMP_DIR"
248  readonly COPY_SYSTEM_TARGET_FILES_ARCHIVE="$TEMP_DIR"/"$(basename "$SYSTEM_TARGET_FILES_ARCHIVE")"
249
250  # Check compatibility of security patch level
251  readonly SYSTEM_SPL=$(sed -n -r "s/^"$SPL_PROPERTY_NAME"=(.*)$/\1/p" "$SYSTEM_ARTIFACTS_DIR"/"$SYSTEM_BUILD_PROP")
252  readonly VENDOR_SPL=$(sed -n -r "s/^"$SPL_PROPERTY_NAME"=(.*)$/\1/p" "$DEVICE_ARTIFACTS_DIR"/"$SYSTEM_BUILD_PROP")
253  declare -a args
254  args=(-v "$VENDOR_VERSION" "$COPY_SYSTEM_TARGET_FILES_ARCHIVE")
255  if [[ "$SYSTEM_SPL" != "$VENDOR_SPL" ]]; then
256    echo "Security patch level mismatch detected..."
257    echo "  SPL of system: "$SYSTEM_SPL""
258    echo "  SPL of vendor: "$VENDOR_SPL""
259    args+=("$VENDOR_SPL")
260  fi
261  "$MODIFY_SYSTEM_SCRIPT" "${args[@]}"
262  # Replace system.img with newly modified system.img
263  unzip -o "$COPY_SYSTEM_TARGET_FILES_ARCHIVE" IMAGES/system.img -d "$SYSTEM_ARTIFACTS_DIR"
264fi
265
266# Check vintf
267if [[ "$OTATOOLS_AVAILABLE" == true ]]; then
268  # Overwrite VINTF system matrix to device artifacts dir
269  unzip -o "$SYSTEM_TARGET_FILES_ARCHIVE" "${EXTRACT_VINTF_SYSTEM_FILE_LIST[@]}" \
270    -d "$DEVICE_ARTIFACTS_DIR"
271  check_target_files_vintf "$DEVICE_ARTIFACTS_DIR"
272fi
273
274###
275# Overwrite artifacts in the device archive to create the Mixed Build artifacts.
276cp "$SYSTEM_IMAGES_DIR"/system.img "$DEVICE_IMAGES_DIR"/
277if [[ "$INCLUDE_PRODUCT" == true ]]; then
278  if [[ -f "$SYSTEM_IMAGES_DIR"/product.img ]]; then
279    cp "$SYSTEM_IMAGES_DIR"/product.img "$DEVICE_IMAGES_DIR"/
280  else
281    rm -f "$DEVICE_IMAGES_DIR"/product.img
282    # Removed product partition from required partition list
283    sed -i "/partition-exists=product$/d" "$DEVICE_IMAGES_DIR"/android-info.txt
284  fi
285fi
286
287if [[ "$SKIP_VBMETA_REPLACE" == true ]]; then
288    # Totally skip the vbmeta.img replacement
289    echo "Skip vbmeta.img replacement."
290else
291    # Only override vbmeta if it is already present since fastboot update will try
292    # to flash whatever is in the archive.
293    if [[ -f "$DEVICE_IMAGES_DIR"/vbmeta.img ]]; then
294      readonly VBMETA_IMAGE_PATH="${OVERRIDE_VBMETA_IMAGE_PATH:-"$SYSTEM_IMAGES_DIR"/vbmeta.img}"
295      cp "$VBMETA_IMAGE_PATH" "$DEVICE_IMAGES_DIR"/
296    fi
297fi
298
299# Override boot.img with the provided boot image file since fastboot update cmd
300# will try to flash boot.img in the archive.
301if [[ ! -z "${OVERRIDE_BOOT_IMAGE_PATH+x}" && -f "$DEVICE_IMAGES_DIR"/boot.img ]]; then
302  cp "$OVERRIDE_BOOT_IMAGE_PATH" "$DEVICE_IMAGES_DIR"/boot.img
303fi
304
305###
306# Create the Mixed Build archive.
307(
308  cd "$DEVICE_IMAGES_DIR"
309  zip -r mixed.zip ./*
310)
311
312###
313# Archive the artifacts.
314if [ -n "$DIST_DIR" ]; then
315  mkdir -p "$DIST_DIR" || true
316fi
317# Archive all the device artifacts.
318rsync --archive --verbose --copy-links --exclude='logs' \
319  "$DEVICE_DIR"/* "$DIST_DIR"
320# Overwrite the image archive with the Mixed Build archive.
321OUT_ARCHIVE="$DIST_DIR"/"$(basename $DEVICE_ARCHIVE)"
322cp "$DEVICE_IMAGES_DIR"/mixed.zip "$OUT_ARCHIVE"
323# Overwrite android-info.txt with the updated one.
324cp "$DEVICE_IMAGES_DIR"/android-info.txt "$DIST_DIR"/
325