A full-stack AOSP vendor component that exposes CPU temperature and fan control on a Raspberry Pi 5 running Android 15. Built entirely inside vendor/myoem/ with no modifications to frameworks/ or device/.
The project follows a 4-layer AOSP vendor stack:
┌─────────────────────────────────────────────────┐
│ ThermalMonitor App (Kotlin + Jetpack Compose) │
│ apps/ThermalMonitor/ │
└──────────────────┬──────────────────────────────┘
│ Java Binder (ServiceManager)
┌──────────────────▼──────────────────────────────┐
│ ThermalControlManager (Java SDK library) │
│ libs/thermalcontrol/ │
└──────────────────┬──────────────────────────────┘
│ AIDL / Binder IPC (NDK)
┌──────────────────▼──────────────────────────────┐
│ thermalcontrold (C++ native service) │
│ services/thermalcontrol/ │
└──────────────────┬──────────────────────────────┘
│ C++ interface call
┌──────────────────▼──────────────────────────────┐
│ libthermalcontrolhal (C++ HAL library) │
│ hal/thermalcontrol/ │
│ reads/writes sysfs on RPi5 hardware │
└─────────────────────────────────────────────────┘
libthermalcontrolhal—cc_library_sharedbuilt with Soong- Reads CPU temperature from
/sys/class/thermal/thermal_zone0/temp - Controls fan PWM via
/sys/class/hwmon/hwmonN/pwm1andpwm1_enable - Dynamically discovers the hwmon sysfs index at init (not hardcoded)
- Supports read/write/auto mode; degrades gracefully when hardware is absent
thermalcontrold—cc_binaryregistered as a@VintfStabilityAIDL service- AIDL interface:
IThermalControlService(NDK backend,libbinder_ndk) - Launched via
init.rc; managed by Android'sinitprocess - SELinux policy (
thermalcontrold.te,service_contexts,file_contexts)
thermalcontrol-manager—java_sdk_library- Wraps the AIDL stub with safe defaults and
RemoteExceptionhandling - Exposes a clean Java API:
getCpuTemperatureCelsius(),setFanSpeed(int), etc.
- Jetpack Compose UI with real-time polling (2 s interval via
StateFlow) - Displays CPU temperature with color-coded heat category (Cool / Warm / Hot / Critical)
- Fan control: On / Off / Auto mode / speed slider (0–100%)
- MVI pattern:
UiState,ThermalViewModel, statelessThermalScreencomposable
lunch myoem_rpi5-trunk_staging-userdebug
m libthermalcontrolhal # HAL shared library
m thermalcontrold # native service binary
m thermalcontrol-manager # Java SDK library
m ThermalMonitor # Compose app
m VtsThermalControlHalTest # HAL unit tests
m VtsThermalControlServiceTest # VTS binder tests| Test suite | Type | Target |
|---|---|---|
VtsThermalControlHalTest |
GTest (native) | HAL sysfs read/write, boundary checks, graceful degradation |
VtsThermalControlServiceTest |
VTS / GTest | VINTF compliance, binder IPC, error codes, concurrency |
ThermalControlManagerTest |
JUnit (Java) | Manager null-binder safety, range validation |
ThermalScreenTest |
Compose instrumented | UI state rendering, button interactions, state transitions |
- AIDL backend: NDK (
libbinder_ndk) — required for vendor processes in AOSP 15 - VINTF stability:
@VintfStabilityannotation with frozen API snapshot (aidl_api/) - SELinux: custom
thermalcontrolddomain; hwmon files use genericsysfslabel (notsysfs_hwmon, which does not exist in AOSP 15 base policy) - hwmon discovery: scanned dynamically at startup since the hwmon index is not stable across kernel versions or boot order
- RC file:
chown root system+chmod 0664on hwmon sysfs nodes aton boot— kernel creates them asroot:root 0644, blocking writes from thesystemuser
| Item | Value |
|---|---|
| Device | Raspberry Pi 5 |
| AOSP branch | android-15.0.0_r14 |
| Build system | Soong (Android.bp) |
| Languages | C++17, AIDL, Java, Kotlin |
