Apply-update: Script to apply updates to device
<Development workflow for any project in the platform and build with 'm' to create the images>
Build:
$m apply_update
$ apply_update --help
Update the device to the current build in $OUT:
$ apply_update
Update the device, but skip flashing static partitions (see --help):
$ apply_update --skip-static-partitions
Update the device and wipe user data:
$ apply_update --wipe
Performance:
a: Default update without any paramenters: Update takes ~30-40 seconds.
b: With --skip-static-partitions its < 20 seconds
Bug: 371304627
Test: Test development workflow:
1: m libsnapshot && m -j
apply_update
2: m snapshotctl && m -j
apply_update --wipe
3: m virtmgr && m -j
apply_update --skip-static-partitions
4: m crosvm && m -j
apply_update --skip-static-partitions
Change-Id: Iff2c774ef83bc67601cc978e2e3ceea355a5482f
Signed-off-by: Akilesh Kailash <akailash@google.com>
diff --git a/fs_mgr/libsnapshot/scripts/Android.bp b/fs_mgr/libsnapshot/scripts/Android.bp
index 829f5bc..b99da93 100644
--- a/fs_mgr/libsnapshot/scripts/Android.bp
+++ b/fs_mgr/libsnapshot/scripts/Android.bp
@@ -29,3 +29,8 @@
"snapshot_proto_python",
],
}
+
+sh_binary_host {
+ name: "apply_update",
+ src: "apply-update.sh",
+}
diff --git a/fs_mgr/libsnapshot/scripts/apply-update.sh b/fs_mgr/libsnapshot/scripts/apply-update.sh
index 90b0119..0b10721 100755
--- a/fs_mgr/libsnapshot/scripts/apply-update.sh
+++ b/fs_mgr/libsnapshot/scripts/apply-update.sh
@@ -1,77 +1,220 @@
#!/bin/bash
-# This is a debug script to quicky test end-to-end flow
-# of snapshot updates without going through update-engine.
+# Copyright 2024 Google Inc. All rights reserved.
#
-# Usage:
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# To update both dynamic and static partitions:
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# ./system/core/fs_mgr/libsnapshot/apply_update.sh [--update-static-partitions] [--wipe]
-#
-# --update-static-partitions: This will update bootloader and static A/B
-# partitions
-# --wipe: Allows data wipe as part of update flow
-#
-# To update dynamic partitions only (this should be used when static
-# partitions are present in both the slots):
-#
-# ./system/core/fs_mgr/libsnapshot/apply_update.sh
-#
-#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
-rm -f $OUT/*.patch
+# apply_update.sh: Script to update the device in incremental way
-# Compare images and create snapshot patches. Currently, this
-# just compares two identical images in $OUT. In general, any source
-# and target images could be passed to create snapshot patches. However,
-# care must be taken to ensure source images are already present on the device.
-#
-# create_snapshot is a host side binary. Build it with `m create_snapshot`
-create_snapshot --source=$OUT/system.img --target=$OUT/system.img &
-create_snapshot --source=$OUT/product.img --target=$OUT/product.img &
-create_snapshot --source=$OUT/vendor.img --target=$OUT/vendor.img &
-create_snapshot --source=$OUT/system_ext.img --target=$OUT/system_ext.img &
-create_snapshot --source=$OUT/vendor_dlkm.img --target=$OUT/vendor_dlkm.img &
-create_snapshot --source=$OUT/system_dlkm.img --target=$OUT/system_dlkm.img &
+# Ensure OUT directory exists
+if [ -z "$OUT" ]; then
+ echo "Error: OUT environment variable not set." >&2
+ exit 1
+fi
-echo "Waiting for snapshot patch creation"
-wait $(jobs -p)
-echo "Snapshot patch creation completed"
+DEVICE_PATH="/data/verity-hash"
+HOST_PATH="$OUT/verity-hash"
-mv *.patch $OUT/
+# Create the log file path
+log_file="$HOST_PATH/snapshot.log"
+
+# Function to log messages to both console and log file
+log_message() {
+ message="$1"
+ echo "$message" # Print to stdout
+ echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$log_file" # Append to log file with timestamp
+}
+
+# Function to check for create_snapshot and build if needed
+ensure_create_snapshot() {
+ if ! command -v create_snapshot &> /dev/null; then
+ log_message "create_snapshot not found. Building..."
+ m create_snapshot
+ if [[ $? -ne 0 ]]; then
+ log_message "Error: Failed to build create_snapshot."
+ exit 1
+ fi
+ fi
+}
+
+ensure_create_snapshot
+
+# Function to flash static partitions
+flash_static_partitions() {
+ local wipe_flag="$1"
+
+ fastboot flash bootloader "$OUT"/bootloader.img
+ fastboot reboot bootloader
+ sleep 1
+ fastboot flash radio "$OUT"/radio.img
+ fastboot reboot bootloader
+ sleep 1
+ fastboot flashall --exclude-dynamic-partitions --disable-super-optimization --skip-reboot
+
+ if (( wipe_flag )); then
+ log_message "Wiping device..."
+ fastboot -w
+ fi
+ fastboot reboot
+}
+
+# Function to display the help message
+show_help() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+This script updates an Android device with incremental flashing, optionally wiping data and flashing static partitions.
+
+Options:
+ --skip-static-partitions Skip flashing static partitions (bootloader, radio, boot, vbmeta, dtbo and other static A/B partitions).
+ * Requires manual update of static partitions on both A/B slots
+ *before* using this flag.
+ * Speeds up the update process and development iteration.
+ * Ideal for development focused on the Android platform (AOSP,
+ git_main).
+ * Safe usage: First update static partitions on both slots, then
+ use this flag for faster development iterations.
+ Ex:
+ 1: Run this on both the slots - This will update the kernel and other static partitions:
+ $fastboot flashall --exclude-dynamic-partitions --disable-super-optimization --skip-reboot
+
+ 2: Update bootloader on both the slots:
+ $fastboot flash bootloader $OUT/bootloader.img --slot=all
+
+ 3: Update radio on both the slots:
+ $fastboot flash radio $OUT/radio.img --slot=all
+ Now, the script can safely use this flag for update purpose.
+
+ --wipe Wipe user data during the update.
+ --help Display this help message.
+
+Environment Variables:
+ OUT Path to the directory containing build output.
+ This is required for the script to function correctly.
+
+Examples:
+ <Development workflow for any project in the platform and build with 'm' to create the images>
+
+ Update the device:
+ $0
+
+ Update the device, but skip flashing static partitions (see above for the usage):
+ $0 --skip-static-partitions
+
+ Update the device and wipe user data:
+ $0 --wipe
+
+ Display this help message:
+ $0 --help
+EOF
+}
+
+skip_static_partitions=0
+wipe_flag=0
+help_flag=0
+
+# Parse arguments
+for arg in "$@"; do
+ case "$arg" in
+ --skip-static-partitions)
+ skip_static_partitions=1
+ ;;
+ --wipe)
+ wipe_flag=1
+ ;;
+ --help)
+ help_flag=1
+ ;;
+ *)
+ echo "Unknown argument: $arg" >&2
+ help_flag=1
+ ;;
+ esac
+done
+
+# Check if help flag is set
+if (( help_flag )); then
+ show_help
+ exit 0
+fi
+
+rm -rf $HOST_PATH
adb root
adb wait-for-device
-adb shell mkdir -p /data/update/
-adb push $OUT/*.patch /data/update/
-if [[ "$2" == "--wipe" ]]; then
- adb shell snapshotctl apply-update /data/update/ -w
+adb shell rm -rf $DEVICE_PATH
+adb shell mkdir -p $DEVICE_PATH
+
+echo "Extracting device source hash from dynamic partitions"
+adb shell snapshotctl dump-verity-hash $DEVICE_PATH
+adb pull -q $DEVICE_PATH $OUT/
+
+log_message "Entering directory:"
+
+# Navigate to the verity-hash directory
+cd "$HOST_PATH" || { log_message "Error: Could not navigate to $HOST_PATH"; exit 1; }
+
+pwd
+
+# Iterate over all .pb files using a for loop
+for pb_file in *.pb; do
+ # Extract the base filename without the .pb extension
+ base_filename="${pb_file%.*}"
+
+ # Construct the source and target file names
+ source_file="$pb_file"
+ target_file="$OUT/$base_filename.img"
+
+ # Construct the create_snapshot command using an array
+ snapshot_args=(
+ "create_snapshot"
+ "--source" "$source_file"
+ "--target" "$target_file"
+ "--merkel_tree"
+ )
+
+ # Log the command about to be executed
+ log_message "Running: ${snapshot_args[*]}"
+
+ "${snapshot_args[@]}" >> "$log_file" 2>&1 &
+done
+
+log_message "Waiting for snapshot patch creation"
+
+# Wait for all background processes to complete
+wait $(jobs -p)
+
+log_message "Snapshot patches created successfully"
+
+adb push -q $HOST_PATH/*.patch $DEVICE_PATH
+
+log_message "Applying update"
+
+if (( wipe_flag )); then
+ adb shell snapshotctl apply-update $DEVICE_PATH -w
else
- adb shell snapshotctl apply-update /data/update/
+ adb shell snapshotctl apply-update $DEVICE_PATH
fi
-# Check if the --update-static-partitions option is provided.
-# For quick developer workflow, there is no need to repeatedly
-# apply static partitions.
-if [[ "$1" == "--update-static-partitions" ]]; then
- adb reboot bootloader
- sleep 5
- if [[ "$2" == "--wipe" ]]; then
- fastboot -w
- fi
- fastboot flash bootloader $OUT/bootloader.img
- sleep 1
- fastboot reboot bootloader
- sleep 1
- fastboot flash radio $OUT/radio.img
- sleep 1
- fastboot reboot bootloader
- sleep 1
- fastboot flashall --exclude-dynamic-partitions --disable-super-optimization
+if (( skip_static_partitions )); then
+ log_message "Rebooting device - Skipping flashing static partitions"
+ adb reboot
else
- adb reboot
+ log_message "Rebooting device to bootloader"
+ adb reboot bootloader
+ log_message "Waiting to enter fastboot bootloader"
+ flash_static_partitions "$wipe_flag"
fi
-echo "Update completed"
+log_message "Update completed"