OTA update flow and rollback
High-level sequence
fwupdaterauthenticates with the Marusya session and queriesGET /device/firmwareon the configured API host.- If
need_updateis true, it downloads the image to/tmp/update.imgor streams it to the SWUpdate writer. swupdateverifies and installs the image into the inactive A/B slot.- Boot control makes the other slot active and resets its bootable state.
- The next boot runs
self-check.shbecause/data/update_successfulexists. - The new slot becomes permanent only after version, Wi-Fi, update-API, and voice-agent checks pass and uptime exceeds 300 seconds.
Server request
Decompiled from fwupdater:sub_CD00: the request path is /device/firmware. It includes device metadata and uses Accept: application/json; when session credentials are present, it adds Authorization: Bearer <session_secret>. Response fields visible in the binary include need_update, version, and image size/download information.
The default host is vc.go.mail.ru. /data/permanent/api_url can override it. HTTPS is the default; the parser also accepts explicit HTTP. DONTUPDATE is a special test/development path rather than a normal server version.
Slot installation
swupdate.sh maps _a → slot,b and _b → slot,a, then runs:
swupdate -k /etc/swupdate-public.pem -i IMAGE -e slot,OTHER
boot-control reset-bootable other
boot-control set-active other
Optional reboot restarts immediately. fwupdater contains the same slot selection and public-key logic and reports the child process's exit status. /tmp/fwupdate.lock serializes updater activity; /tmp/reboot_required blocks a new update.
The public key authenticates the SWUpdate container. A valid image for the wrong slot/layout is still a separate compatibility concern.
Self-check gate
S98 always invokes self-check.sh. With no update markers it marks the current slot bootable. With /data/update_successful, it performs:
| Check | Retry/failure behavior |
|---|---|
FW_VERSION == NEW_VERSION |
Otherwise record update failure |
wpa_state=COMPLETED |
15 attempts, 20 seconds apart |
fwupdater --check |
Five attempts; return 0 or 1 accepted |
voice-agent process |
Must remain alive |
| Uptime | Must exceed 300 seconds |
Success removes /data/update_successful and keeps the current slot. Failure selects the other slot, renames the marker to /data/update_failed, appends REASON, saves logs, syncs, and reboots.
On the following boot, the failure path keeps the fallback slot, creates another log dump, waits 60 seconds, removes both markers, and syncs. The source says the delay prevents immediate re-update; the cloud-failure event is still a TODO.
Persistent evidence
/data/update_successful: new slot awaiting validation./data/update_failed: fallback/failure metadata and reason./data/telemetry_dump/: compressed logread/dmesg snapshots./data/fwlabel: firmware label preserved across S03 factory cleanup./data/permanent: survives ordinary factory cleanup and stores update configuration such asapi_url.
A factory reset intentionally preserves update_successful, update_failed handling, fwlabel, permanent, and bounded telemetry/crash history. This prevents a user reset from silently defeating A/B rollback bookkeeping.