Modern Android smartphones and tablets use seamless system updates (also known as A/B system updates) to eliminate prolonged downtime during operating system upgrades. Instead of booting into a dedicated recovery environment and freezing the device during an install, Android maintains two complete sets of bootable disk partitions (known as slot _a and slot _b). While the user actively uses the operating system running on the active slot, the system update daemon downloads, verifies, and flashes new system partitions to the inactive slot in the background.
The core daemon orchestrating this background upgrade process is update_engine. When debugging failed over-the-air (OTA) updates, testing enterprise device updates via mobile device management (MDM) platforms, or inspecting partition health on custom Android builds, the Android Debug Bridge (ADB) provides deep visibility into the daemon through dumpsys update_engine and the update_engine_client command-line utility.
Architecture of Android A/B Seamless Updates
Seamless updates rely on hardware bootloader support and partitioned storage layout. Core partitions—including boot, init_boot, vendor_boot, system, vendor, product, and system_ext—exist as paired slot partitions (for example, system_a and system_b). The user data partition (userdata) remains unified and shared across both slots.
The update lifecycle follows distinct sequential states managed by update_engine:
- IDLE: The daemon is inactive, waiting for an OTA trigger from Google Play Services, carrier software, or system settings.
- CHECKING_FOR_UPDATE: The update client contacts the update server to parse payload metadata and cryptographic signatures.
- DOWNLOADING_AND_UPDATING: The daemon streams partition diffs or full images directly into the inactive partition slot via block-level writing.
- VERIFYING: Post-install cryptographic hashing verifies SHA-256 signatures across the written inactive partitions.
- FINALIZING: The daemon instructs the boot control hardware abstraction layer (HAL) to mark the inactive slot as
bootableand sets it as the next boot target. - UPDATED_NEED_REBOOT: The system waits for the user or enterprise policy to restart the device. Upon reboot, the bootloader attempts to launch the new slot.
Inspecting update_engine Diagnostics via dumpsys
To inspect the current status and internal memory metrics of the update engine, connect your Android device with USB debugging enabled and execute dumpsys update_engine via ADB:
# Query the update engine status via dumpsys
adb shell dumpsys update_engine
The command dumps the daemon’s runtime state, current operation progress, and compilation metadata:
Current Status:
Status: IDLE
Progress: 0.00
New Version:
New Size: 0
Active slot: _a
Target slot: _b
Boot control HAL: [email protected]::IBootControl/default
If an update is actively downloading or applying in the background, the output reflects the real-time operational status and floating-point completion progress:
Current Status:
Status: DOWNLOADING_AND_UPDATING
Progress: 0.64
New Version: UP1A.231005.007
New Size: 1845892014
Monitoring Live Progress with update_engine_client
While dumpsys provides a static snapshot of the service state, Android includes a dedicated command-line client, update_engine_client, which allows interactive querying and live event streaming from the daemon.
To query the immediate status using the client utility:
# Query status using the native update engine client
adb shell update_engine_client --status
The client formats the output into clean key-value pairs suitable for parsing by automated testing scripts:
CURRENT_OP=UPDATE_STATUS_DOWNLOADING
PROGRESS=0.725831
NEW_VERSION=14.0.0_r28
NEW_SIZE=1924510920
To monitor an ongoing update continuously without polling in a loop, attach to the event stream using the --follow parameter:
# Stream real-time update progress events to the console
adb shell update_engine_client --follow
The client remains connected, outputting progress updates as each block group is written to the inactive slot. Press Ctrl + C at any time to disconnect without interrupting the background update.
Inspecting Active and Inactive Partition Slots via Bootctl
To understand which physical partition slot is currently executing and which slot will be loaded upon the next restart, use the bootctl hardware abstraction interface alongside getprop:
# Identify the currently active boot slot suffix
adb shell getprop ro.boot.slot_suffix
The terminal returns either _a or _b. To inspect full slot health and bootability metrics, invoke bootctl:
# List available slots and boot statuses
adb shell bootctl get-number-slots
adb shell bootctl get-current-slot
To verify whether both slots are marked as bootable or successful:
# Check if slot 0 (Slot A) is marked bootable (returns 1 for true, 0 for false)
adb shell bootctl is-slot-bootable 0
# Check if slot 0 is marked successful
adb shell bootctl is-slot-marked-successful 0
# Check if slot 1 (Slot B) is marked bootable
adb shell bootctl is-slot-bootable 1
# Check if slot 1 is marked successful
adb shell bootctl is-slot-marked-successful 1
Cancelling and Resetting Pending Updates
In testing environments where an erroneous OTA build was pushed or an enterprise staging profile must be cancelled before rebooting, you can instruct update_engine to abort the pending operation:
# Cancel an active update operation
adb shell update_engine_client --cancel
If an update has already completed and the device is waiting in the UPDATED_NEED_REBOOT state, resetting the daemon status forces update_engine to revert the target boot slot back to the currently running slot:
# Reset update engine state back to IDLE
adb shell update_engine_client --reset_status
After resetting the status, re-verify with adb shell update_engine_client --status to ensure that CURRENT_OP=UPDATE_STATUS_IDLE is restored, guaranteeing that subsequent reboots remain safely on the established active slot.