README.md
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