Skip to content

Azure/meta-azure-device-update-samples

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

meta-azure-device-update-samples

Board-agnostic Yocto layer for Azure Device Update delta generation, testing, and reference workflows

⚠️ Important Notice

This layer is intended for DEMONSTRATION and REFERENCE purposes only.

The artifacts generated by this layer (sample update images v1/v2/v3 and delta files) are example implementations designed to:

  • Demonstrate Azure Device Update delta generation capabilities
  • Provide a reference workflow for automating delta artifact creation
  • Enable testing and validation of delta update scenarios
  • Serve as a starting point for device builders and update builders

For production deployments, you must:

  • Customize recipes for your specific hardware platform
  • Adapt the delta generation workflow to your update strategy
  • Implement proper security, versioning, and rollback mechanisms
  • Test thoroughly on your target devices

Purpose

This layer provides a platform-independent reference implementation showing how to:

  1. Automate delta generation between SWUpdate update packages
  2. Integrate with BitBake build workflows for repeatable, auditable delta creation
  3. Verify delta integrity automatically during the build process
  4. Structure versioned update artifacts for Azure Device Update deployment

What This Layer Demonstrates

  • Automated delta generation workflow - Complete BitBake recipes for creating binary diff packages
  • Recompression and signing pipeline - Preparation of SWUpdate files for delta-compatible format
  • Built-in verification - Automatic delta reconstruction validation before deployment
  • Versioned sample images - Three pre-configured update images (v1.0.0, v2.0.0, v3.0.0) for testing
  • Board-agnostic design - Separates delta generation logic from hardware-specific configuration

What This Layer Does NOT Provide

This layer is board-agnostic by design. Your BSP (Board Support Package) layer must provide:

  • Base image content - Platform-specific rootfs, kernel, drivers, firmware
  • Boot infrastructure - Hardware-specific bootloader configuration (U-Boot, GRUB, etc.)
  • Partition layouts - Board-specific storage strategies and A/B update mechanisms
  • Production configuration - Real versioning strategy, security policies, rollback mechanisms

Example BSP Layer: See meta-raspberrypi-adu for a complete Raspberry Pi 4 implementation that provides these components.


Architecture Overview

┌────────────────────────────────────────────────────────────────────┐
│  BSP Layer (e.g., meta-raspberrypi-adu)                           │
│  Provides: virtual/adu-base-image                                  │
│  Output: adu-base-image.ext4.gz (platform-specific rootfs)         │
└──────────────────────┬─────────────────────────────────────────────┘
                       │ provides base content
                       ↓
┌────────────────────────────────────────────────────────────────────┐
│  meta-azure-device-update-samples (THIS LAYER)                     │
│                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │ SAMPLE IMAGE RECIPES (Versioning)                            │ │
│  │  • adu-update-image-v1.bb → v1.0.0-raspberrypi4-64.swu      │ │
│  │  • adu-update-image-v2.bb → v2.0.0-raspberrypi4-64.swu      │ │
│  │  • adu-update-image-v3.bb → v3.0.0-raspberrypi4-64.swu      │ │
│  │  Output: Signed SWUpdate packages with versioned content    │ │
│  └──────────────────────────────────────────────────────────────┘ │
│                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │ DELTA GENERATION WORKFLOW (adu-delta-image.bb)               │ │
│  │                                                              │ │
│  │  Step 1: Recompress & Sign (for each version)               │ │
│  │    • Extract .swu → decompress .ext4.gz → recompress (PAMZ) │ │
│  │    • Sign sw-description with RSA-2048                       │ │
│  │    • Output: v*.0.0-recompressed.swu (3 files each)         │ │
│  │                                                              │ │
│  │  Step 2: Generate Deltas (using DiffGenTool)                │ │
│  │    • v1-recompressed + v2-recompressed → delta-v1-v2.diff   │ │
│  │    • v2-recompressed + v3-recompressed → delta-v2-v3.diff   │ │
│  │    • v1-recompressed + v3-recompressed → delta-v1-v3.diff   │ │
│  │    Tool: C# DiffGenTool (PAMZ format, P/Invoke libadudiffapi)│ │
│  │                                                              │ │
│  │  Step 3: Verify Deltas (using applydiff)                    │ │
│  │    • v1-recompressed + delta-v1-v2 → verify matches v2      │ │
│  │    • v2-recompressed + delta-v2-v3 → verify matches v3      │ │
│  │    • v1-recompressed + delta-v1-v3 → verify matches v3      │ │
│  │    Tool: C++ applydiff (SHA256 hash verification)           │ │
│  │                                                              │ │
│  │  Step 4: Deploy                                             │ │
│  │    • Copy *.diff and *-recompressed.swu to deploy directory │ │
│  │    • Generate SHA256 checksums for verification             │ │
│  └──────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘

