cros_generate_update_payload: Use patched kernel A if kernel B is empty.

When generating a delta payload, the source image may not have a normally
signed kernel in slot B if it's older. If that's the case, use the kernel in
slot A and patch it with the vblock from the stateful partition.

BUG=chromium:417072
TEST=Tryjob, manual testing.

Change-Id: I047fc331f7bbbc08bb8e6024531d6473bb54aee6
Reviewed-on: https://chromium-review.googlesource.com/219573
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
diff --git a/host/cros_generate_update_payload b/host/cros_generate_update_payload
index 5799b3b..5e19b2f 100755
--- a/host/cros_generate_update_payload
+++ b/host/cros_generate_update_payload
@@ -260,6 +260,23 @@
 
 echo "Generating $PAYLOAD_TYPE update"
 
+patch_kernel() {
+  local IMAGE="$1"
+  local KERN_FILE="$2"
+
+  echo "Patching kernel" $KERN_FILE
+  echo "   into" $IMAGE
+  # Keep `local` decl split from assignment so return code is checked.
+  local offset
+  offset=$(partoffset "${IMAGE}" 1)
+  : $(( offset *= 512 ))
+  STATE_MNT=$(mktemp -d --tmpdir="${FLAGS_work_dir}" state.XXXXXX)
+  sudo mount -o ro,loop,offset=$offset "$IMAGE" "$STATE_MNT"
+  dd if="$STATE_MNT"/vmlinuz_hd.vblock of="$KERN_FILE" conv=notrunc 2>/dev/null
+  umount_and_rmdir "$STATE_MNT"
+  STATE_MNT=""
+}
+
 # Sanity check that the real generator exists:
 GENERATOR="$(which delta_generator)"
 [ -x "$GENERATOR" ] || die "can't find delta_generator"
@@ -269,6 +286,13 @@
   if [ "$FLAGS_full_kernel" -eq "$FLAGS_FALSE" ]; then
     SRC_KERNEL=$(extract_partition_to_temp_file "$FLAGS_src_image" 4 \
                  "$FLAGS_src_kern_path")
+    if $(cmp /dev/zero "${SRC_KERNEL}" -n 65536 -s); then
+      echo "Source kernel B is empty, patching kernel A."
+      rm -rf "$SRC_KERNEL"
+      SRC_KERNEL=$(extract_partition_to_temp_file "$FLAGS_src_image" 2 \
+                   "$FLAGS_src_kern_path")
+      patch_kernel "$FLAGS_src_image" "$SRC_KERNEL"
+    fi
     echo md5sum of src kernel:
     md5sum "$SRC_KERNEL"
   else
@@ -283,6 +307,13 @@
 
 DST_KERNEL=$(extract_partition_to_temp_file "$FLAGS_image" 4 \
              "$FLAGS_kern_path")
+if $(cmp /dev/zero "${DST_KERNEL}" -n 65536 -s); then
+  echo "Destination kernel B is empty, patching kernel A."
+  rm -rf "$DST_KERNEL"
+  DST_KERNEL=$(extract_partition_to_temp_file "$FLAGS_image" 2 \
+               "$FLAGS_kern_path")
+  patch_kernel "$FLAGS_image" "$DST_KERNEL"
+fi
 DST_ROOT=$(extract_partition_to_temp_file "$FLAGS_image" 3 \
            "$FLAGS_root_path")