This document describes Magisk's addon.d survival mechanism, which enables Magisk to automatically re-install itself after an OTA (Over-The-Air) update on ROMs that support the addon.d standard. The addon.d system allows third-party modifications to persist across system updates by providing hooks that execute during the OTA installation process.
This page covers the installation of the addon.d script, the execution flow during OTA updates, and the differences between addon.d v1 (A-only devices) and v2 (A/B devices). For information about the initial Magisk installation and boot image patching process, see Boot Image Patching Workflow. For details about the installation scripts themselves, see Installation Scripts.
The addon.d survival mechanism operates by placing a script at /system/addon.d/99-magisk.sh that the ROM's OTA update system calls at various stages of the update process. This script hooks into the OTA workflow, allowing Magisk to re-patch the new boot image after the system partition has been updated but before the device reboots into the new system.
Sources: scripts/addon.d.sh1-169 scripts/util_functions.sh429-452
The addon.d survival script is installed during Magisk installation if the system supports addon.d. The presence of the /system/addon.d directory indicates addon.d support.
The installation process is handled by flash_script.sh:
| Step | Action | Location |
|---|---|---|
| 1 | Check for /system/addon.d directory | scripts/flash_script.sh81 |
| 2 | Remount system partition as read-write | scripts/flash_script.sh83-84 |
| 3 | Copy addon.d.sh to /system/addon.d/99-magisk.sh | scripts/flash_script.sh85-86 |
| 4 | Set executable permissions (755) | scripts/flash_script.sh87 |
Sources: scripts/flash_script.sh80-88
The addon.d script uses a trampoline pattern to ensure execution always occurs from the persistent /data/adb/magisk location rather than from the /system/addon.d location, which may be modified during OTA.
The trampoline redirects execution to /data/adb/magisk/addon.d.sh if the script is being executed from the system partition:
Sources: scripts/addon.d.sh10-47
If /data/adb/magisk/addon.d.sh is not found, the trampoline displays an error message indicating that either:
Sources: scripts/addon.d.sh36-41
Magisk supports both addon.d v1 and v2 protocols, which differ in their execution model and target device types.
| Protocol | Version Identifier | Device Type | Execution Model | Key Difference |
|---|---|---|---|---|
| v1 | ADDOND_VERSION=2 in script | A-only (non-A/B) | Background process | Runs asynchronously after 5s delay |
| v2 | Detected by backuptool.functions | A/B devices | Direct execution | Runs synchronously in current shell |
Sources: scripts/addon.d.sh49-59 scripts/addon.d.sh154-167
The addon.d protocol defines multiple execution phases during an OTA update. Magisk implements logic for specific phases while leaving others as stubs.
| Phase | When Called | Magisk Implementation | Purpose |
|---|---|---|---|
backup | Before OTA applied | Stub (no-op) | ROM framework backs up files |
restore | After OTA applied | Stub (no-op) | ROM framework restores files |
pre-backup | Before backup phase | Active (A-only only) | Extract PREINITDEVICE config |
post-backup | After backup phase | Stub (no-op) | Not used |
pre-restore | Before restore phase | Stub (no-op) | Not used |
post-restore | After restore phase | Active (main logic) | Re-install Magisk |
Sources: scripts/addon.d.sh129-168
On A-only devices, the pre-backup phase extracts the PREINITDEVICE configuration from the existing boot image before the OTA is applied. This is necessary because A-only devices maintain a single system partition that gets completely replaced.
The extraction process:
find_boot_image() to locate the current boot partitionmagiskboot unpack to extract the boot imagemagiskboot cpio to extract .backup/.magisk config fileconfig.orig for use in post-restore phasemagiskboot cleanup to remove temporary filesSources: scripts/addon.d.sh136-145
The post-restore phase is where the main Magisk re-installation occurs. This phase executes differently based on the addon.d protocol version:
For A-only devices, the script waits 5 seconds after addon.d-v1 completes, then runs main() in a background process:
This background execution is necessary because the addon.d-v1 system expects the script to exit quickly. The 5-second delay ensures that other addon.d-v1 processes have finished.
Sources: scripts/addon.d.sh159-162
For A/B devices, the script immediately spawns a new shell process with elevated privileges:
This executes the script again with the addond-v2 argument, which triggers the main() function directly.
Sources: scripts/addon.d.sh155-158
The main() function orchestrates the complete Magisk re-installation process after an OTA update.
Sources: scripts/addon.d.sh73-127
For A/B devices using addon.d v2, the script must swap the slot identifier because the OTA system updates the inactive slot:
| Current Slot | After OTA | Script Swaps To | Reason |
|---|---|---|---|
_a | System on _b | _b | Need to patch the newly updated slot |
_b | System on _a | _a | Need to patch the newly updated slot |
The swap logic:
This ensures that find_boot_image() targets the correct boot partition containing the newly installed system.
Sources: scripts/addon.d.sh100-108
The install_magisk() function, defined in util_functions.sh, serves as the bridge between the addon.d script and the boot patching logic.
Sources: scripts/util_functions.sh430-452 scripts/boot_patch.sh1-270
| Operation | Function | Purpose |
|---|---|---|
| Change directory | cd $MAGISKBIN | Ensure binaries are accessible |
| Set source mode | SOURCEDMODE=true | Tell boot_patch.sh it's being sourced |
| Source patcher | . ./boot_patch.sh "$BOOTIMAGE" | Execute patching logic |
| Flash image | flash_image new-boot.img "$BOOTIMAGE" | Write patched boot to device |
| Cleanup | ./magiskboot cleanup | Remove temporary files |
| Migrations | run_migrations() | Update backup structure |
Sources: scripts/util_functions.sh431-452
The addon.d script includes error handling for various failure scenarios.
If /data/adb/magisk/addon.d.sh is not found during the trampoline, the script displays an error message to the user:
***********************
Magisk addon.d failed
***********************
! Cannot find Magisk binaries - was data wiped or not decrypted?
! Reflash OTA from decrypted recovery or reflash Magisk
This occurs when:
Sources: scripts/addon.d.sh36-40
If find_boot_image() cannot locate a target boot partition, the script aborts with an error:
! Unable to detect target image
This can occur on devices with non-standard partition layouts or when the device uses an unsupported boot configuration.
Sources: scripts/addon.d.sh111-112 scripts/util_functions.sh379-403
The flash_image() function checks for two specific failure conditions:
| Error Code | Condition | Message | Resolution |
|---|---|---|---|
| 1 | Image size exceeds partition size | ! Insufficient partition size | Use smaller boot image or different device |
| 2 | Partition is read-only | ! $BOOTIMAGE is read only | Check partition permissions or SELinux policy |
Sources: scripts/util_functions.sh439-446
| Path | Purpose | Created By | Used By |
|---|---|---|---|
/system/addon.d/99-magisk.sh | System copy of addon.d script | flash_script.sh | OTA system |
/data/adb/magisk/addon.d.sh | Working copy of addon.d script | Magisk installation | Trampoline execution |
/data/adb/magisk/util_functions.sh | Utility functions library | Magisk installation | addon.d.sh |
/data/adb/magisk/boot_patch.sh | Boot patching logic | Magisk installation | install_magisk() |
/data/adb/magisk/magiskboot | Boot image manipulation tool | Magisk installation | boot_patch.sh |
config.orig | Temporary config backup | pre-backup phase | post-restore phase |
Sources: scripts/addon.d.sh46 scripts/flash_script.sh85 scripts/util_functions.sh763
The initialize() function prepares the execution environment for the addon.d script.
Sources: scripts/addon.d.sh61-71
The initialize() function and subsequent calls establish the following environment:
| Variable | Set By | Purpose |
|---|---|---|
BOOTMODE | initialize() | Indicates if running in booted Android vs recovery |
TMPDIR | initialize() | Temporary directory for working files |
MAGISKBIN | initialize() | Path to Magisk binaries |
SLOT | mount_partitions() | Current boot slot (_a or _b) |
SYSTEM_AS_ROOT | mount_partitions() | Whether device uses system-as-root |
LEGACYSAR | mount_partitions() | Whether device uses legacy SAR |
BOOTIMAGE | find_boot_image() | Path to boot partition to patch |
ABI | api_level_arch_detect() | Device architecture (arm64, x86_64, etc.) |
Sources: scripts/addon.d.sh61-71 scripts/util_functions.sh274-324 scripts/util_functions.sh379-403 scripts/util_functions.sh502-526
The addon.d survival mechanism provides automatic Magisk re-installation after OTA updates through a standardized hook system. The implementation handles both addon.d v1 (A-only devices) and v2 (A/B devices) protocols, with different execution models for each:
The script uses a trampoline pattern to ensure execution from persistent storage, integrates with the standard Magisk boot patching workflow, and includes comprehensive error handling for common failure scenarios.
Sources: scripts/addon.d.sh1-169 scripts/util_functions.sh429-452 scripts/flash_script.sh80-88
Refresh this wiki