Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 447ab696 authored by Akilesh Kailash's avatar Akilesh Kailash
Browse files

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: default avatarAkilesh Kailash <akailash@google.com>
parent d07b423e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -29,3 +29,8 @@ python_binary_host {
        "snapshot_proto_python",
    ],
}

sh_binary_host {
    name: "apply_update",
    src: "apply-update.sh",
}
+201 −58
Original line number Diff line number Diff line
#!/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:
#
#  To update both dynamic and static partitions:
#
# ./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
# 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
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# 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 &

echo "Waiting for snapshot patch creation"
wait $(jobs -p)
echo "Snapshot patch creation completed"
# Ensure OUT directory exists
if [ -z "$OUT" ]; then
  echo "Error: OUT environment variable not set." >&2
  exit 1
fi

mv *.patch $OUT/
DEVICE_PATH="/data/verity-hash"
HOST_PATH="$OUT/verity-hash"

adb root
adb wait-for-device
adb shell mkdir -p /data/update/
adb push $OUT/*.patch /data/update/
# Create the log file path
log_file="$HOST_PATH/snapshot.log"

if [[ "$2" == "--wipe" ]]; then
  adb shell snapshotctl apply-update /data/update/ -w
else
  adb shell snapshotctl apply-update /data/update/
fi
# 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
}

# 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
# 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
  fastboot flash bootloader $OUT/bootloader.img
  sleep 1
  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
  sleep 1
  fastboot flash radio "$OUT"/radio.img
  fastboot reboot bootloader
  sleep 1
  fastboot flashall --exclude-dynamic-partitions --disable-super-optimization
  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 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 $DEVICE_PATH
fi

if (( skip_static_partitions )); then
    log_message "Rebooting device - Skipping flashing static partitions"
    adb reboot
else
    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"