Output Location: tmp/deploy/images/<MACHINE>/
  • adu-update-image-v1.0.0.swu           (Original signed SWU ~240MB)
  • adu-update-image-v2.0.0.swu           (Original signed SWU ~240MB)
  • adu-update-image-v3.0.0.swu           (Original signed SWU ~240MB)
  • adu-update-image-v1.0.0-recompressed.swu  (For delta source)
  • adu-update-image-v2.0.0-recompressed.swu  (For delta source)
  • adu-update-image-v3.0.0-recompressed.swu  (For delta source)
  • adu-delta-v1-to-v2.diff               (Binary delta ~20MB*)
  • adu-delta-v2-to-v3.diff               (Binary delta ~20MB*)
  • adu-delta-v1-to-v3.diff               (Binary delta ~44KB*)

* Delta sizes vary based on actual content changes in the base image.
  Smaller deltas indicate more similar content between versions.

Quick Start

Prerequisites

Required BitBake Variables (set in conf/local.conf or BSP layer):

# REQUIRED: Point to your board's base image recipe
PREFERRED_PROVIDER_virtual/adu-base-image = "adu-base-image"

# REQUIRED: RSA signing keys for SWUpdate package verification
ADUC_PRIVATE_KEY = "/path/to/keys/priv.pem"          # RSA-2048 private key
ADUC_PRIVATE_KEY_PASSWORD = "/path/to/keys/priv.pass" # Key password file
ADUC_PUBLIC_KEY = "/path/to/keys/public.pem"         # RSA public key

# OPTIONAL: ADU manifest metadata (defaults shown)
ADU_PROVIDER ?= "Contoso"         # Your company/organization name
ADU_MODEL ?= "Video"              # Device model identifier
BASE_ADU_SOFTWARE_VERSION ?= "1.0.0"  # Base version for v1 image

Required Recipe Dependencies:

Your BSP layer must have a base image recipe that provides:

# In your BSP: recipes-core/images/adu-base-image.bb
PROVIDES = "virtual/adu-base-image"
inherit swupdate-image  # For SWUpdate packaging support

1. Add Layer to Your Build

The layer is automatically included if you're using the iot-hub-device-update-yocto repository. For manual setup:

# Add required dependencies first
bitbake-layers add-layer ../meta-azure-device-update
bitbake-layers add-layer ../meta-iot-hub-device-update-delta
bitbake-layers add-layer ../meta-swupdate
bitbake-layers add-layer ../meta-clang

# Add samples layer
bitbake-layers add-layer ../meta-azure-device-update-samples

2. Build Sample Update Images

# Build all three versioned sample images (v1.0.0, v2.0.0, v3.0.0)
bitbake adu-update-image-v1 adu-update-image-v2 adu-update-image-v3

# Or use the convenience script (if using iot-hub-device-update-yocto repo)
cd ~/adu_yocto/iot-hub-device-update-yocto
./scripts/build.sh --rebuild adu-update-image-v1,adu-update-image-v2,adu-update-image-v3

Output: Three signed SWUpdate packages in tmp/deploy/images/<MACHINE>/

3. Generate Delta Files

# Generate all delta files with automatic verification
bitbake adu-delta-image

What happens during the build:

  1. Recompression Phase (Tasks: do_recompress_and_sign_v1/v2/v3)

    • Extracts each .swu file
    • Decompresses .ext4.gz images
    • Recompresses with PAMZ-compatible format
    • Signs with RSA-2048 key (using openssl dgst)
    • Creates *-recompressed.swu files (3 files each: sw-description, sw-description.sig, image)
  2. Delta Generation Phase (Tasks: do_generate_delta_v1_v2/v2_v3/v1_v3)

    • Uses C# DiffGenTool (PAMZ format, P/Invoke to libadudiffapi.so)
    • Generates binary diffs between recompressed files
    • Creates .diff files
  3. Verification Phase (Tasks: do_verify_delta_v1_v2/v2_v3/v1_v3) ← AUTOMATIC QUALITY CHECK

    • Uses C++ applydiff tool to reconstruct target from source + delta
    • Compares SHA256 hash of reconstructed vs. original target
    • Build fails if verification fails (prevents broken deltas from being deployed)
  4. Deployment Phase (do_deploy)

    • Copies .diff and *-recompressed.swu files to deploy directory
    • Generates SHA256 checksum files for each artifact

