Introduction to Recovery OTA
In the early days of Android, Over-The-Air (OTA) updates were delivered and applied through a specialized, minimal Linux environment known as Recovery Mode. This legacy method, while simple, required the device to reboot out of the main Android OS, resulting in user-visible downtime while the update was applied.
Although modern Android devices primarily use A/B (Seamless) updates or Virtual A/B, Recovery OTA remains essential for understanding the evolution of Android updates, and it is still used in specific embedded or low-cost devices.
The OTA Package Format
A Recovery OTA package is typically a zip archive containing the new system images, an updater binary, and a script.
Key Components of an OTA Zip:
META-INF/com/google/android/updater-script: The instructions for applying the update.META-INF/com/google/android/update-binary: The executable that parses and runs the updater script.payload.bin(or traditional patches/images): The actual update payload. Modern recovery OTAs often use apayload.binsimilar to A/B updates, adapting it for recovery application.
Updater Script and the Edify Language
The updater-script uses a specialized, simple scripting language called Edify. The update-binary interprets these Edify commands to perform actions like formatting partitions, unpacking files, and verifying signatures.
Example: Edify Script Snippet
getprop("ro.product.device") == "marlin" || abort("E3004: This package is for marlin devices.");
ui_print("Patching system image...");
block_image_update("/dev/block/bootdevice/by-name/system", package_extract_file("system.transfer.list"), "system.new.dat.br", "system.patch.dat");
ui_print("Update complete!");
In the Android open-source project (AOSP), the Edify language parser and functions are defined in C++ under bootable/recovery/edify/.
Edify Function Registration (C++)
// bootable/recovery/updater/install.cpp
void RegisterInstallFunctions() {
RegisterFunction("mount", MountFn);
RegisterFunction("is_mounted", IsMountedFn);
RegisterFunction("unmount", UnmountFn);
RegisterFunction("format", FormatFn);
RegisterFunction("show_progress", ShowProgressFn);
RegisterFunction("set_progress", SetProgressFn);
RegisterFunction("package_extract_file", PackageExtractFileFn);
RegisterFunction("getprop", GetPropFn);
}
Sideloading OTA via ADB
During development or recovery, users can manually apply an OTA zip without downloading it directly on the device using adb sideload.
When you select "Apply update from ADB" in the recovery menu, the device starts an adbd daemon in sideload mode.
How to Sideload:
- Reboot to recovery:
adb reboot recovery - Select "Apply update from ADB" using device buttons.
- Execute the sideload command on the host machine:
adb sideload ota_package.zip
Behind the scenes, the ADB client on the host acts as a server that streams the zip file chunks to the recovery daemon as requested by the update-binary.
Limitations of Recovery OTA
The transition to A/B updates was driven by several critical limitations of the Recovery OTA architecture:
- Significant Downtime: The user cannot use the device for the entire duration of the update process (often 10 to 20 minutes).
- Risk of Bricking: If the power fails during the
block_image_updateprocess or if an I/O error occurs, the partition is left corrupted. - Storage Requirements: The device needs enough
/cacheor/dataspace to store the downloaded OTA zip before rebooting into recovery. - Lack of Seamless Rollback: If an update fails to boot after installation, there is no automatic fallback mechanism to the previous working build.