coredomain may not be allowed sysfs:file or usb_device access (build-time neverallow in coredomain.te). SELinux is permissive on PawletOS so these succeed at runtime anyway; switch the sysfs (USB enumeration) and /dev/bus/usb (flashing) rules from allow to dontaudit to pass the neverallow check and silence denial spam.
PawletOS hardware update subsystem (pawlethwd)
Detects integrated and attached peripherals (displays, touch controllers, docks,
MCUs, HATs, automotive hardware, …) and updates their firmware over
device-specific transports (USB, i2c, spi, uart, gpio, can). This is separate
from the Android system OTA (me.pawlet.updater), which updates the OS image.
Components
| Piece | What | Installs to |
|---|---|---|
pawlethwd |
native C++ system daemon: detect → check → verify → flash → state | /system_ext/bin/pawlethwd |
IPawletHardwareUpdate |
AIDL: list components, trigger a check, read state | pawlet_hwupdate service |
| handler plugins | per-transport .so flashers, dlopened by the daemon |
/system_ext/lib{,64}/pawlet/hwh/libpawlethwh_<id>.so |
supported_hardware.json |
image-local authoritative manifest (what this image supports) | /system_ext/etc/pawlet/supported_hardware.json |
Even though the source lives in the vendor repo, the daemon is a system-side
(system_ext, coredomain) component — it needs network (firmware download)
and registers a binder service, both of which a /vendor daemon cannot do
without violating AOSP neverallows.
Trust model
The server catalog (device-updates.json) only describes releases; it never
selects executable code. Root of trust is the read-only, dm-verity-protected
/system_ext partition:
- A server-named
installer.handleris honored only if that handler id is in the component'sinstaller_handlersallowlist in the local, immutablesupported_hardware.json. - The allowlisted id maps to exactly
/system_ext/lib64/pawlet/hwh/libpawlethwh_<id>.so; the daemon refuses any other path and refuses a plugin whose reportedabi_version/handler_iddon't match. - Every payload is SHA-256 verified against the catalog before a handler runs.
So the server can only request handlers already baked into the signed image.
Flow
boot / hotplug / AIDL checkNow
│
▼
read supported_hardware.json ──▶ fetch catalog (ota.php?mode=hardware&target=catalog)
│ │
│ detect present hardware (USB VID/PID, DT compatible, …)
│ │
└── for each detected component ALSO supported by the local manifest:
read installed version (handler get_version)
query ota.php?mode=hardware&target=update&… ─▶ newest compatible or 204
download + sha256 verify
dlopen allowlisted handler .so → flash()
persist installed version / retry state
Handler plugin ABI
See include/pawlet/hwh_abi.h. A handler is a .so exporting a single symbol
pawlet_hwh_entry() returning a const pawlet_hwh_api* vtable
(abi_version, handler_id, detect, get_version, flash). The USB DFU
handler (handlers/usbdfu, libpawlethwh_usbdfu.so) is the first
implementation.
Layout
hwupdate/
aidl/ IPawletHardwareUpdate + parcelables
include/pawlet/ hwh_abi.h (shared by daemon + handlers)
daemon/ pawlethwd sources
handlers/usbdfu/ libpawlethwh_usbdfu.so
sepolicy/ pawlethwd domain
etc/ init.pawlethwd.rc, supported_hardware.default.json
schemas/ JSON schemas (CI validation)
hwupdate.mk product inclusion (prop + manifest + modules)
Per-device manifests may override the default by installing their own
supported_hardware.json from the device tree.