Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e438211a authored by Yifan Hong's avatar Yifan Hong
Browse files

health 2.1 implementation.

Test: VTS health 2.1 test
Bug: 137670450

Change-Id: I04ea74facbaa534eee00a51474a013db3b6eb212
parent 950dcb63
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
# Implement the 2.1 HAL instead!

It is strongly recommended that you implement the 2.1 HAL directly. See
`hardware/interfaces/health/2.1/README.md` for more details.

# Upgrading from Health 1.0 HAL

1. Remove `android.hardware.health@1.0*` from `PRODUCT_PACKAGES`

health/2.1/README.md

0 → 100644
+245 −0
Original line number Diff line number Diff line
# Implementing Health 2.1 HAL

1. Install common binderized service. The binderized service `dlopen()`s
   passthrough implementations on the device, so there is no need to write
   your own.

    ```mk
    # Install default binderized implementation to vendor.
    PRODUCT_PACKAGES += android.hardware.health@2.1-service
    ```

1. 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, when `android.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](https://source.android.com/devices/architecture/vintf/objects#manifest-fragments)
   for details.

1. Install the proper passthrough implemetation.

    1. If you want to use default implementation:

        ```mk
        # Install default passthrough implementation to vendor.
        PRODUCT_PACKAGES += android.hardware.health@2.1-impl
        ```

        You are done. Otherwise, go to the next step.

    1. If you want to write your own implementation,

        1. Copy skeleton implementation from the [appendix](#impl).

        1. Modify the implementation to suit your needs.

            * If you have a board or device specific `libhealthd`, see
              [Upgrading with  a customized libhealthd](#update-from-1-0).
            * If you are upgrading from 1.0 health HAL, see
              [Upgrading from Health HAL 1.0](#update-from-1-0).
            * If you are upgrading from a customized 2.0 health HAL
              implementation, See
              [Upgrading from Health HAL 2.0](#update-from-2-0).

        1. [Update necessary SELinux permissions](#selinux).

        1. [Fix `/charger` symlink](#charger-symlink).

# Upgrading with a customized libhealthd or from Health HAL 1.0 {#update-from-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 the `healthd_config` struct to your `HealthImpl` class. See
  `HIDL_FETCH_IHealth` in [`HealthImpl.cpp`](#health_impl_cpp).

* `healthd_board_battery_update()` / `@1.0::IHealth.update()` should be called
  in `HealthImpl::UpdateHealthInfo()`. Example:

  ```c++
  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` to
  `HealthImpl::UpdateHealthInfo` and modify `health_info` directly to avoid
  conversion to `BatteryProperties`.

* Code for `@1.0::IHealth.energyCounter()` should be moved to
  `HealthImpl::getEnergyCounter()`. Example:

  ```c++
  Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
      int64_t energy = /* ... */;
      _hidl_cb(Result::SUCCESS, energy);
      return Void();
  }
  ```

# Upgrading from Health HAL 2.0 {#update-from-2-0}

* If you have implemented `healthd_board_init()` and/or
  `healthd_board_battery_update()` (instead of using `libhealthd.default`),
  see [the section above](#update-from-1-0)
  for instructions to convert them.

* If you have implemented `get_storage_info()` and/or `get_disk_stats()`
  (instead of using libhealthstoragedefault), implement `HealthImpl::getDiskStats`
  and/or `HealthImpl::getStorageInfo` directly. There is no need to override
  `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
  `getDiskStats` and `getStorageInfo` to retrieve storage information.

# Update necessary SELinux permissions {#selinux}

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 {#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 {#impl}

## `device/<manufacturer>/<device>/health/Android.bp` {#android_bp}

```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` {#health_impl_cpp}

```c++
#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));
}
```
+81 −0
Original line number Diff line number Diff line
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

cc_defaults {
    name: "android.hardware.health@2.1-impl-defaults",
    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",
    ],
}

// Default passthrough implementation of the health@2.1 HAL.
// Passhtrough implementations of the health@2.1 HAL must be installed in
// vendor in order to support charger.
// Passhtrough implementations of the health@2.1 HAL must be installed in
// recovery in order to allow recovery to check battery status.
// See README.md for details.
cc_library_shared {
    name: "android.hardware.health@2.1-impl",
    stem: "android.hardware.health@2.0-impl-2.1",

    // Only vendor and recovery variants are allowed, not core.
    vendor: true,
    recovery_available: true,

    defaults: ["android.hardware.health@2.1-impl-defaults"],

    srcs: [
        "impl.cpp",
    ],

    // No vintf_fragments because both -impl and -service should have been
    // installed.
}

// Default binderized service of the health@2.1 HAL.
// This binderized implementation dlopen()s the passthrough implementation,
// so there is no need to implement your own.
cc_binary {
    name: "android.hardware.health@2.1-service",
    vendor: true,
    defaults: ["android.hardware.health@2.1-impl-defaults"],
    init_rc: ["android.hardware.health@2.1-service.rc"],

    srcs: [
        "service.cpp",
    ],

    vintf_fragments: [
        "android.hardware.health@2.1.xml"
    ],

    overrides: [
        "healthd",
    ],
}
+6 −0
Original line number Diff line number Diff line
service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
    class hal
    user system
    group system
    capabilities WAKE_ALARM
    file /dev/kmsg w
+7 −0
Original line number Diff line number Diff line
<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>android.hardware.health</name>
        <transport>hwbinder</transport>
        <fqname>@2.1::IHealth/default</fqname>
    </hal>
</manifest>
Loading