Board-agnostic Yocto layer for Azure Device Update delta generation, testing, and reference workflows
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
This layer provides a platform-independent reference implementation showing how to:
- Automate delta generation between SWUpdate update packages
- Integrate with BitBake build workflows for repeatable, auditable delta creation
- Verify delta integrity automatically during the build process
- Structure versioned update artifacts for Azure Device Update deployment
- ✅ 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
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.
┌────────────────────────────────────────────────────────────────────┐
│ 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.
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 imageRequired 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 supportThe 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# 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-v3Output: Three signed SWUpdate packages in tmp/deploy/images/<MACHINE>/
# Generate all delta files with automatic verification
bitbake adu-delta-imageWhat happens during the build:
-
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.swufiles (3 files each: sw-description, sw-description.sig, image)
-
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
.difffiles
-
Verification Phase (Tasks:
do_verify_delta_v1_v2/v2_v3/v1_v3) ← AUTOMATIC QUALITY CHECK- Uses C++
applydifftool 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)
- Uses C++
-
Deployment Phase (
do_deploy)- Copies
.diffand*-recompressed.swufiles to deploy directory - Generates SHA256 checksum files for each artifact
- Copies
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)*.sha256checksum 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.
Located in recipes-samples/images/:
-
adu-update-image-v1.bb- Base version (v1.0.0)- Wraps
virtual/adu-base-imagein signed SWUpdate package - Sets
ADU_SOFTWARE_VERSION = "${BASE_ADU_SOFTWARE_VERSION}" - Inherits:
swupdate-image - Output:
adu-update-image-v1.0.0-<MACHINE>.swu
- Wraps
-
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
- Uses
-
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
- Uses
Key Recipe Dependencies:
DEPENDS = "virtual/adu-base-image swupdate-native openssl-native"
do_swuimage[depends] = "${PN}:do_image_complete"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 filesdo_generate_delta_v1_v2/v2_v3/v1_v3- Generate binary diffsdo_verify_delta_v1_v2/v2_v3/v1_v3- Verify delta reconstructiondo_verify_all_deltas- Aggregate verificationdo_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.diffadu-update-image-v*.0.0-recompressed.swu(3 files)*.sha256checksum files
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
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 libraryWithout 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 |
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"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:
Requirements: ADU agent + device connection What it demonstrates: Installing a complete update package via Azure IoT Hub
Steps:
- Flash device with base image containing v1
- Upload
adu-update-image-v2.swuand manifest to Azure Portal - Deploy update to device via IoT Hub
- Device downloads and installs v2.swu (full package ~240MB)
Layer artifacts used: adu-update-image-v2.swu
Requirements: ADU agent + delta support enabled + sufficient storage What it demonstrates: Efficient updates using binary diff patches
Steps:
- Device running v1 (1.0.0)
- Upload
adu-delta-v1-to-v2.diffand manifest to Azure - Deploy delta update to device
- Device downloads tiny diff (~600 bytes vs 240MB full image)
- Device reconstructs v2 from v1 + diff
- 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
Requirements: ADU agent + persistence layer What it demonstrates: Controlled rollout through multiple versions
Steps:
- Device at v1 (1.0.0)
- Update to v2 (1.0.1) - verify functionality
- Update to v3 (1.0.2) - demonstrate continuous updates
- Optional: Rollback from v3 → v2 → v1
Layer artifacts used:
adu-update-image-v1.swuadu-update-image-v2.swuadu-update-image-v3.swuadu-delta-v1-to-v2.diffadu-delta-v2-to-v3.diff
Requirements: Azure Device Update account What it demonstrates: Automated manifest creation for Azure Portal
Steps:
- Build images and manifests:
bitbake adu-import-manifests - Navigate to
tmp/deploy/images/<MACHINE>/import-manifests/ - Find JSON manifests for each update package
- Import to Azure Portal via UI or CLI
- Deploy to device groups
Layer artifacts used: adu-import-manifests-v*.json
| 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 |
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# 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"bitbake adu-update-image-v1The sample images will automatically wrap your board's base image in SWUpdate format.
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"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
- 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
Cause: Your BSP layer doesn't provide the required virtual interface.
Solution:
-
Add to your base image recipe:
PROVIDES = "virtual/adu-base-image"
-
Set preferred provider in
local.conf:PREFERRED_PROVIDER_virtual/adu-base-image = "your-base-image-name"
-
Verify with:
bitbake-getvar PREFERRED_PROVIDER_virtual/adu-base-image
Cause: Recompression tasks failed or didn't run.
Solution:
-
Check recompression logs:
cat tmp/work/*/adu-delta-image/*/temp/log.do_recompress_and_sign_v1
-
Verify signing keys exist:
ls -l $ADUC_PRIVATE_KEY $ADUC_PRIVATE_KEY_PASSWORD
-
Check original .swu files were created:
ls -lh tmp/deploy/images/<MACHINE>/adu-update-image-v*.swu
Cause: Delta file is corrupted or base images contain non-reproducible content.
Solution:
-
Check verification logs for specific failure:
grep -A 10 "FAIL" tmp/work/*/adu-delta-image/*/temp/log.do_verify_delta*
-
Verify SHA256 mismatch:
# Compare expected vs actual hashes in log output -
Ensure reproducible builds:
# In your base image recipe INHERIT += "reproducible_build" SOURCE_DATE_EPOCH = "1609459200" # Fixed timestamp
-
Clean and rebuild:
bitbake -c cleansstate adu-delta-image bitbake adu-delta-image
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/v2Solution:
- 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
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_v2Cause: SWU files contain gzip-compressed .ext4.gz files, which DiffGenTool cannot process directly.
Solution: This is why the recompression step exists! The recipe automatically:
- Extracts .swu archives
- Decompresses .ext4.gz → .ext4
- 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)Cause: LAYERSERIES_COMPAT mismatch between layers.
Solution: Update conf/layer.conf:
LAYERSERIES_COMPAT_meta-azure-device-update-samples = "scarthgap"Cause: Public key mismatch between build-time signing and device-side verification.
Solution:
-
Verify keys match:
openssl rsa -in $ADUC_PRIVATE_KEY -pubout -out /tmp/pubkey.pem diff /tmp/pubkey.pem $ADUC_PUBLIC_KEY
-
Ensure device has correct public key:
# On device cat /etc/swupdate/public.pem -
Rebuild with correct keys:
bitbake -c cleansstate adu-update-image-v1 adu-delta-image bitbake adu-update-image-v1 adu-delta-image
# 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
doneThis 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:
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"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"# 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-v3Customize 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
}# 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)
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_v3C. 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"This layer enables multiple Azure Device Update demonstration workflows:
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:
- Flash device with base image containing v1.0.0
- Upload
adu-update-image-v2.0.0.swuand manifest to Azure Portal - Deploy update to device via IoT Hub
- 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
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:
- Device running v1.0.0 (has
adu-update-image-v1.0.0-recompressed.swustored) - Upload
adu-delta-v1-to-v2.diffto Azure Storage - Deploy delta update via IoT Hub
- Device downloads delta (~20MB vs ~240MB full image)
- ADU agent reconstructs v2.0.0 from: v1.0.0-recompressed.swu + delta
- 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
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:
- Device at v1.0.0 (initial deployment)
- Deploy delta v1→v2 (1.0.0 → 2.0.0) - verify functionality
- Deploy delta v2→v3 (2.0.0 → 3.0.0) - demonstrate continuous updates
- 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
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:
- File issues for bugs or unclear documentation
- Submit pull requests with clear descriptions
- Add comments and documentation for complex workflows
- Test on your hardware platform and share results
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
- SWUpdate Project - Update framework
- iot-hub-device-update - ADU agent source
- iot-hub-device-update-delta - Delta library
- iot-hub-device-update-yocto Main README - Build environment guide
- meta-raspberrypi-adu README - Reference BSP example
This samples layer:
- File issues in iot-hub-device-update-yocto
- Tag with
samples-layerordelta-generation
ADU Agent or Service:
- See iot-hub-device-update
- Azure support channels for service issues
Delta Library:
Yocto/BitBake:
Azure Device Update Team
- Repository: iot-hub-device-update-yocto
┌─────────────────────────────────────────────────────────────┐
│ 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_* │
└─────────────────────────────────────────────────────────────┘