1# Health AIDL HAL 2 3## Determine whether the example service implementation is sufficient {#determine} 4 5You need a custom implementation if any of the following is true: 6 7* You are migrating from a custom 8 [health 2.1 HIDL HAL implementation](../2.1/README.md). 9* System properties `ro.charger.enable_suspend` and/or `ro.charger.no_ui` 10 are set to a `true` value. See [below](#charger-sysprops). 11* The device supports offline charging mode, and the `service` 12 declaration with `class charger` in `init.rc` is different from the one 13 provided by the example implementation. See [below](#charger-init-rc). 14 15If the example HAL service is sufficient, [install it](#use-example). Otherwise, 16[implement a custom HAL service](#use-custom). 17 18### System properties for charger {#charger-sysprops} 19 20The health AIDL HAL service also provides functionalities of `charger`. As a 21result, the system charger at `/system/bin/charger` is deprecated. 22 23However, the health AIDL HAL service is not allowed to read `ro.charger.*` 24system properties. These properties include: 25* `ro.charger.enable_suspend`. If set, you need a custom health AIDL HAL 26 service. See [below](#charger-enable-suspend). 27* `ro.charger.no_ui`. If set, you need a custom health AIDL HAL service. 28 See [below](#charger-no-ui). 29* `ro.charger.draw_split_screen`. The system property is deprecated. 30* `ro.charger.draw_split_offset`. The system property is deprecated. 31* `ro.charger.disable_init_blank`. The system property is deprecated. 32 33If you need to set any of the deprecated system properties, contact 34[OWNERS](OWNERS). 35 36### Default `service` declaration for charger in `init.rc` {#charger-init-rc} 37 38See 39[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc). 40 41Check the `service` declaration in your device-specific `init.rc` file that 42has `class charger`. Most likely, the declaration looks something like this 43(Below is an excerpt from Pixel 3): 44 45```text 46service vendor.charger /system/bin/charger 47 class charger 48 seclabel u:r:charger:s0 49 user system 50 group system wakelock input 51 capabilities SYS_BOOT 52 file /dev/kmsg w 53 file /sys/fs/pstore/console-ramoops-0 r 54 file /sys/fs/pstore/console-ramoops r 55 file /proc/last_kmsg r 56``` 57 58Compare each line against the one provided by the example health AIDL HAL 59service in 60[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc). 61Specifically: 62 63* For the `service` line, if the name of the service is **NOT** 64 `vendor.charger`, and there are actions 65 in the rc file triggered by `on property:init.svc.<name>=running` where 66 `<name>` is the name of your charger service, then you need a custom health 67 AIDL service. 68* If your service belongs to additional classes beside `charger`, you need a 69 custom health AIDL service. 70* Modify the `seclabel` line. Replace `charger` with `charger_vendor`. 71* If your service has a different `user` (not `system`), you need a custom 72 health AIDL service. 73* If your service belongs to additional `group`s beside 74 `system wakelock input`, you need a custom health AIDL service. 75* If your service requires additional capabilities beside `SYS_BOOT`, 76 you need a custom health AIDL service. 77* If your service requires additional `file`s to be opened prior to execution, 78 you need a custom health AIDL service. 79 80## Using the example health AIDL HAL service {#use-example} 81 82If you [determined](#determine) that the example health AIDL HAL service works 83for your device, install it with 84 85```mk 86PRODUCT_PACKAGES += \ 87 android.hardware.health-service.example \ 88 android.hardware.health-service.example_recovery \ 89``` 90 91Then, delete any existing `service` with `class charger` in your device-specific 92`init.rc` files, because 93[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc) 94already contains an entry for charger. 95 96If your device supports charger mode and it has custom charger resources, 97[move charger resources to `/vendor`](#charger-res) 98 99## Implementing a custom health AIDL HAL service {#use-custom} 100 101### Override the `Health` class {#health-impl} 102 103See [`Health.h`](default/include/health-impl/Health.h) for its class 104declaration. Inherit the class to customize for your device. 105 106```c++ 107namespace aidl::android::hardware::health { 108class HealthImpl : public Health { 109 // ... 110}; 111} // namespace aidl::android::hardware::health 112int main(int, char**) { 113 // ... 114 auto binder = ndk::SharedRefBase::make<aidl::android::hardware::health::HealthImpl>( 115 "default", std::move(config)); 116 // ... 117} 118``` 119 120* The logic to modify `healthd_config`, traditionally in `healthd_board_init()` 121 should be called before passing the `healthd_config` struct to your 122 `HealthImpl` class in [`main()`](#main). 123 124* The following functions are similar to the ones in the health 2.1 HIDL HAL: 125 126| AIDL implementation | HIDL implementation | 127|-------------------------------------|-----------------------------| 128| `Health::getChargeCounterUah` | `Health::getChargeCounter` | 129| `Health::getCurrentNowMicroamps` | `Health::getCurrentNow` | 130| `Health::getCurrentAverageMicroamps`| `Health::getCurrentAverage` | 131| `Health::getCapacity` | `Health::getCapacity` | 132| `Health::getChargeStatus` | `Health::getChargeStatus` | 133| `Health::getEnergyCounterNwh` | `Health::getEnergyCounter` | 134| `Health::getDiskStats` | `Health::getDiskStats` | 135| `Health::getStorageInfo` | `Health::getStorageInfo` | 136| `Health::BinderEvent` | `BinderHealth::BinderEvent` | 137| `Health::dump` | `Health::debug` | 138| `Health::ShouldKeepScreenOn` | `Health::shouldKeepScreenOn`| 139| `Health::UpdateHealthInfo` | `Health::UpdateHealthInfo` | 140 141### Implement `main()` {#main} 142 143See the [`main.cpp`](default/main.cpp) for the example health AIDL service for 144an example. 145 146If you need to modify `healthd_config`, do it before passing it to the 147constructor of `HealthImpl` (or `Health` if you did not implement a subclass 148of it). 149 150```c++ 151int main(int argc, char** argv) { 152 auto config = std::make_unique<healthd_config>(); 153 ::android::hardware::health::InitHealthdConfig(config.get()); 154 healthd_board_init(config.get()); 155 auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config)); 156 // ... 157} 158``` 159 160If your device does not support off-line charging mode, or does not have a UI 161for charger (`ro.charger.no_ui=true`), skip the invocation of 162`ChargerModeMain()` in `main()`. 163 164### Build system changes 165 166Install both the platform and recovery variant of the service. For example: 167 168```mk 169PRODUCT_PACKAGES += \ 170 android.hardware.health-service.cuttlefish \ 171 android.hardware.health-service.cuttlefish_recovery \ 172``` 173 174### SELinux rules 175 176Add device specific permissions to the domain where the health HAL 177process is executed, especially if a device-specific `libhealthd` is used 178and/or device-specific storage related APIs are implemented. 179 180Example (assuming that your health AIDL service runs in domain 181`hal_health_tuna`: 182 183```text 184type hal_health_tuna, domain; 185hal_server_domain(hal_health_tuna, hal_health) 186type hal_health_tuna_exec, exec_type, vendor_file_type, file_type; 187 188# allow hal_health_tuna ...; 189``` 190 191If you did not define a separate domain, the domain is likely 192`hal_health_default`. The device-specific rules for it is likely at 193`device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te`. 194In this case, the aforementioned SELinux rules and types has already been 195defined. You only need to add device-specific permissions. 196 197```text 198# allow hal_health_default ...; 199``` 200 201### Implementing charger {#charger} 202 203#### Move charger resources to `/vendor` 204 205Ensure that charger resources are installed to `/vendor`, not `/product`. 206 207`animation.txt` must be moved to the following location: 208 209```text 210/vendor/etc/res/values/charger/animation.txt 211``` 212 213Charger resources in `/system` is not read by the health HAL service in 214`/vendor`. Specifically, resources should be installed to the following 215location: 216 217``` 218/vendor/etc/res/images/charger/*.png 219``` 220 221If resources are not found in these locations, the health HAL service falls 222back to the following locations: 223 224``` 225/vendor/etc/res/images/charger/default/*.png 226``` 227 228You can use the default resources by installing the default module: 229 230```makefile 231PRODUCT_PACKAGES += charger_res_images_vendor 232``` 233 234#### Modify `init.rc` for charger 235 236It is recommended that you move the existing `service` entry with 237`class charger` to the `init.rc` file in your custom health service. 238 239If there are existing actions in the rc file triggered by 240`on property:init.svc.<name>=running`, where `<name>` is the name of your 241existing charger service (usually `vendor.charger`), then the name of the 242service must be kept as-is. If you modify the name of the service, the actions 243are not triggered properly. 244 245Modify the entry to invoke the health service binary with `--charger` argument. 246See 247[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc) 248for an example: 249 250```text 251service vendor.charger /vendor/bin/hw/android.hardware.health-service-tuna --charger 252 class charger 253 seclabel u:r:charger_vendor:s0 254 # ... 255``` 256 257#### No charger mode {#no-charger} 258 259If your device does not support off-line charging mode, skip the invocation of 260`ChargerModeMain()` in `main()`. 261 262```c++ 263int main(int, char**) { 264 // ... 265 // Skip checking if arguments contain "--charger" 266 auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder); 267 return hal_health_loop->StartLoop(); 268} 269``` 270 271You may optionally delete the `service` entry with `class charger` in the 272`init.rc` file. 273 274#### No charger UI {#charger-no-ui} 275 276If your device does not have a UI for charger (`ro.charger.no_ui=true`), skip 277the invocation of `ChargerModeMain()` in `main()`. 278 279You may want to keep the `KernelLogger` so that charger still logs battery 280information to the kernel logs. 281 282```c++ 283int main(int argc, char** argv) { 284 // ... 285 if (argc >= 2 && argv[1] == "--charger"sv) { 286 android::base::InitLogging(argv, &android::base::KernelLogger); 287 // fallthrough to HalHealthLoop::StartLoop() 288 } 289 auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder); 290 return hal_health_loop->StartLoop(); 291} 292``` 293 294#### Enable suspend {#charger-enable-suspend} 295 296If your device has `ro.charger.enable_suspend=true`, implement a new class, 297`ChargerCallbackImpl`, that inherits from 298[`ChargerCallback`](default/include/health-impl/ChargerUtils.h). Then 299override the `ChargerEnableSuspend` function to return `true`. Then pass an 300instance of `ChargerCallbackImpl` to `ChargerModeMain()` instead. 301 302```c++ 303namespace aidl::android::hardware::health { 304class ChargerCallbackImpl : public ChargerCallback { 305 bool ChargerEnableSuspend() override { return true; } 306}; 307} // namespace aidl::android::hardware::health 308int main(int argc, char** argv) { 309 // ... 310 if (argc >= 2 && argv[1] == "--charger"sv) { 311 android::base::InitLogging(argv, &android::base::KernelLogger); 312#if !CHARGER_FORCE_NO_UI 313 return ChargerModeMain(binder, 314 std::make_shared<aidl::android::hardware::health::ChargerCallbackImpl>(binder)); 315#endif 316 } 317 // ... 318} 319``` 320 321#### SELinux rules for charger 322 323If your health AIDL service runs in a domain other than `hal_health_default`, 324add `charger_type` to it so the health HAL service can have charger-specific 325permissions. Example (assuming that your health AIDL service runs in domain 326`hal_health_tuna`: 327 328```text 329domain_trans(init, hal_health_tuna_exec, charger_vendor) 330``` 331