1# Implementing Health 2.1 HAL
2
31. Install common binderized service. The binderized service `dlopen()`s
4   passthrough implementations on the device, so there is no need to write
5   your own.
6
7    ```mk
8    # Install default binderized implementation to vendor.
9    PRODUCT_PACKAGES += android.hardware.health@2.1-service
10    ```
11
121. Delete existing VINTF manifest entry. Search for `android.hardware.health` in
13   your device manifest, and delete the whole `<hal>` entry for older versions
14   of the HAL. Instead, when `android.hardware.health@2.1-service` is installed,
15   a VINTF manifest fragment is installed to `/vendor/etc/vintf`, so there is
16   no need to manually specify it in your device manifest. See
17   [Manifest fragments](https://source.android.com/devices/architecture/vintf/objects#manifest-fragments)
18   for details.
19
201. Install the proper passthrough implemetation.
21
22    1. If you want to use default implementation:
23
24        ```mk
25        # Install default passthrough implementation to vendor.
26        PRODUCT_PACKAGES += android.hardware.health@2.1-impl
27
28        # For non-A/B devices, install default passthrough implementation to recovery.
29        PRODUCT_PACKAGES += android.hardware.health@2.1-impl.recovery
30        ```
31
32        You are done. Otherwise, go to the next step.
33
34    1. If you want to write your own implementation,
35
36        1. Copy skeleton implementation from the [appendix](#impl).
37
38        1. Modify the implementation to suit your needs.
39
40            * If you have a board or device specific `libhealthd`, see
41              [Upgrading with  a customized libhealthd](#update-from-1-0).
42            * If you are upgrading from 1.0 health HAL, see
43              [Upgrading from Health HAL 1.0](#update-from-1-0).
44            * If you are upgrading from a customized 2.0 health HAL
45              implementation, See
46              [Upgrading from Health HAL 2.0](#update-from-2-0).
47
48        1. [Install the implementation](#install).
49
50        1. [Update necessary SELinux permissions](#selinux).
51
52        1. [Fix `/charger` symlink](#charger-symlink).
53
54# Upgrading with a customized libhealthd or from Health HAL 1.0 {#update-from-1-0}
55
56`libhealthd` contains two functions: `healthd_board_init()` and
57`healthd_board_battery_update()`. Similarly, Health HAL 1.0 contains `init()`
58and `update()`, with an additional `energyCounter()` function.
59
60* `healthd_board_init()` / `@1.0::IHealth.init()` should be called before
61  passing the `healthd_config` struct to your `HealthImpl` class. See
62  `HIDL_FETCH_IHealth` in [`HealthImpl.cpp`](#health_impl_cpp).
63
64* `healthd_board_battery_update()` / `@1.0::IHealth.update()` should be called
65  in `HealthImpl::UpdateHealthInfo()`. Example:
66
67  ```c++
68  void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
69      struct BatteryProperties props;
70      convertFromHealthInfo(health_info->legacy.legacy, &props);
71      healthd_board_battery_update(&props);
72      convertToHealthInfo(&props, health_info->legacy.legacy);
73  }
74  ```
75  For efficiency, you should move code in `healthd_board_battery_update` to
76  `HealthImpl::UpdateHealthInfo` and modify `health_info` directly to avoid
77  conversion to `BatteryProperties`.
78
79* Code for `@1.0::IHealth.energyCounter()` should be moved to
80  `HealthImpl::getEnergyCounter()`. Example:
81
82  ```c++
83  Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
84      int64_t energy = /* ... */;
85      _hidl_cb(Result::SUCCESS, energy);
86      return Void();
87  }
88  ```
89
90# Upgrading from Health HAL 2.0 {#update-from-2-0}
91
92* If you have implemented `healthd_board_init()` and/or
93  `healthd_board_battery_update()` (instead of using `libhealthd.default`),
94  see [the section above](#update-from-1-0)
95  for instructions to convert them.
96
97* If you have implemented `get_storage_info()` and/or `get_disk_stats()`
98  (instead of using libhealthstoragedefault), implement `HealthImpl::getDiskStats`
99  and/or `HealthImpl::getStorageInfo` directly. There is no need to override
100  `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
101  `getDiskStats` and `getStorageInfo` to retrieve storage information.
102
103# Install the implementation {#install}
104
105In `device.mk`:
106
107```mk
108# Install the passthrough implementation to vendor.
109PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>
110
111# For non-A/B devices, also install the passthrough implementation to recovery.
112PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>.recovery
113```
114
115# Update necessary SELinux permissions {#selinux}
116
117For example (replace `<device>` with the device name):
118```
119# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
120# Add device specific permissions to hal_health_default domain, especially
121# if a device-specific libhealthd is used and/or device-specific storage related
122# APIs are implemented.
123```
124
125# Fix `/charger` symlink {#charger-symlink}
126If you are using `/charger` in your `init.rc` scripts, it is recommended
127(required for devices running in Android R) that the path is changed to
128`/system/bin/charger` instead.
129
130Search for `service charger` in your device configuration directory to see if
131this change applies to your device. Below is an example of how the script should
132look like:
133
134```
135service charger /system/bin/charger
136    class charger
137    user system
138    group system wakelock input
139    capabilities SYS_BOOT
140    file /dev/kmsg w
141    file /sys/fs/pstore/console-ramoops-0 r
142    file /sys/fs/pstore/console-ramoops r
143    file /proc/last_kmsg r
144```
145
146# Appendix: sample code for the implementation {#impl}
147
148## `device/<manufacturer>/<device>/health/Android.bp` {#android_bp}
149
150```bp
151cc_library_shared {
152    name: "android.hardware.health@2.1-impl-<device>",
153    stem: "android.hardware.health@2.0-impl-2.1-<device>",
154
155    // Install to vendor and recovery.
156    proprietary: true,
157    recovery_available: true,
158
159    relative_install_path: "hw",
160
161    shared_libs: [
162        "libbase",
163        "libcutils",
164        "libhidlbase",
165        "liblog",
166        "libutils",
167        "android.hardware.health@2.1",
168        "android.hardware.health@2.0",
169    ],
170
171    static_libs: [
172        "android.hardware.health@1.0-convert",
173        "libbatterymonitor",
174        "libhealthloop",
175        "libhealth2impl",
176        // "libhealthd.<device>"
177    ],
178
179    srcs: [
180        "HealthImpl.cpp",
181    ],
182
183    // No vintf_fragments because both -impl and -service should have been
184    // installed.
185}
186```
187
188## `device/<manufacturer>/<device>/health/HealthImpl.cpp` {#health_impl_cpp}
189
190```c++
191#include <memory>
192#include <string_view>
193
194#include <health/utils.h>
195#include <health2impl/Health.h>
196#include <hidl/Status.h>
197
198using ::android::sp;
199using ::android::hardware::Return;
200using ::android::hardware::Void;
201using ::android::hardware::health::InitHealthdConfig;
202using ::android::hardware::health::V2_1::IHealth;
203using ::android::hidl::base::V1_0::IBase;
204
205using namespace std::literals;
206
207namespace android {
208namespace hardware {
209namespace health {
210namespace V2_1 {
211namespace implementation {
212
213// android::hardware::health::V2_1::implementation::Health implements most
214// defaults. Uncomment functions that you need to override.
215class HealthImpl : public Health {
216  public:
217    HealthImpl(std::unique_ptr<healthd_config>&& config)
218        : Health(std::move(config)) {}
219
220    // A subclass can override this if these information should be retrieved
221    // differently.
222    // Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
223    // Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
224    // Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
225    // Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
226    // Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
227    // Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
228    // Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
229    // Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
230    // Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
231
232    // Functions introduced in Health HAL 2.1.
233    // Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
234    // Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
235    // Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
236
237  protected:
238    // A subclass can override this to modify any health info object before
239    // returning to clients. This is similar to healthd_board_battery_update().
240    // By default, it does nothing.
241    // void UpdateHealthInfo(HealthInfo* health_info) override;
242};
243
244}  // namespace implementation
245}  // namespace V2_1
246}  // namespace health
247}  // namespace hardware
248}  // namespace android
249
250extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
251    using ::android::hardware::health::V2_1::implementation::HealthImpl;
252    if (instance != "default"sv) {
253        return nullptr;
254    }
255    auto config = std::make_unique<healthd_config>();
256    InitHealthdConfig(config.get());
257
258    // healthd_board_init(config.get());
259
260    return new HealthImpl(std::move(config));
261}
262```
263