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