Output files in tmp/deploy/images/<MACHINE>/:

  • adu-delta-v1-to-v2.diff (~20MB for this sample implementation)
  • adu-delta-v2-to-v3.diff (~20MB for this sample implementation)
  • adu-delta-v1-to-v3.diff (~44KB for this sample implementation)
  • adu-update-image-v*.0.0-recompressed.swu (3 files)
  • *.sha256 checksum files

Note on delta sizes: The actual delta size depends on the content differences between versions. In this sample implementation, v1→v2 and v2→v3 contain significant changes, while v1→v3 is optimized with minimal differences, demonstrating the range of possible delta sizes.



Recipes Provided

Sample Image Recipes

Located in recipes-samples/images/:

  • adu-update-image-v1.bb - Base version (v1.0.0)

    • Wraps virtual/adu-base-image in signed SWUpdate package
    • Sets ADU_SOFTWARE_VERSION = "${BASE_ADU_SOFTWARE_VERSION}"
    • Inherits: swupdate-image
    • Output: adu-update-image-v1.0.0-<MACHINE>.swu
  • adu-update-image-v2.bb - Incremental update (v2.0.0)

    • Uses ${@oe.utils.inc_pr("BASE_ADU_SOFTWARE_VERSION", 1)} for auto-versioning
    • Adds version marker file to demonstrate change detection
    • Output: adu-update-image-v2.0.0-<MACHINE>.swu
  • adu-update-image-v3.bb - Second incremental (v3.0.0)

    • Uses ${@oe.utils.inc_pr("BASE_ADU_SOFTWARE_VERSION", 2)}
    • Output: adu-update-image-v3.0.0-<MACHINE>.swu

Key Recipe Dependencies:

DEPENDS = "virtual/adu-base-image swupdate-native openssl-native"
do_swuimage[depends] = "${PN}:do_image_complete"

Delta Generation Recipe

