Tell your agent to root your camera with this prompt:
Root my DJI Osmo Action 5 Pro using these guides:
https://blog.kevmo314.com/rooting-the-dji-osmo-action-5-pro.html
https://blog.alliot.tech/post/osmo-action5pro-unlock-bootloader-adbd
Verify the model, firmware, active slot, and live GPT before writing.
Verify the loader and factory ABL hashes. Back up my original partitions
and verify the backups. Derive addresses from my camera's GPT; don't
copy another camera's addresses or userdata. Don't switch slots just to
match the guide. If compatibility is unclear, investigate before writing.
Patch devinfo first and check normal boot before replacing the active ABL.
Read back and compare every write. Ask me to handle the cable and battery
steps. Verify root ADB, bootloader unlock, and root access after reboot.
I rooted my DJI Osmo Action 5 Pro with a Qualcomm engineering cable from
Taobao. It now gives me a Linux root shell over USB with
adb shell.
The method comes from Alliot's Chinese walkthrough. This is an English version with notes from my run on Linux. The main difference was that my camera used slot B, while Alliot tested slot A.
This involves direct bootloader writes and can brick the camera. Back up your data first. I tested only the camera and firmware below.
| Component | My camera |
|---|---|
| Model | Osmo Action 5 Pro, AC204 |
| Platform | Qualcomm QCS8550 / SM8550 family, Kalama |
| Firmware version shown in Device Info | 01.06.01.04 |
| Camera firmware version | 10.00.16.13 |
| Active slot | B, before and after rooting |
| Host | Ubuntu Linux |
Camera firmware 10.00.16.13 matches Alliot's version. Check
both version fields in Settings → Device Info; unplug USB if the connected
screen blocks settings.
The camera already has adbd and an enabled
adbd.service. The method exposes root ADB with two changes:
devinfo partition, setting
the bootloader's unlocked and critical-unlocked flags.
This enables mp_state=engineering and
androidboot.secure_debug=1. I left system, userdata, GPT,
XBL, calibration data, and the inactive ABL unchanged. Don't flash someone
else's userdata: it contains device-specific settings and credentials.
I bought a second-generation Qualcomm 9008 engineering cable with a USB-C
connector and a button. On Taobao, search for
高通二代工程线 9008 Type-C. A regular USB-C cable won't
trigger EDL this way.
There is also an eBay listing for a v2.0 EDL cable, though I haven't tested that seller's cable. If you'd like to buy one from me, email me.
I used bkerler's EDL client at Alliot's pinned commit. On Ubuntu, install Python with venv support, Git, libusb, curl, unzip, ADB, and Fastboot. Run these commands in Bash:
set -euo pipefail
mkdir action5-root
cd action5-root
python3 -m venv .edl-venv
git clone https://github.com/bkerler/edl.git edl-tool
git -C edl-tool checkout 2f8e89a848afaaef68997fcbcb5b178d958d497b
.edl-venv/bin/pip install ./edl-tool
curl -fL https://github.com/AlliotTech/action-control/releases/download/action5pro-unlock-files.zip/action5pro-unlock-files.zip \
-o action5pro-unlock-files.zip
unzip action5pro-unlock-files.zip
sha256sum loader/RedMagicCommon_8Gen2_devprg img-unlock/abl-factory.img
wc -c img-unlock/abl-factory.img
The expected SHA-256 hashes are:
b85fb0e651f88f12e3c9b7b56c0f7229449c410f87fc20c6bc35698516383297 loader/RedMagicCommon_8Gen2_devprg
658af73f3319af4c07c733fe6ad184f68c299b678819815bbdacbaaff3b12466 img-unlock/abl-factory.img
The factory ABL must be exactly 1048576 bytes, and both
hashes must match. The RedMagic programmer is the exact file Alliot tested
and I used; don't substitute another loader just because it targets the
same SoC.
Set up the paths and a helper:
EDL_PY="$PWD/.edl-venv/bin/python"
EDL_SCRIPT="$PWD/edl-tool/edl.py"
LOADER="$PWD/loader/RedMagicCommon_8Gen2_devprg"
FACTORY_ABL="$PWD/img-unlock/abl-factory.img"
BACKUP="$PWD/backup-original"
edl() {
"$EDL_PY" "$EDL_SCRIPT" "$@" --loader="$LOADER"
}
Set up USB permissions with udev rules or run the client with the required
privileges. I temporarily stopped ModemManager with
sudo systemctl stop ModemManager and restarted it afterward.
The client's optional Capstone and Keystone warnings didn't prevent
flashing.
lsusb shows 05c6:9008, then
release the button.
The screen stays blank in EDL, and ADB and Fastboot won't see the camera.
Check for 05c6:9008, then read GPT:
lsusb -d 05c6:9008
edl printgpt --memory=ufs | tee gpt-before.log
The tool loads the programmer into RAM and reads the partition tables. My camera reported UFS, six LUNs, and 4096-byte blocks. These were its addresses, in decimal:
| Partition | LUN | Start sector | Sectors | Active |
|---|---|---|---|---|
devinfo |
4 | 239752 | 1 | Shared |
abl_a |
4 | 66566 | 256 | No |
abl_b |
4 | 190279 | 256 | Yes |
userdata |
0 | 15214715 | 25472 | Shared |
Read your own GPT before using any addresses. Check the model, block size, partition sizes, and active slot. Stop if they differ from what you expect.
Alliot says to stop if slot B is active, so I initially stopped. Before changing anything, I needed to check whether the factory ABL could boot B. Switching to A could have booted older firmware.
I backed up both ABLs and the active system image, decompressed the
factory and stock B ABLs, and compared their ARM64 code with Capstone. The
checked slot-detection, selection, and attribute routines matched after
resolving moved string addresses. Both images contained
_a and _b suffixes and selected a slot using GPT
active and priority bits.
That supported trying B on the matching camera firmware. I changed devinfo
first and checked that the camera still booted normally, then replaced
abl_b. It worked without switching slots. This is an
additional result from my camera, not a guarantee for other firmware.
Back up GPT and the small partitions. This skips the large data partitions:
mkdir -p "$BACKUP"
edl rl "$BACKUP" --memory=ufs \
--skip=system_a,system_b,emulated,userdata,blackbox,blackbox_upgrade,rawdump
test -f "$BACKUP/lun4/devinfo.bin"
test -f "$BACKUP/lun4/abl_a.bin"
test -f "$BACKUP/lun4/abl_b.bin"
The lun4 paths match my layout. I also read the full userdata
partition and active system_b image. This doesn't back up
recordings, the SD card, or blackbox data; copy those separately.
Set DEVINFO_LUN, DEVINFO_START,
DEVINFO_SECTORS, ABL_LUN,
ABL_START, and ABL_SECTORS from your GPT. Set
ORIGINAL_DEVINFO and ORIGINAL_ABL to your backup
files, using the ABL for the active slot. Derive the userdata variables
the same way:
mkdir -p "$BACKUP/lun$USERDATA_LUN"
edl rs "$USERDATA_START" "$USERDATA_SECTORS" \
"$BACKUP/lun$USERDATA_LUN/userdata.bin" \
--memory=ufs --lun="$USERDATA_LUN"
(cd "$BACKUP" && sha256sum lun*/*.bin > SHA256SUMS)
(cd "$BACKUP" && sha256sum -c SHA256SUMS)
Check backup sizes against GPT and verify the hashes after copying. I also verified the GPT CRCs. My second backup copy was on the same SSD, so it wouldn't protect against disk failure. Use a separate disk if available, and keep device backups private.
Read devinfo and the active ABL again. Both must match the backups before you write:
edl rs "$DEVINFO_START" "$DEVINFO_SECTORS" devinfo-before.bin \
--memory=ufs --lun="$DEVINFO_LUN"
cmp devinfo-before.bin "$ORIGINAL_DEVINFO"
edl rs "$ABL_START" "$ABL_SECTORS" abl-before.bin \
--memory=ufs --lun="$ABL_LUN"
cmp abl-before.bin "$ORIGINAL_ABL"
Patch your own devinfo. The script checks its size, magic, and flags, then
changes only offsets 0x10 and 0x18:
python3 - "$ORIGINAL_DEVINFO" devinfo-unlocked.bin <<'PY'
from pathlib import Path
import sys
src, dst = map(Path, sys.argv[1:])
original = src.read_bytes()
assert len(original) == 4096
assert original.startswith(b"ANDROID-BOOT!")
assert original[0x10] == original[0x18] == 0
patched = bytearray(original)
patched[0x10] = patched[0x18] = 1
assert [i for i, (a, b) in enumerate(zip(original, patched)) if a != b] == [0x10, 0x18]
dst.write_bytes(patched)
PY
# First persistent write: one devinfo sector, with only two bytes changed.
edl ws "$DEVINFO_START" devinfo-unlocked.bin --memory=ufs --lun="$DEVINFO_LUN"
edl rs "$DEVINFO_START" "$DEVINFO_SECTORS" devinfo-after.bin \
--memory=ufs --lun="$DEVINFO_LUN"
cmp devinfo-after.bin devinfo-unlocked.bin
# Only reset after the complete readback matches.
edl reset --resetmode=reset
Reset printed a USB I/O error when the camera disconnected; the 9008 device disappeared as expected. If it stays in EDL or readback fails, stop. I pressed power, unplugged USB, and checked the live view and touch controls. ABL was still original and ADB wasn't available yet.
Enter EDL again and reinstall the battery. Re-read GPT and check that the layout and active slot are unchanged. Devinfo must match the patched image; ABL must match the original. Verify the factory ABL's hash and size again before writing:
edl printgpt --memory=ufs | tee gpt-second-stage.log
edl rs "$DEVINFO_START" "$DEVINFO_SECTORS" devinfo-second-stage.bin \
--memory=ufs --lun="$DEVINFO_LUN"
cmp devinfo-second-stage.bin devinfo-unlocked.bin
edl rs "$ABL_START" "$ABL_SECTORS" abl-second-stage.bin \
--memory=ufs --lun="$ABL_LUN"
cmp abl-second-stage.bin "$ORIGINAL_ABL"
edl ws "$ABL_START" "$FACTORY_ABL" --memory=ufs --lun="$ABL_LUN"
edl rs "$ABL_START" "$ABL_SECTORS" abl-after.bin \
--memory=ufs --lun="$ABL_LUN"
cmp abl-after.bin "$FACTORY_ABL"
sha256sum abl-after.bin "$FACTORY_ABL"
# Again, only after a byte-for-byte match:
edl reset --resetmode=reset
I wrote only abl_b. The full 1 MiB readback matched the
factory image before I reset.
Power on and connect USB without holding the cable button. The connected screen is normal. Check ADB from the host:
adb devices -l
adb shell id
adb shell cat /proc/cmdline
adb shell systemctl is-enabled adbd.service
adb shell systemctl is-active adbd.service
My results included:
uid=0(root) gid=0(root) ...
mp_state=engineering
androidboot.secure_debug=1
systemd.setenv="SLOT_SUFFIX=_b"
enabled
active
One early ADB command failed while USB was re-enumerating; the next attempt worked. Give it time to settle. If ADB remains unavailable, check USB permissions and boot state before considering another flash.
Check Fastboot, then reboot:
adb reboot bootloader
fastboot devices
fastboot getvar unlocked
fastboot getvar current-slot
fastboot getvar product
# My output:
# unlocked: yes
# current-slot: b
# product: kalama
fastboot reboot
adb wait-for-device
adb shell id
Root ADB returned after reboot. Storage mounted, and the live view and
touch controls worked. A FactoryMode overlay appeared, which
I left in place. I haven't fully tested recording/playback or long-term
stability.
To undo this, enter EDL and verify GPT again. Restore your original active ABL, read it back and compare, then do the same for devinfo. Reset only after both match:
edl ws "$ABL_START" "$ORIGINAL_ABL" --memory=ufs --lun="$ABL_LUN"
edl rs "$ABL_START" "$ABL_SECTORS" abl-restored.bin \
--memory=ufs --lun="$ABL_LUN"
cmp abl-restored.bin "$ORIGINAL_ABL"
edl ws "$DEVINFO_START" "$ORIGINAL_DEVINFO" --memory=ufs --lun="$DEVINFO_LUN"
edl rs "$DEVINFO_START" "$DEVINFO_SECTORS" devinfo-restored.bin \
--memory=ufs --lun="$DEVINFO_LUN"
cmp devinfo-restored.bin "$ORIGINAL_DEVINFO"
edl reset --resetmode=reset
I kept the original images but haven't tested rollback. Keep the loader and engineering cable too; recovery depends on working EDL access.
For daily use, connect USB and run adb shell. Root ADB starts
automatically, so use trusted hosts. An OTA may replace ABL and remove
root access; check the new firmware and active slot before flashing again.
References: Alliot's original post (CC BY-NC-SA 4.0), the pinned EDL client, and Action Control, Alliot's web console for rooted cameras. I haven't installed the console.