7be3fd486c | ||
---|---|---|
.. | ||
default | ||
vts | ||
Android.bp | ||
IHealth.hal | ||
IHealthInfoCallback.hal | ||
README.md | ||
types.hal |
README.md
Implementing Health 2.1 HAL
-
Install common binderized service. The binderized service
dlopen()
s passthrough implementations on the device, so there is no need to write your own.# Install default binderized implementation to vendor. PRODUCT_PACKAGES += android.hardware.health@2.1-service
-
Delete existing VINTF manifest entry. Search for
android.hardware.health
in your device manifest, and delete the whole<hal>
entry for older versions of the HAL. Instead, whenandroid.hardware.health@2.1-service
is installed, a VINTF manifest fragment is installed to/vendor/etc/vintf
, so there is no need to manually specify it in your device manifest. See Manifest fragments for details. -
Install the proper passthrough implemetation.
-
If you want to use default implementation:
# Install default passthrough implementation to vendor. PRODUCT_PACKAGES += android.hardware.health@2.1-impl # For non-A/B devices, install default passthrough implementation to recovery. PRODUCT_PACKAGES += android.hardware.health@2.1-impl.recovery
You are done. Otherwise, go to the next step.
-
If you want to write your own implementation,
-
Copy skeleton implementation from the appendix.
-
Modify the implementation to suit your needs.
- If you have a board or device specific
libhealthd
, see Upgrading with a customized libhealthd. - If you are upgrading from 1.0 health HAL, see Upgrading from Health HAL 1.0.
- If you are upgrading from a customized 2.0 health HAL implementation, See Upgrading from Health HAL 2.0.
- If you have a board or device specific
-
-
Upgrading with a customized libhealthd or from Health HAL 1.0
libhealthd
contains two functions: healthd_board_init()
and
healthd_board_battery_update()
. Similarly, Health HAL 1.0 contains init()
and update()
, with an additional energyCounter()
function.
-
healthd_board_init()
/@1.0::IHealth.init()
should be called before passing thehealthd_config
struct to yourHealthImpl
class. SeeHIDL_FETCH_IHealth
inHealthImpl.cpp
. -
healthd_board_battery_update()
/@1.0::IHealth.update()
should be called inHealthImpl::UpdateHealthInfo()
. Example:void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) { struct BatteryProperties props; convertFromHealthInfo(health_info->legacy.legacy, &props); healthd_board_battery_update(&props); convertToHealthInfo(&props, health_info->legacy.legacy); }
For efficiency, you should move code in
healthd_board_battery_update
toHealthImpl::UpdateHealthInfo
and modifyhealth_info
directly to avoid conversion toBatteryProperties
. -
Code for
@1.0::IHealth.energyCounter()
should be moved toHealthImpl::getEnergyCounter()
. Example:Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) { int64_t energy = /* ... */; _hidl_cb(Result::SUCCESS, energy); return Void(); }
Upgrading from Health HAL 2.0
-
If you have implemented
healthd_board_init()
and/orhealthd_board_battery_update()
(instead of usinglibhealthd.default
), see the section above for instructions to convert them. -
If you have implemented
get_storage_info()
and/orget_disk_stats()
(instead of using libhealthstoragedefault), implementHealthImpl::getDiskStats
and/orHealthImpl::getStorageInfo
directly. There is no need to overrideHealthImpl::getHealthInfo
orHealthImpl::getHealthInfo_2_1
because they callgetDiskStats
andgetStorageInfo
to retrieve storage information.
Install the implementation
In device.mk
:
# Install the passthrough implementation to vendor.
PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>
# For non-A/B devices, also install the passthrough implementation to recovery.
PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>.recovery
Update necessary SELinux permissions
For example (replace <device>
with the device name):
# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
# Add device specific permissions to hal_health_default domain, especially
# if a device-specific libhealthd is used and/or device-specific storage related
# APIs are implemented.
Fix /charger
symlink
If you are using /charger
in your init.rc
scripts, it is recommended
(required for devices running in Android R) that the path is changed to
/system/bin/charger
instead.
Search for service charger
in your device configuration directory to see if
this change applies to your device. Below is an example of how the script should
look like:
service charger /system/bin/charger
class charger
user system
group system wakelock input
capabilities SYS_BOOT
file /dev/kmsg w
file /sys/fs/pstore/console-ramoops-0 r
file /sys/fs/pstore/console-ramoops r
file /proc/last_kmsg r
Appendix: sample code for the implementation
device/<manufacturer>/<device>/health/Android.bp
cc_library_shared {
name: "android.hardware.health@2.1-impl-<device>",
stem: "android.hardware.health@2.0-impl-2.1-<device>",
// Install to vendor and recovery.
proprietary: true,
recovery_available: true,
relative_install_path: "hw",
shared_libs: [
"libbase",
"libcutils",
"libhidlbase",
"liblog",
"libutils",
"android.hardware.health@2.1",
"android.hardware.health@2.0",
],
static_libs: [
"android.hardware.health@1.0-convert",
"libbatterymonitor",
"libhealthloop",
"libhealth2impl",
// "libhealthd.<device>"
],
srcs: [
"HealthImpl.cpp",
],
// No vintf_fragments because both -impl and -service should have been
// installed.
}
device/<manufacturer>/<device>/health/HealthImpl.cpp
#include <memory>
#include <string_view>
#include <health/utils.h>
#include <health2impl/Health.h>
#include <hidl/Status.h>
using ::android::sp;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::health::InitHealthdConfig;
using ::android::hardware::health::V2_1::IHealth;
using ::android::hidl::base::V1_0::IBase;
using namespace std::literals;
namespace android {
namespace hardware {
namespace health {
namespace V2_1 {
namespace implementation {
// android::hardware::health::V2_1::implementation::Health implements most
// defaults. Uncomment functions that you need to override.
class HealthImpl : public Health {
public:
HealthImpl(std::unique_ptr<healthd_config>&& config)
: Health(std::move(config)) {}
// A subclass can override this if these information should be retrieved
// differently.
// Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
// Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
// Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
// Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
// Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
// Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
// Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
// Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
// Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
// Functions introduced in Health HAL 2.1.
// Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
// Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
// Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
protected:
// A subclass can override this to modify any health info object before
// returning to clients. This is similar to healthd_board_battery_update().
// By default, it does nothing.
// void UpdateHealthInfo(HealthInfo* health_info) override;
};
} // namespace implementation
} // namespace V2_1
} // namespace health
} // namespace hardware
} // namespace android
extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
using ::android::hardware::health::V2_1::implementation::HealthImpl;
if (instance != "default"sv) {
return nullptr;
}
auto config = std::make_unique<healthd_config>();
InitHealthdConfig(config.get());
// healthd_board_init(config.get());
return new HealthImpl(std::move(config));
}