Located in recipes-samples/delta-generation/:

  • adu-delta-image.bb - Complete delta generation workflow
    • Native tool dependencies:

      • iot-hub-device-update-delta-diffgentool-native (C# DiffGenTool for PAMZ format)
      • iot-hub-device-update-delta-processor-native (C++ applydiff, recompress tools)
      • cpio-native (for SWU extraction/creation)
    • Key tasks:

      • do_recompress_and_sign_v1/v2/v3 - Prepare recompressed+signed files
      • do_generate_delta_v1_v2/v2_v3/v1_v3 - Generate binary diffs
      • do_verify_delta_v1_v2/v2_v3/v1_v3 - Verify delta reconstruction
      • do_verify_all_deltas - Aggregate verification
      • do_deploy - Deploy artifacts to deploy directory
    • Task dependencies:

do_generate_delta_v1_v2[depends] = "\
    adu-delta-image:do_recompress_and_sign_v1 \
    adu-delta-image:do_recompress_and_sign_v2 \
    iot-hub-device-update-delta-diffgentool-native:do_populate_sysroot \
"

do_verify_delta_v1_v2[depends] = "\
    adu-delta-image:do_generate_delta_v1_v2 \
    iot-hub-device-update-delta-processor-native:do_populate_sysroot \
"
  • Output files:
    • adu-delta-v1-to-v2.diff, adu-delta-v2-to-v3.diff, adu-delta-v1-to-v3.diff
    • adu-update-image-v*.0.0-recompressed.swu (3 files)
    • *.sha256 checksum files

BBClass: adu-timestamp-check.bbclass

Located in classes/:

  • Validates that delta files are newer than their source SWU files
  • Prevents accidental deployment of stale delta files
  • Only active when WITH_FEATURE_DELTA_UPDATE='1'
  • Automatically inherited by adu-delta-image.bb

Layer Configuration

Layer Dependencies

Defined in conf/layer.conf:

LAYERDEPENDS_meta-azure-device-update-samples = " \
    core \
    azure-device-update \
    iot-hub-device-update-delta \
    swupdate \
"

What each dependency provides:

Layer Purpose Key Components
core (openembedded-core) Base Yocto functionality BitBake, package management, toolchain
azure-device-update ADU agent infrastructure ADU agent recipes, configuration, device management
iot-hub-device-update-delta CRITICAL for delta generation bsdiff - Binary diff tool
DiffGenTool - C# PAMZ delta generator
applydiff - Delta reconstruction/verification
recompress - SWU recompression tool
libadudiffapi.so - Core delta library
Without this layer, delta generation will fail
swupdate SWUpdate packaging framework SWU creation, signing, CPIO handling
clang-layer (transitive) Clang compiler toolchain Required by iot-hub-device-update-delta

Default Variables

Defined in conf/distro/include/adu-samples-defaults.inc (not yet created, uses BitBake defaults):

# Software version for sample images (override in local.conf)
BASE_ADU_SOFTWARE_VERSION ?= "1.0.0"

# ADU manifest metadata (override in local.conf)
ADU_PROVIDER ?= "Contoso"
ADU_MODEL ?= "Video"

To customize: Add to your conf/local.conf:

BASE_ADU_SOFTWARE_VERSION = "2.5.0"
ADU_PROVIDER = "YourCompany"
ADU_MODEL = "YourDevice"

Version Strategy

Versions auto-increment based on BASE_ADU_SOFTWARE_VERSION:

BASE_ADU_SOFTWARE_VERSION = "1.0.0"  (set in local.conf)
  ↓
v1: ADU_SOFTWARE_VERSION = "1.0.0"   (${BASE_ADU_SOFTWARE_VERSION})
v2: ADU_SOFTWARE_VERSION = "2.0.0"   (${@oe.utils.inc_pr(BASE, 1)})
v3: ADU_SOFTWARE_VERSION = "3.0.0"   (${@oe.utils.inc_pr(BASE, 2)})

Note: This is a demonstration versioning strategy. Production systems should implement:

  • Semantic versioning (MAJOR.MINOR.PATCH)
  • Build number tracking
  • Git commit hash integration
  • Release branch management

This layer enables multiple Azure Device Update demonstration workflows:

Demo 1: Full-Image Update (Basic)

Requirements: ADU agent + device connection What it demonstrates: Installing a complete update package via Azure IoT Hub

Steps:

  1. Flash device with base image containing v1
  2. Upload adu-update-image-v2.swu and manifest to Azure Portal
  3. Deploy update to device via IoT Hub
  4. Device downloads and installs v2.swu (full package ~240MB)

Layer artifacts used: adu-update-image-v2.swu


Demo 2: Delta Update (Advanced)

Requirements: ADU agent + delta support enabled + sufficient storage What it demonstrates: Efficient updates using binary diff patches

Steps:

  1. Device running v1 (1.0.0)
  2. Upload adu-delta-v1-to-v2.diff and manifest to Azure
  3. Deploy delta update to device
  4. Device downloads tiny diff (~600 bytes vs 240MB full image)
  5. Device reconstructs v2 from v1 + diff
  6. Device installs reconstructed v2.swu

Layer artifacts used:

  • adu-delta-v1-to-v2.diff (tiny binary patch)
  • adu-update-image-v1.swu (required on device as source)

Benefits:

  • 99.9% bandwidth savings (600 bytes vs 240MB)
  • Faster OTA deployment
  • Lower cloud egress costs

Demo 3: Multi-Step Update Chain

Requirements: ADU agent + persistence layer What it demonstrates: Controlled rollout through multiple versions

Steps:

  1. Device at v1 (1.0.0)
  2. Update to v2 (1.0.1) - verify functionality
  3. Update to v3 (1.0.2) - demonstrate continuous updates
  4. Optional: Rollback from v3 → v2 → v1

Layer artifacts used:

  • adu-update-image-v1.swu
  • adu-update-image-v2.swu
  • adu-update-image-v3.swu
  • adu-delta-v1-to-v2.diff
  • adu-delta-v2-to-v3.diff

Demo 4: Import Manifest Generation

Requirements: Azure Device Update account What it demonstrates: Automated manifest creation for Azure Portal

Steps:

  1. Build images and manifests: bitbake adu-import-manifests
  2. Navigate to tmp/deploy/images/<MACHINE>/import-manifests/
  3. Find JSON manifests for each update package
  4. Import to Azure Portal via UI or CLI
  5. Deploy to device groups

Layer artifacts used: adu-import-manifests-v*.json


Feature Requirements Matrix

Feature Layer Components BSP Requirements External Requirements
Full Image Updates adu-update-image-v*.bb virtual/adu-base-image provider, Boot A/B slots Azure IoT Hub, ADU account
Delta Updates adu-delta-image.bb Same as above + storage for temp files ADU with delta support enabled
Manifest Generation adu-import-manifests.bb Image metadata (version, size) None (offline operation)
Version Testing All three versioned images Persistence across updates Test IoT Hub instance
Rollback Demo v1, v2, v3 images A/B boot slots with fallback ADU agent with rollback support

Customizing for Your Platform

Step 1: Create Your Base Image Recipe

In your BSP layer (e.g., meta-myboard/recipes-core/images/myboard-base.bb):

require recipes-core/images/core-image-minimal.bb

DESCRIPTION = "My board base image for ADU"

# Essential: Provide virtual interface
PROVIDES = "virtual/adu-base-image"

# Add your board-specific packages
IMAGE_INSTALL:append = " \
    myboard-firmware \
    myboard-drivers \
"

# Configure persistence, boot, etc.
inherit adu-filesystem-layout

Step 2: Configure local.conf

# Point to your base image
PREFERRED_PROVIDER_virtual/adu-base-image = "myboard-base"

# Set your company/model info
ADU_PROVIDER = "MyCompany"
ADU_MODEL = "MyDevice-v1"

# Configure signing keys
ADUC_PRIVATE_KEY = "${TOPDIR}/../keys/priv.pem"
ADUC_PRIVATE_KEY_PASSWORD = "${TOPDIR}/../keys/priv.pass"

Step 3: Build Samples

bitbake adu-update-image-v1

The sample images will automatically wrap your board's base image in SWUpdate format.


Layer Configuration

Default Variables (can be overridden)

Defined in conf/distro/include/adu-samples-defaults.inc:

# Software version for all samples
BASE_ADU_SOFTWARE_VERSION ?= "1.0.0"

# ADU manifest metadata
ADU_PROVIDER ?= "Contoso"
ADU_MODEL ?= "Video"

Layer Dependencies

Defined in conf/layer.conf:

LAYERDEPENDS_meta-azure-device-update-samples = " \
    core \
    azure-device-update \
    iot-hub-device-update-delta \
    swupdate \
"

What each dependency provides:

  • core (openembedded-core) - Base Yocto functionality
  • azure-device-update - ADU agent, configuration infrastructure, and device management
  • iot-hub-device-update-delta - Critical for delta generation:
    • bsdiff - Binary diff tool for efficient patch generation (enables 99.9% bandwidth savings)
    • Delta processor library for applying patches on devices
    • zstd integration for high-performance compression
    • Without this layer, delta generation will fail
  • swupdate - SWUpdate framework for creating atomic .swu update packages
  • clang-layer (transitive dependency via iot-hub-device-update-delta) - Clang compiler toolchain

Recipe Naming Convention

  • Samples: recipes-samples/images/adu-update-image-v*.bb
  • Delta: recipes-samples/delta-generation/adu-delta-image.bb
  • Manifests: recipes-samples/delta-generation/adu-import-manifests.bb


Troubleshooting

Build Issues

Issue: "Nothing PROVIDES virtual/adu-base-image"

Cause: Your BSP layer doesn't provide the required virtual interface.

Solution:

  1. Add to your base image recipe:

    PROVIDES = "virtual/adu-base-image"
  2. Set preferred provider in local.conf:

    PREFERRED_PROVIDER_virtual/adu-base-image = "your-base-image-name"
  3. Verify with:

    bitbake-getvar PREFERRED_PROVIDER_virtual/adu-base-image

Issue: "ERROR: adu-delta-image do_generate_delta_v1_v2: Recompressed file not found"

Cause: Recompression tasks failed or didn't run.

Solution:

  1. Check recompression logs:

    cat tmp/work/*/adu-delta-image/*/temp/log.do_recompress_and_sign_v1
  2. Verify signing keys exist:

    ls -l $ADUC_PRIVATE_KEY $ADUC_PRIVATE_KEY_PASSWORD
  3. Check original .swu files were created:

    ls -lh tmp/deploy/images/<MACHINE>/adu-update-image-v*.swu

Issue: "Delta verification failed - reconstructed file does not match target"

Cause: Delta file is corrupted or base images contain non-reproducible content.

Solution:

  1. Check verification logs for specific failure:

    grep -A 10 "FAIL" tmp/work/*/adu-delta-image/*/temp/log.do_verify_delta*
  2. Verify SHA256 mismatch:

    # Compare expected vs actual hashes in log output
  3. Ensure reproducible builds:

    # In your base image recipe
    INHERIT += "reproducible_build"
    SOURCE_DATE_EPOCH = "1609459200"  # Fixed timestamp
  4. Clean and rebuild:

    bitbake -c cleansstate adu-delta-image
    bitbake adu-delta-image

Delta Generation Issues

Issue: Delta files are unexpectedly large (>50MB)

Cause: Base images contain volatile data or non-reproducible timestamps.

Analysis:

# Compare file contents
cpio -it < v1-recompressed.swu > v1-files.txt
cpio -it < v2-recompressed.swu > v2-files.txt
diff v1-files.txt v2-files.txt

# Check for timestamp differences
sudo mount -o loop,ro v1.ext4 /mnt/v1
sudo mount -o loop,ro v2.ext4 /mnt/v2
diff -r /mnt/v1 /mnt/v2

Solution:

  • Remove logs and volatile files from rootfs:
    ROOTFS_POSTPROCESS_COMMAND += "remove_volatile_data;"
    remove_volatile_data() {
        rm -rf ${IMAGE_ROOTFS}/var/log/*
        rm -rf ${IMAGE_ROOTFS}/tmp/*
    }
  • Enable reproducible builds (see above)
  • Mask timestamps in ext4 filesystem

Issue: "applydiff: error while loading shared libraries: libjsoncpp.so.25"

Cause: Missing native library dependencies for applydiff tool.

Solution: This should be automatic in the recipe. If you see this error, check:

# Verify processor-native is built
bitbake -e iot-hub-device-update-delta-processor-native | grep ^STAGING_LIBDIR_NATIVE

# Check library exists
find tmp/sysroots-components/x86_64 -name "libjsoncpp.so.25"

Workaround: The recipe automatically sets LD_LIBRARY_PATH in verification tasks. If still failing, manually check:

# Review verification task environment
cat tmp/work/*/adu-delta-image/*/temp/log.do_verify_delta_v1_v2

Issue: "DiffGenTool: Archive is not diffable - Target archive is not diffable"

Cause: SWU files contain gzip-compressed .ext4.gz files, which DiffGenTool cannot process directly.

Solution: This is why the recompression step exists! The recipe automatically:

  1. Extracts .swu archives
  2. Decompresses .ext4.gz → .ext4
  3. Recompresses with PAMZ-compatible format

If you still see this error, verify recompression worked:

# Check recompressed file structure
cpio -it < adu-update-image-v1.0.0-recompressed.swu
# Expected output:
# sw-description
# sw-description.sig
# adu-update-image-v1-<MACHINE>.ext4.gz  (must be .gz, not .pamz yet)

Configuration Issues

Issue: "WARNING: BBFILE_COLLECTIONS version mismatch"

Cause: LAYERSERIES_COMPAT mismatch between layers.

Solution: Update conf/layer.conf:

LAYERSERIES_COMPAT_meta-azure-device-update-samples = "scarthgap"

Issue: RSA signature verification fails on device

Cause: Public key mismatch between build-time signing and device-side verification.

Solution:

  1. Verify keys match:

    openssl rsa -in $ADUC_PRIVATE_KEY -pubout -out /tmp/pubkey.pem
    diff /tmp/pubkey.pem $ADUC_PUBLIC_KEY
  2. Ensure device has correct public key:

    # On device
    cat /etc/swupdate/public.pem
  3. Rebuild with correct keys:

    bitbake -c cleansstate adu-update-image-v1 adu-delta-image
    bitbake adu-update-image-v1 adu-delta-image

Testing and Validation

Verify Delta Generation Pipeline

# 1. Build all components
bitbake adu-update-image-v1 adu-update-image-v2 adu-update-image-v3 adu-delta-image

# 2. Check all outputs exist
ls -lh tmp/deploy/images/<MACHINE>/adu-delta*.diff
ls -lh tmp/deploy/images/<MACHINE>/adu-update-image-v*.0.0-recompressed.swu

# 3. Verify delta integrity (automatic during build)
grep "✅ SUCCESS" tmp/work/*/adu-delta-image/*/temp/log.do_verify_delta*

# 4. Check delta sizes (should be reasonable for your content changes)
du -h tmp/deploy/images/<MACHINE>/adu-delta*.diff

# 5. Verify signature files
for f in tmp/deploy/images/<MACHINE>/*-recompressed.swu; do
    echo "=== $f ==="
    cpio -it < "$f" | grep sig
done


Reference Workflow: Adapting for Your Product

This layer demonstrates a complete delta generation workflow that device builders and update builders can adapt for their own products. Follow these steps to customize for your hardware platform and update strategy:

Step 1: Create Your Base Image Recipe

In your BSP layer (e.g., meta-myboard/recipes-core/images/myboard-adu-base.bb):

require recipes-core/images/core-image-minimal.bb

DESCRIPTION = "My device base image for ADU updates"

# CRITICAL: Provide virtual interface for samples layer
PROVIDES = "virtual/adu-base-image"

# Add your hardware-specific packages
IMAGE_INSTALL:append = " \
    myboard-firmware \
    myboard-drivers \
    myboard-config \
    azure-device-update-agent \
"

# Configure A/B update infrastructure
inherit adu-filesystem-layout swupdate-image

# Board-specific partition layout
ADU_PARTITION_LAYOUT = "dual-rootfs"

Step 2: Configure BitBake Variables

In your conf/local.conf:

# Point to your base image
PREFERRED_PROVIDER_virtual/adu-base-image = "myboard-adu-base"

# Set your product metadata
ADU_PROVIDER = "MyCompany"
ADU_MODEL = "MyProduct-v2"
BASE_ADU_SOFTWARE_VERSION = "1.0.0"

# Configure signing keys (generate with: openssl genrsa -aes256 -out priv.pem 2048)
ADUC_PRIVATE_KEY = "${TOPDIR}/../keys/priv.pem"
ADUC_PRIVATE_KEY_PASSWORD = "${TOPDIR}/../keys/priv.pass"
ADUC_PUBLIC_KEY = "${TOPDIR}/../keys/public.pem"

Step 3: Build Your Versioned Updates

# Build base version
bitbake adu-update-image-v1

# Build subsequent versions (customize version markers in v2/v3 recipes)
bitbake adu-update-image-v2 adu-update-image-v3

Customize version markers: Edit recipes-samples/images/adu-update-image-v*.bb to add your product-specific changes:

# In adu-update-image-v2.bb
do_install:append() {
    # Add your v2-specific changes here
    echo "MyProduct v2.0.0 - Added feature X" > ${D}/etc/product-version
    install -m 0644 ${WORKDIR}/my-v2-config ${D}/etc/my-config
}

Step 4: Generate and Verify Deltas

# Generate deltas with automatic verification
bitbake adu-delta-image

# Verify outputs
ls -lh tmp/deploy/images/<MACHINE>/adu-delta*.diff
cat tmp/work/<MACHINE>/adu-delta-image/*/temp/log.do_verify_delta*

Expected verification output:

NOTE: ✅ SUCCESS: v1 + delta-v1-v2 = v2 (verified)
NOTE: ✅ SUCCESS: v2 + delta-v2-v3 = v3 (verified)
NOTE: ✅ SUCCESS: v1 + delta-v1-v3 = v3 (verified)

Step 5: Customize Delta Generation Workflow (Advanced)

For production use, you may want to:

A. Add More Versions

# Copy and customize adu-update-image-v3.bb → v4.bb
cp recipes-samples/images/adu-update-image-v3.bb \
   recipes-samples/images/adu-update-image-v4.bb

# Update version increment
ADU_SOFTWARE_VERSION = "${@oe.utils.inc_pr("BASE_ADU_SOFTWARE_VERSION", 3)}"

B. Modify Delta Generation Strategy Edit recipes-samples/delta-generation/adu-delta-image.bb:

# Example: Only generate v1→v2 and v2→v3 deltas (skip v1→v3)
addtask generate_delta_v1_v2 after do_recompress_and_sign_v2
addtask generate_delta_v2_v3 after do_recompress_and_sign_v3
# Remove: addtask generate_delta_v1_v3

C. Integrate with CI/CD

# Example Jenkins/GitHub Actions workflow
bitbake adu-update-image-v1 adu-update-image-v2 adu-update-image-v3
bitbake adu-delta-image

# Check verification logs
if grep -q "❌ FAIL" tmp/work/*/adu-delta-image/*/temp/log.do_verify*; then
    echo "Delta verification failed!"
    exit 1
fi

# Upload artifacts to Azure Storage
az storage blob upload-batch \
    --source tmp/deploy/images/$MACHINE \
    --destination adu-updates \
    --pattern "adu-delta*.diff"

Demonstration Scenarios

This layer enables multiple Azure Device Update demonstration workflows:

Demo 1: Full-Image Update (Basic)

Target Audience: Device builders learning ADU basics Requirements: ADU agent + device connection What it demonstrates: Installing a complete update package via Azure IoT Hub

Steps:

  1. Flash device with base image containing v1.0.0
  2. Upload adu-update-image-v2.0.0.swu and manifest to Azure Portal
  3. Deploy update to device via IoT Hub
  4. Device downloads and installs v2.0.0 (full package ~240MB)

Layer artifacts used: adu-update-image-v2.0.0.swu

Key Learning: Basic ADU deployment flow, SWUpdate integration, A/B update mechanisms


Demo 2: Delta Update (Advanced)

Target Audience: Update builders optimizing bandwidth and deployment speed Requirements: ADU agent + delta support enabled + sufficient storage What it demonstrates: Efficient updates using binary diff patches

Steps:

  1. Device running v1.0.0 (has adu-update-image-v1.0.0-recompressed.swu stored)
  2. Upload adu-delta-v1-to-v2.diff to Azure Storage
  3. Deploy delta update via IoT Hub
  4. Device downloads delta (~20MB vs ~240MB full image)
  5. ADU agent reconstructs v2.0.0 from: v1.0.0-recompressed.swu + delta
  6. ADU agent installs reconstructed v2.0.0.swu

Layer artifacts used:

  • adu-delta-v1-to-v2.diff (binary patch)
  • adu-update-image-v1.0.0-recompressed.swu (stored on device as source)

Benefits:

  • ~91% bandwidth savings (20MB delta vs 240MB full image for this sample)
  • Faster deployment over cellular/satellite connections
  • Lower cloud egress costs
  • Reduced update time

Key Learning: Delta generation workflow, recompression requirements, reconstruction verification


Demo 3: Multi-Version Update Chain

Target Audience: Product teams planning staged rollouts Requirements: ADU agent + A/B update support + rollback capability What it demonstrates: Controlled rollout through multiple versions, testing update chaining

Steps:

  1. Device at v1.0.0 (initial deployment)
  2. Deploy delta v1→v2 (1.0.0 → 2.0.0) - verify functionality
  3. Deploy delta v2→v3 (2.0.0 → 3.0.0) - demonstrate continuous updates
  4. Optional: Rollback v3→v2→v1 using stored versions

Layer artifacts used:

  • All three versioned .swu files
  • All three delta files
  • Recompressed files for each version

Key Learning: Update chaining, version management, delta applicability across multiple hops


Contributing

This layer serves as a reference implementation for the Azure Device Update community. Contributions that improve the delta generation workflow or add educational value are welcome.

Areas for contribution:

  • Additional demonstration scenarios and use cases
  • Improved documentation and troubleshooting guides
  • Performance optimizations for delta generation
  • Test automation and validation scripts
  • Platform-agnostic best practices (in documentation, not code)

Not in scope for this layer:

  • Board-specific implementations (create separate BSP layers)
  • Production-ready versioning strategies (each product is different)
  • Cloud integration code (belongs in ADU agent repositories)

How to contribute:

  1. File issues for bugs or unclear documentation
  2. Submit pull requests with clear descriptions
  3. Add comments and documentation for complex workflows
  4. Test on your hardware platform and share results

License

This layer is licensed under the MIT License.

See LICENSE file for full text.

Key points:

  • Free to use for commercial and non-commercial purposes
  • Modify and redistribute as needed
  • No warranty provided (demonstration/reference code)
  • Attribution appreciated but not required

Related Documentation

Azure Device Update Resources

Component Documentation

Yocto/BitBake Resources

Repository Documentation


Support and Contact

For Issues Related To:

This samples layer:

ADU Agent or Service:

Delta Library:

Yocto/BitBake:


Maintainers

Azure Device Update Team


Quick Reference

┌─────────────────────────────────────────────────────────────┐
│  meta-azure-device-update-samples - Quick Reference        │
├─────────────────────────────────────────────────────────────┤
│  PURPOSE: Board-agnostic delta generation reference         │
│  AUDIENCE: Device builders, update builders                 │
│  SCOPE: Demonstration/reference only (not production)       │
├─────────────────────────────────────────────────────────────┤
│  REQUIRED VARIABLES (conf/local.conf):                      │
│    PREFERRED_PROVIDER_virtual/adu-base-image = "..."        │
│    ADUC_PRIVATE_KEY = "/path/to/priv.pem"                   │
│    ADUC_PRIVATE_KEY_PASSWORD = "/path/to/priv.pass"         │
├─────────────────────────────────────────────────────────────┤
│  BUILD:                                                     │
│    bitbake adu-update-image-v1 adu-update-image-v2 ...      │
│    bitbake adu-delta-image  # Generates & verifies deltas   │
├─────────────────────────────────────────────────────────────┤
│  OUTPUT: tmp/deploy/images/<MACHINE>/                       │
│    • adu-update-image-v*.0.0.swu         (Originals)        │
│    • adu-update-image-v*.0.0-recompressed.swu (Sources)     │
│    • adu-delta-v*-to-v*.diff             (Binary diffs)     │
│    • *.sha256                            (Checksums)        │
├─────────────────────────────────────────────────────────────┤
│  VERIFICATION: Automatic (build fails if deltas invalid)    │
│    Check: tmp/work/.../log.do_verify_delta_*                │
└─────────────────────────────────────────────────────────────┘

About

Board-agnostic Yocto layer for Azure Device Update demos: delta generation, versioned sample images, and ADU feature testing independent of hardware platforms.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors