Custota
Android A/B OTA updater app for custom OTA servers
Install / Use
/learn @chenxiaolong/CustotaREADME
Custota
<img src="app/images/icon.svg" alt="app icon" width="72" />
Custota is an app for installing Android A/B OTA updates from a custom OTA server. When paired with avbroot, it can be used to seamlessly install OTAs signed by a custom key.
Custota is installed via a Magisk/KernelSU module so that it can run as a system app.
<img src="app/images/light.png" alt="light mode screenshot" width="200" /> <img src="app/images/dark.png" alt="dark mode screenshot" width="200" />
Features
- Supports Android 13 and newer
- Supports pausing, resuming, and cancelling updates
- Supports skipping optional post-install scripts to speed up updates
- Never communicates with any server besides the configured OTA server
- OTA updates safely continue running even if the app crashes or is uninstalled during the operation
- Supports Direct Boot, allowing updates to install before the device is initially unlocked
Limitations
- The device must support A/B updates.
- This notably excludes all Samsung devices.
- Pre-downloading an update to install later is not supported.
- Custota runs
update_enginein streaming mode, which downloads and installs OTAs at the same time.
- Custota runs
- The stock OS' Settings app on Pixel devices always launches the builtin OTA updater.
- These shortcuts in the Settings app are loaded from GmsCore (part of Google Play Services) via a mechanism called "settings slices" and cannot be overridden. Apps that launch the OTA updater via the standard
android.settings.SYSTEM_UPDATE_SETTINGSintent will show a prompt to pick between Custota or the builtin OTA updater.
- These shortcuts in the Settings app are loaded from GmsCore (part of Google Play Services) via a mechanism called "settings slices" and cannot be overridden. Apps that launch the OTA updater via the standard
Usage
-
Follow the instructions in the OTA server section to set up a webserver and generate the metadata files for the OTA zips.
Alternatively, Custota supports installing OTAs from a local directory instead of downloading them from an OTA server. When using a local directory, the expected directory structure is exactly the same as how it would be with a server.
-
If you're installing OTA updates signed with a custom key, follow the instructions in the Custom Verification Key section.
-
Download the latest version from the releases page. To verify the digital signature, see the verifying digital signatures section.
-
Install the Custota module in Magisk/KernelSU.
-
Reboot and open Custota.
-
Set the OTA server URL to point to your OTA server.
-
That's it!
Once the OTA server URL is configured, Custota will automatically check for updates periodically. The checks can be turned off completely or extended to automatically install the updates as well. To reduce battery usage, the timing of the periodic update checks is controlled by Android. They run at most once every 6 hours.
If OTAs are installed from an OTA server (instead of a local directory), then automatic checks and automatic installs will work even before the device is initially unlocked following a reboot.
OTA server
Custota only requires a basic webserver capable of serving static files and supporting the HTTP Range header. Any standard webserver, like Apache, Nginx, or Caddy, will do the trick. For testing, Caddy is very useful because it can serve files from a directory without setting up any config files:
caddy file-server --access-log --listen :8080 --root /path/to/ota/directory
The following static files need to be hosted:
- OTA zip
- The filename can be anything.
- Csig ("Custota signature") file
- This is a file that contains a digital signature of the metadata sections of the OTA. This allows Custota to securely read the OTA's metadata without downloading the entire zip.
- The filename can be anything, but is commonly
<ota filename>.csig.
- Update info JSON
- This contains the path or URL to the
.zipand.csigfiles. - The filename must be
<device codename>.json.
- This contains the path or URL to the
To generate the csig and update info files:
-
Download
custota-toolfrom the release page. Binaries are provided for Linux, Windows, and Mac. To compile from source instead, follow the instructions here. -
Generate the csig file from the OTA zip. The keypair that was used to sign the OTA can also be used to create the csig.
./custota-tool \ gen-csig \ --input path/to/ota.zip \ --key path/to/ota.key \ --cert path/to/ota.crtIf the OTA was signed with a different keypair, use
--cert-verifyto specify the certificate for verifying the OTA. This is not needed if the OTA and csig are signed with the same keypair.The csig will be saved to
<input>.csig.-o/--outputcan be used to specify a different output path.If the private key is encrypted, an interactive prompt for the passphrase will be shown. For automation, see
--helpfor information on providing the passphrase via an environment variable or a file. -
Create the update info JSON file.
./custota-tool \ gen-update-info \ --file <device codename>.json \ --location <ota filename>.zipThe location can be set to:
- A relative path (computed starting from the directory containing the update info file). This is the easy option if the update info, OTA, and csig files are all stored in the same directory tree. Subdirectories are supported.
- A full URL. This is useful if the OTA and csig files are stored on different servers (eg. cloud object storage).
By default, the csig location is set to
<location>.csig. This can be changed with the-c/--csig-locationoption.If needed, this file can be easily edited by hand.
Incremental OTAs
Generating incremental OTAs is out of scope for this project, but if they are generated some other way, Custota can use them. The process is a bit more tedious and requires the following two components:
- The csig file for the full OTA for the source OS version
- The incremental OTA that upgrades the source OS version to the target OS version
With those components available, follow these steps to generate a csig file for the incremental OTA and update the update info JSON file accordingly:
-
Generate a csig file for the incremental OTA. This is the same command as for generating csig files for full OTAs.
custota-tool \ gen-csig \ --input <incremental OTA>.zip \ --key path/to/ota.key \ --cert path/to/ota.crt -
Get the vbmeta digest of the source full OTA from its csig file:
custota-tool show-csig -i <source full OTA>.zip.csigTo do this programmatically, use
-rand parse the JSON output. For example:custota-tool show-csig -i <source full OTA>.zip.csig -r | jq -r .vbmeta_digest -
Take the existing update info JSON file (which should already have the full OTA location) and update it with the incremental OTA information. Replace
<source vbmeta digest>with the digest from the previous step../custota-tool \ gen-update-info \ --file <device codename>.json \ --location <incremental OTA>.zip \ --inc-vbmeta-digest <source vbmeta digest>
When checking for updates, Custota will look for an incremental OTA matching the vbmeta digest of the currently running OS. If an incremental OTA does not exist, it will use the full OTA instead.
HTTPS
To use a self-signed certificate or a custom CA certificate, it needs to be installed into the system CA trust store. To generate a module that does this, run the following command and then flash the generated module zip.
custota-tool gen-cert-module -o system-ca-certs.zip /path/to/cert.pem
Custom verification key
Android's update_engine verifies OTA signatures against certificates contained within /system/etc/security/otacerts.zip. If your OTAs were signed by a custom key via avbroot, make sure it was done with avbroot 3.0.0 or newer, which added support for patching the system partition's copy of otacerts.zip (instead of just the recovery partition's copy).
Permissions
ACCESS_CACHE_FILESYSTEM(automatically granted by system app permissions)- Needed to store temporary OTA files.
ACCESS_NETWORK_STATE(automatically granted at install time)- Needed on Android 14+ for unmetered network background run condition.
FOREGROUND_SERVICE,FOREGROUND_SERVICE_SPECIAL_USE(automatically granted at install time)- Needed to run the OTA update service in the background.
INTERNET(automatically granted at install time)- Needed to communicate with the OTA server. Custota does not and will never communicate with any server outside of the configured OTA server. There are no ads, analytics, or any sort of tracking.
MANAGE_CARRIER_OEM_UNLOCK_STATE,MANAGE_USER_OEM_UNLOCK_STATE,READ_OEM_UNLOCK_STATE(automatically granted by system app permissions)- Needed to show the bootloader unlock status.
POST_NOTIFICATIONS(must be granted by the user)- Android requires a notification to be shown in order for the updater service to reliably run in the background.
REBOOT(automatically granted by system app permissions)- Needed to reboot the device when the user explicitly presses the reboot button in Custota's notification after an update is installed.
RECEIVE_BOOT_COMPLETED(automatically granted at install time)- Needed to schedule periodic update checks.
- Needed to show the OTA cleanup notification on the reboot following an OTA update.
WAKE_LOCK(**automatically gra
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
