OS Updater improvements (#19914)

* Clear hashes before swapping

* add retry logic

* better retry logic

* actually fail on retries exceeded
pull/19916/head
Willem Melching 4 years ago committed by GitHub
parent 9f2088e2c3
commit fe91b8a1b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      launch_chffrplus.sh
  2. 97
      selfdrive/hardware/tici/agnos.py

@ -146,6 +146,12 @@ function tici_init {
if [[ "$SYSTEM_HASH" == "$SYSTEM_HASH_EXPECTED" && "$BOOT_HASH" == "$BOOT_HASH_EXPECTED" ]]; then if [[ "$SYSTEM_HASH" == "$SYSTEM_HASH_EXPECTED" && "$BOOT_HASH" == "$BOOT_HASH_EXPECTED" ]]; then
echo "Swapping active slot to $OTHER_SLOT_NUMBER" echo "Swapping active slot to $OTHER_SLOT_NUMBER"
# Clean hashes before swapping to prevent looping
dd if=/dev/zero of="/dev/disk/by-partlabel/system$OTHER_SLOT" bs=1 seek="$SYSTEM_SIZE" count=64
dd if=/dev/zero of="/dev/disk/by-partlabel/boot$OTHER_SLOT" bs=1 seek="$BOOT_SIZE" count=64
sync
abctl --set_active "$OTHER_SLOT_NUMBER" abctl --set_active "$OTHER_SLOT_NUMBER"
sleep 1 sleep 1
@ -154,6 +160,12 @@ function tici_init {
echo "Hash mismatch, downloading agnos" echo "Hash mismatch, downloading agnos"
if $DIR/selfdrive/hardware/tici/agnos.py $MANIFEST; then if $DIR/selfdrive/hardware/tici/agnos.py $MANIFEST; then
echo "Download done, swapping active slot to $OTHER_SLOT_NUMBER" echo "Download done, swapping active slot to $OTHER_SLOT_NUMBER"
# Clean hashes before swapping to prevent looping
dd if=/dev/zero of="/dev/disk/by-partlabel/system$OTHER_SLOT" bs=1 seek="$SYSTEM_SIZE" count=64
dd if=/dev/zero of="/dev/disk/by-partlabel/boot$OTHER_SLOT" bs=1 seek="$BOOT_SIZE" count=64
sync
abctl --set_active "$OTHER_SLOT_NUMBER" abctl --set_active "$OTHER_SLOT_NUMBER"
fi fi

@ -76,6 +76,48 @@ def unsparsify(f):
raise Exception("Unhandled sparse chunk type") raise Exception("Unhandled sparse chunk type")
def flash_partition(cloudlog, spinner, target_slot, partition):
cloudlog.info(f"Downloading and writing {partition['name']}")
downloader = StreamingDecompressor(partition['url'])
with open(f"/dev/disk/by-partlabel/{partition['name']}{target_slot}", 'wb') as out:
partition_size = partition['size']
# Clear hash before flashing
out.seek(partition_size)
out.write(b"\x00" * 64)
out.seek(0)
os.sync()
# Flash partition
if partition['sparse']:
raw_hash = hashlib.sha256()
for chunk in unsparsify(downloader):
raw_hash.update(chunk)
out.write(chunk)
if spinner is not None:
spinner.update_progress(out.tell(), partition_size)
if raw_hash.hexdigest().lower() != partition['hash_raw'].lower():
raise Exception(f"Unsparse hash mismatch '{raw_hash.hexdigest().lower()}'")
else:
while not downloader.eof:
out.write(downloader.read(1024 * 1024))
if spinner is not None:
spinner.update_progress(out.tell(), partition_size)
if downloader.sha256.hexdigest().lower() != partition['hash'].lower():
raise Exception("Uncompressed hash mismatch")
if out.tell() != partition['size']:
raise Exception("Uncompressed size mismatch")
# Write hash after successfull flash
os.sync()
out.write(partition['hash_raw'].lower().encode())
def flash_agnos_update(manifest_path, cloudlog, spinner=None): def flash_agnos_update(manifest_path, cloudlog, spinner=None):
update = json.load(open(manifest_path)) update = json.load(open(manifest_path))
@ -89,45 +131,22 @@ def flash_agnos_update(manifest_path, cloudlog, spinner=None):
os.system(f"abctl --set_unbootable {target_slot_number}") os.system(f"abctl --set_unbootable {target_slot_number}")
for partition in update: for partition in update:
cloudlog.info(f"Downloading and writing {partition['name']}") success = False
downloader = StreamingDecompressor(partition['url']) for retries in range(10):
with open(f"/dev/disk/by-partlabel/{partition['name']}{target_slot}", 'wb') as out: try:
partition_size = partition['size'] flash_partition(cloudlog, spinner, target_slot, partition)
# Clear hash before flashing success = True
out.seek(partition_size) break
out.write(b"\x00" * 64)
out.seek(0) except requests.exceptions.RequestException:
os.sync() spinner.update("Waiting for internet...")
cloudlog.info(f"Failed to download {partition['name']}, retrying ({retries})")
# Flash partition time.sleep(10)
if partition['sparse']:
raw_hash = hashlib.sha256() if not success:
for chunk in unsparsify(downloader): cloudlog.info(f"Failed to flash {partition['name']}, aborting")
raw_hash.update(chunk) raise Exception("Maximum retries exceeded")
out.write(chunk)
if spinner is not None:
spinner.update_progress(out.tell(), partition_size)
if raw_hash.hexdigest().lower() != partition['hash_raw'].lower():
raise Exception(f"Unsparse hash mismatch '{raw_hash.hexdigest().lower()}'")
else:
while not downloader.eof:
out.write(downloader.read(1024 * 1024))
if spinner is not None:
spinner.update_progress(out.tell(), partition_size)
if downloader.sha256.hexdigest().lower() != partition['hash'].lower():
raise Exception("Uncompressed hash mismatch")
if out.tell() != partition['size']:
raise Exception("Uncompressed size mismatch")
# Write hash after successfull flash
os.sync()
out.write(partition['hash_raw'].lower().encode())
cloudlog.info(f"AGNOS ready on slot {target_slot}") cloudlog.info(f"AGNOS ready on slot {target_slot}")

Loading…
Cancel
Save