{"id":28234191,"url":"https://github.com/sachindsilvanist/swupdaterv2-bootable-beta","last_synced_at":"2025-08-31T13:39:47.115Z","repository":{"id":285374351,"uuid":"947715751","full_name":"sachindsilvaNIST/SWUpdaterV2-Bootable-Beta","owner":"sachindsilvaNIST","description":"Android OS 12 Software Updater Beta Features in sync with Update Engine","archived":false,"fork":false,"pushed_at":"2025-04-03T02:52:08.000Z","size":187,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"bootable-alpha-v20","last_synced_at":"2025-06-12T21:47:15.270Z","etag":null,"topics":["java","json","json-api","update-engine","xml","xml-p"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sachindsilvaNIST.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-13T06:12:08.000Z","updated_at":"2025-04-03T02:57:41.000Z","dependencies_parsed_at":"2025-06-12T21:44:55.847Z","dependency_job_id":"9a935443-9269-42e3-b1a2-856de706e793","html_url":"https://github.com/sachindsilvaNIST/SWUpdaterV2-Bootable-Beta","commit_stats":null,"previous_names":["sachindsilvanist/swupdaterv2-bootable-beta"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sachindsilvaNIST/SWUpdaterV2-Bootable-Beta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachindsilvaNIST%2FSWUpdaterV2-Bootable-Beta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachindsilvaNIST%2FSWUpdaterV2-Bootable-Beta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachindsilvaNIST%2FSWUpdaterV2-Bootable-Beta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachindsilvaNIST%2FSWUpdaterV2-Bootable-Beta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sachindsilvaNIST","download_url":"https://codeload.github.com/sachindsilvaNIST/SWUpdaterV2-Bootable-Beta/tar.gz/refs/heads/bootable-alpha-v20","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachindsilvaNIST%2FSWUpdaterV2-Bootable-Beta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272988781,"owners_count":25026959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","json","json-api","update-engine","xml","xml-p"],"created_at":"2025-05-18T22:13:21.142Z","updated_at":"2025-08-31T13:39:46.790Z","avatar_url":"https://github.com/sachindsilvaNIST.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SWUpdater Version 2.0.0\n\nThis app demonstrates how to use Android system updates APIs to install\n[OTA updates](https://source.android.com/devices/tech/ota/). It contains a\nsample client for `update_engine` to install A/B (seamless) updates.\n\nA/B (seamless) update is available since Android Nougat (API 24), but this sample\ntargets the latest android.\n\n\n## Workflow\n\nSystemUpdaterSample app shows list of available updates on the UI. User is allowed\nto select an update and apply it to the device. App shows installation progress,\nlogs can be found in `adb logcat`. User can stop or reset an update. Resetting\nthe update requests update engine to cancel any ongoing update, and revert\nif the update has been applied. Stopping does not revert the applied update.\n\n\n## Update Config file\n\nIn this sample updates are defined in JSON update config files.\nThe structure of a config file is defined in\n`com.example.android.systemupdatersample.UpdateConfig`, example file is located\nat `res/raw/sample.json`.\n\nIn real-life update system the config files expected to be served from a server\nto the app, but in this sample, the config files are stored on the device.\nThe directory can be found in logs or on the UI. In most cases it should be located at\n`/data/user/0/com.example.android.systemupdatersample/files/configs/`.\n\nSystemUpdaterSample app downloads OTA package from `url`. In this sample app\n`url` is expected to point to file system, e.g. `file:///data/my-sample-ota-builds-dir/ota-002.zip`.\n\nIf `ab_install_type` is `NON_STREAMING` then app checks if `url` starts\nwith `file://` and passes `url` to the `update_engine`.\n\nIf `ab_install_type` is `STREAMING`, app downloads only the entries in need, as\nopposed to the entire package, to initiate a streaming update. The `payload.bin`\nentry, which takes up the majority of the space in an OTA package, will be\nstreamed by `update_engine` directly. The ZIP entries in such a package need to be\nsaved uncompressed (`ZIP_STORED`), so that their data can be downloaded directly\nwith the offset and length. As `payload.bin` itself is already in compressed\nformat, the size penalty is marginal.\n\nif `ab_config.force_switch_slot` set true device will boot to the\nupdated partition on next reboot; otherwise button \"Switch Slot\" will\nbecome active, and user can manually set updated partition as the active slot.\n\nConfig files can be generated using `tools/gen_update_config.py`.\nRunning `./tools/gen_update_config.py --help` shows usage of the script.\n\n\n## Sample App State vs UpdateEngine Status\n\nUpdateEngine provides status for different stages of update application\nprocess. But it lacks of proper status codes when update fails.\n\nThis creates two problems:\n\n1. If sample app is unbound from update_engine (MainActivity is paused, destroyed),\n   app doesn't receive onStatusUpdate and onPayloadApplicationCompleted notifications.\n   If app binds to update_engine after update is completed,\n   only onStatusUpdate is called, but status becomes IDLE in most cases.\n   And there is no way to know if update was successful or not.\n\n2. This sample app demostrates suspend/resume using update_engins's\n   `cancel` and `applyPayload` (which picks up from where it left).\n   When `cancel` is called, status is set to `IDLE`, which doesn't allow\n   tracking suspended state properly.\n\nTo solve these problems sample app implements its own separate update\nstate - `UpdaterState`. To solve the first problem, sample app persists\n`UpdaterState` on a device. When app is resumed, it checks if `UpdaterState`\nmatches the update_engine's status (as onStatusUpdate is guaranteed to be called).\nIf they doesn't match, sample app calls `applyPayload` again with the same\nparameters, and handles update completion properly using `onPayloadApplicationCompleted`\ncallback. The second problem is solved by adding `PAUSED` updater state.\n\n\n## Sample App UI\n\n### Text fields\n\n- `Current Build:` - shows current active build.\n- `Updater state:` - SystemUpdaterSample app state.\n- `Engine status:` - last reported update_engine status.\n- `Engine error:` - last reported payload application error.\n\n### Buttons\n\n- `Reload` - reloads update configs from device storage.\n- `View config` - shows selected update config.\n- `Apply` - applies selected update config.\n- `Stop` - cancel running update, calls `UpdateEngine#cancel`.\n- `Reset` - reset update, calls `UpdateEngine#resetStatus`, can be called\n            only when update is not running.\n- `Suspend` - suspend running update, uses `UpdateEngine#cancel`.\n- `Resume` - resumes suspended update, uses `UpdateEngine#applyPayload`.\n- `Switch Slot` - if `ab_config.force_switch_slot` config set true,\n            this button will be enabled after payload is applied,\n            to switch A/B slot on next reboot.\n\n\n## Sending HTTP headers from UpdateEngine\n\nSometimes OTA package server might require some HTTP headers to be present,\ne.g. `Authorization` header to contain valid auth token. While performing\nstreaming update, `UpdateEngine` allows passing on certain HTTP headers;\nas of writing this sample app, these headers are `Authorization` and `User-Agent`.\n\n`android.os.UpdateEngine#applyPayload` contains information on\nwhich HTTP headers are supported.\n\n\n## Used update_engine APIs\n\n### UpdateEngine#bind\n\nBinds given callbacks to update_engine. When update_engine successfully\ninitialized, it's guaranteed to invoke callback onStatusUpdate.\n\n### UpdateEngine#applyPayload\n\nStart an update attempt to download an apply the provided `payload_url` if\nno other update is running. The extra `key_value_pair_headers` will be\nincluded when fetching the payload.\n\n`key_value_pair_headers` argument also accepts properties other than HTTP Headers.\nList of allowed properties can be found in `system/update_engine/common/constants.cc`.\n\n### UpdateEngine#cancel\n\nCancel the ongoing update. The update could be running or suspended, but it\ncan't be canceled after it was done.\n\n### UpdateEngine#resetStatus\n\nReset the already applied update back to an idle state. This method can\nonly be called when no update attempt is going on, and it will reset the\nstatus back to idle, deleting the currently applied update if any.\n\n### Callback: onStatusUpdate\n\nCalled whenever the value of `status` or `progress` changes. For\n`progress` values changes, this method will be called only if it changes significantly.\nAt this time of writing this doc, delta for `progress` is `0.005`.\n\n`onStatusUpdate` is always called when app binds to update_engine,\nexcept when update_engine fails to initialize.\n\n### Callback: onPayloadApplicationComplete\n\nCalled whenever an update attempt is completed or failed.\n\n\n## Running on a device\n\nThe commands are expected to be run from `$ANDROID_BUILD_TOP` and for demo\npurpose only.\n\n### Without the privileged system permissions\n\n1. Compile the app `mmma -j bootable/recovery/updater_sample`.\n2. Install the app to the device using `adb install \u003cAPK_PATH\u003e`.\n3. Change permissions on `/data/ota_package/` to `0777` on the device.\n4. Set SELinux mode to permissive. See instructions below.\n5. Add update config files; look above at [Update Config file](#Update-Config-file).\n6. Push OTA packages to the device.\n7. Run the sample app.\n\n### With the privileged system permissions\n\nTo run sample app as a privileged system app, it needs to be installed in `/system/priv-app/`.\nThis directory is expected to be read-only, unless explicitly remounted.\n\nThe recommended way to run the app is to build and install it as a\nprivileged system app, so it's granted the required permissions to access\n`update_engine` service as well as OTA package files. Detailed steps are as follows:\n\n1. [Prepare to build](https://source.android.com/setup/build/building)\n2. Add the module (SystemUpdaterSample) to the `PRODUCT_PACKAGES` list for the\n   lunch target.\n   e.g. add a line containing `PRODUCT_PACKAGES += SystemUpdaterSample`\n   to `device/google/marlin/device-common.mk`.\n3. [Whitelist the sample app](https://source.android.com/devices/tech/config/perms-whitelist)\n   * Add\n   ```\n    \u003cprivapp-permissions package=\"com.example.android.systemupdatersample\"\u003e\n        \u003cpermission name=\"android.permission.ACCESS_CACHE_FILESYSTEM\"/\u003e\n    \u003c/privapp-permissions\u003e\n   ```\n   to `frameworks/base/data/etc/privapp-permissions-platform.xml`\n4. Add `privileged: true` to SystemUpdaterSample\n   [building rule](https://android.googlesource.com/platform/bootable/recovery/+/refs/heads/master/updater_sample/Android.bp).\n5. Build sample app `make -j SystemUpdaterSample`.\n6. Build Android `make -j`\n7. [Flash the device](https://source.android.com/setup/build/running)\n8. Add update config files; look above at `## Update Config file`;\n   `adb root` might be required.\n9. Push OTA packages to the device if there is no server to stream packages from;\n   changing of SELinux labels of OTA packages directory might be required\n   `chcon -R u:object_r:ota_package_file:s0 /data/my-sample-ota-builds-dir`\n10. Run the sample app.\n\n\n## Development\n\n- [x] Create a UI with list of configs, current version,\n      control buttons, progress bar and log viewer\n- [x] Add `PayloadSpec` and `PayloadSpecs` for working with\n      update zip file\n- [x] Add `UpdateConfig` for working with json config files\n- [x] Add applying non-streaming update\n- [x] Prepare streaming update (partially downloading package)\n- [x] Add applying streaming update\n- [x] Add stop/reset the update\n- [x] Add demo for passing HTTP headers to `UpdateEngine#applyPayload`\n- [x] [Package compatibility check](https://source.android.com/devices/architecture/vintf/match-rules)\n- [x] Deferred switch slot demo\n- [x] Add UpdateManager; extract update logic from MainActivity\n- [x] Add Sample app update state (separate from update_engine status)\n- [x] Add smart update completion detection using onStatusUpdate\n- [x] Add pause/resume demo\n- [x] Verify system partition checksum for package\n\n\n## Running tests\n\nThe commands are expected to be run from `$ANDROID_BUILD_TOP`.\n\n1. Build `make -j SystemUpdaterSample` and `make -j SystemUpdaterSampleTests`.\n2. Install app\n   `adb install $OUT/system/app/SystemUpdaterSample/SystemUpdaterSample.apk`\n3. Install tests\n   `adb install $OUT/testcases/SystemUpdaterSampleTests/arm64/SystemUpdaterSampleTests.apk`\n4. Run tests\n   `adb shell am instrument -w com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner`\n5. Run a test file\n   ```\n   adb shell am instrument \\\n     -w -e class com.example.android.systemupdatersample.UpdateManagerTest#applyUpdate_appliesPayloadToUpdateEngine \\\n     com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner\n   ```\n\n\n## Accessing `android.os.UpdateEngine` API\n\n`android.os.UpdateEngine` APIs are marked as `@SystemApi`, meaning only system\napps can access them.\n\n\n## Getting read/write access to `/data/ota_package/`\n\nAccess to cache filesystem is granted only to system apps.\n\n\n## Setting SELinux mode to permissive (0)\n\n```txt\nlocal$ adb root\nlocal$ adb shell\nandroid# setenforce 0\nandroid# getenforce\n```\n\n\n## License\n\nSystemUpdaterSample app is released under\n[Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsachindsilvanist%2Fswupdaterv2-bootable-beta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsachindsilvanist%2Fswupdaterv2-bootable-beta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsachindsilvanist%2Fswupdaterv2-bootable-beta/lists"}