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

Commit 7ccbe096 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 7895410 from b6533047 to tm-release

Change-Id: Ifdb21f7eb00828b078d889c5d8849b818db80c97
parents d2978a5b b6533047
Loading
Loading
Loading
Loading

health/aidl/README.md

0 → 100644
+293 −0
Original line number Diff line number Diff line
# Health AIDL HAL

## Determine whether the example service implementation is sufficient {#determine}

You need a custom implementation if any of the following is true:

* You are migrating from a custom
  [health 2.1 HIDL HAL implementation](../2.1/README.md).
* System properties `ro.charger.enable_suspend` and/or `ro.charger.no_ui`
  are set to a `true` value. See [below](#charger-sysprops).
* The device supports offline charging mode, and the `service`
  declaration with `class charger` in `init.rc` is different from the one
  provided by the example implementation. See [below](#charger-init-rc).

If the example HAL service is sufficient, [install it](#use-example). Otherwise,
[implement a custom HAL service](#use-custom).

### System properties for charger {#charger-sysprops}

The health AIDL HAL service also provides functionalities of `charger`. As a
result, the system charger at `/system/bin/charger` is deprecated.

However, the health AIDL HAL service is not allowed to read `ro.charger.*`
system properties. These properties include:
* `ro.charger.enable_suspend`. If set, you need a custom health AIDL HAL
  service. See [below](#charger-enable-suspend).
* `ro.charger.no_ui`. If set, you need a custom health AIDL HAL service.
  See [below](#charger-no-ui).
* `ro.charger.draw_split_screen`. The system property is deprecated.
* `ro.charger.draw_split_offset`. The system property is deprecated.
* `ro.charger.disable_init_blank`. The system property is deprecated.

If you need to set any of the deprecated system properties, contact
[OWNERS](OWNERS).

### Default `service` declaration for charger in `init.rc` {#charger-init-rc}

See
[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc).

Check the `service` declaration in your device-specific `init.rc` file that
has `class charger`. Most likely, the declaration looks something like this
(Below is an excerpt from Pixel 3):

```text
service vendor.charger /system/bin/charger
    class charger
    seclabel u:r:charger:s0
    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
```

Compare each line against the one provided by the example health AIDL HAL
service in
[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc).
Specifically:

* You may ignore the `service` line. The name of the service does not matter.
* If your service belongs to additional classes beside `charger`, you need a
  custom health AIDL service.
* You may ignore the `seclabel` line. When the health AIDL service runs in
  charger mode, its original SELinux domain is kept.
* If your service has a different `user` (not `system`), you need a custom
  health AIDL service.
* If your service belongs to additional `group`s beside
  `system wakelock input`, you need a custom health AIDL service.
* If your service requires additional capabilities beside `SYS_BOOT`,
  you need a custom health AIDL service.
* If your service requires additional `file`s to be opened prior to execution,
  you need a custom health AIDL service.

## Using the example health AIDL HAL service {#use-example}

If you [determined](#determine) that the example health AIDL HAL service works
for your device, install it with

```mk
PRODUCT_PACKAGES += android.hardware.health-service.example
```

Then, delete any existing `service` with `class charger` in your device-specific
`init.rc` files, because
[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc)
already contains an entry for charger.

If your device supports charger mode and it has custom charger resources,
[move charger resources to `/vendor`](#charger-res)

## Implementing a custom health AIDL HAL service {#use-custom}

### Override the `Health` class {#health-impl}

See [`Health.h`](default/include/health-impl/Health.h) for its class
declaration. Inherit the class to customize for your device.

```c++
namespace aidl::android::hardware::health {
class HealthImpl : public Health {
    // ...
};
} // namespace aidl::android::hardware::health
int main(int, char**) {
    // ...
    auto binder = ndk::SharedRefBase::make<aidl::android::hardware::health::HealthImpl>(
            "default", std::move(config));
    // ...
}
```

* The logic to modify `healthd_config`, traditionally in `healthd_board_init()`
  should be called before passing the `healthd_config` struct to your
  `HealthImpl` class in [`main()`](#main).

* The following functions are similar to the ones in the health 2.1 HIDL HAL:

| AIDL implementation                 | HIDL implementation         |
|-------------------------------------|-----------------------------|
| `Health::getChargeCounterUah`       | `Health::getChargeCounter`  |
| `Health::getCurrentNowMicroamps`    | `Health::getCurrentNow`     |
| `Health::getCurrentAverageMicroamps`| `Health::getCurrentAverage` |
| `Health::getCapacity`               | `Health::getCapacity`       |
| `Health::getChargeStatus`           | `Health::getChargeStatus`   |
| `Health::getEnergyCounterNwh`       | `Health::getEnergyCounter`  |
| `Health::getDiskStats`              | `Health::getDiskStats`      |
| `Health::getStorageInfo`            | `Health::getStorageInfo`    |
| `Health::BinderEvent`               | `BinderHealth::BinderEvent` |
| `Health::dump`                      | `Health::debug`             |
| `Health::ShouldKeepScreenOn`        | `Health::shouldKeepScreenOn`|
| `Health::UpdateHealthInfo`          | `Health::UpdateHealthInfo`  |

### Implement `main()` {#main}

See the [`main.cpp`](default/main.cpp) for the example health AIDL service for
an example.

If you need to modify `healthd_config`, do it before passing it to the
constructor of `HealthImpl` (or `Health` if you did not implement a subclass
of it).

```c++
int main(int argc, char** argv) {
    auto config = std::make_unique<healthd_config>();
    ::android::hardware::health::InitHealthdConfig(config.get());
    healthd_board_init(config.get());
    auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config));
    // ...
}
```

If your device does not support off-line charging mode, or does not have a UI
for charger (`ro.charger.no_ui=true`), skip the invocation of
`ChargerModeMain()` in `main()`.

### SELinux rules

Add device specific permissions to the domain where the health HAL
process is executed, especially if a device-specific `libhealthd` is used
and/or device-specific storage related APIs are implemented.

If you did not define a separate domain, the domain is likely
`hal_health_default`. The device-specific rules for it is likely at
`device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te`.

### Implementing charger {#charger}

#### Move charger resources to `/vendor`

Ensure that charger resources are installed to `/vendor`, not `/product`.

`animation.txt` must be moved to the following location:

```text
/vendor/etc/res/values/charger/animation.txt
```

Charger resources in `/system` is not read by the health HAL service in
`/vendor`. Specifically, resources should be installed to the following
location:

```
/vendor/etc/res/images/charger/*.png
```

If resources are not found in these locations, the health HAL service falls
back to the following locations:

```
/vendor/etc/res/images/charger/default/*.png
```

You can use the default resources by installing the default module:

```makefile
PRODUCT_PACKAGES += charger_res_images_vendor
```

#### Modify `init.rc` for charger

It is recommended that you move the existing `service` entry with
`class charger` to the `init.rc` file in your custom health service.

Modify the entry to invoke the health service binary with `--charger` argument.
See
[android.hardware.health-service.example.rc](default/android.hardware.health-service.example.rc)
for an example:

```text
service vendor.charger-tuna /vendor/bin/hw/android.hardware.health-service-tuna --charger
    # ...
```

#### No charger mode {#no-charger}

If your device does not support off-line charging mode, skip the invocation of
`ChargerModeMain()` in `main()`.

```c++
int main(int, char**) {
    // ...
    // Skip checking if arguments contain "--charger"
    auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
    return hal_health_loop->StartLoop();
}
```

You may optionally delete the `service` entry with `class charger` in the
`init.rc` file.

#### No charger UI {#charger-no-ui}

If your device does not have a UI for charger (`ro.charger.no_ui=true`), skip
the invocation of `ChargerModeMain()` in `main()`.

You may want to keep the `KernelLogger` so that charger still logs battery
information to the kernel logs.

```c++
int main(int argc, char** argv) {
    // ...
    if (argc >= 2 && argv[1] == "--charger"sv) {
        android::base::InitLogging(argv, &android::base::KernelLogger);
        // fallthrough to HalHealthLoop::StartLoop()
    }
    auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
    return hal_health_loop->StartLoop();
}
```

#### Enable suspend {#charger-enable-suspend}

If your device has `ro.charger.enable_suspend=true`, implement a new class,
`ChargerCallbackImpl`, that inherits from
[`ChargerCallback`](default/include/health-impl/ChargerUtils.h). Then
override the `ChargerEnableSuspend` function to return `true`. Then pass an
instance of `ChargerCallbackImpl` to `ChargerModeMain()` instead.

```c++
namespace aidl::android::hardware::health {
class ChargerCallbackImpl : public ChargerCallback {
    bool ChargerEnableSuspend() override { return true; }
};
} // namespace aidl::android::hardware::health
int main(int argc, char** argv) {
    // ...
    if (argc >= 2 && argv[1] == "--charger"sv) {
        android::base::InitLogging(argv, &android::base::KernelLogger);
#if !CHARGER_FORCE_NO_UI
        return ChargerModeMain(binder,
                std::make_shared<aidl::android::hardware::health::ChargerCallbackImpl>(binder));
#endif
    }
    // ...
}
```

#### SELinux rules for charger

If your health AIDL service runs in a domain other than `hal_health_default`,
add `charger_type` to it so the health HAL service can have charger-specific
permissions. Example (assuming that your health AIDL service runs in domain
`hal_health_tuna`:

```text
type hal_health_tuna, charger_type, domain;
hal_server_domain(hal_health_default, hal_health)
```

[comment: TODO(b/170338625): explain recovery]: #
+59 −0
Original line number Diff line number Diff line
@@ -45,6 +45,52 @@ cc_defaults {
    ],
}

// Dependency to libhealthd_charger_ui. No UI in recovery.
cc_defaults {
    name: "libhealth_aidl_charger_defaults",
    shared_libs: [
        // common
        "android.hardware.health-V1-ndk",
        "libbase",
        "libcutils",
        "liblog",
        "libutils",

        // charger UI only
        "libpng",
    ],

    static_libs: [
        // common
        "libbatterymonitor",
        "libhealthloop",

        // charger UI only
        "libhealthd_draw",
        "libhealthd_charger_ui",
        "libminui",
        "libsuspend",
    ],

    target: {
        recovery: {
            // No UI and libsuspend for recovery charger.
            cflags: [
                "-DCHARGER_FORCE_NO_UI=1",
            ],
            exclude_shared_libs: [
                "libpng",
            ],
            exclude_static_libs: [
                "libhealthd_draw",
                "libhealthd_charger_ui",
                "libminui",
                "libsuspend",
            ],
        },
    },
}

// AIDL version of libhealth2impl.
// A helper library for health HAL implementation.
// HAL implementations can link to this library and extend the Health class.
@@ -52,12 +98,14 @@ cc_library_static {
    name: "libhealth_aidl_impl",
    defaults: [
        "libhealth_aidl_common_defaults",
        "libhealth_aidl_charger_defaults",
    ],
    export_include_dirs: ["include"],
    export_static_lib_headers: [
        "libbatterymonitor",
    ],
    srcs: [
        "ChargerUtils.cpp",
        "health-convert.cpp",
        "HalHealthLoop.cpp",
        "Health.cpp",
@@ -67,6 +115,13 @@ cc_library_static {
        ":__subpackages__",
        "//hardware/interfaces/tests/extension/health:__subpackages__",
    ],
    target: {
        recovery: {
            exclude_srcs: [
                "ChargerUtils.cpp",
            ],
        },
    },
}

// AIDL version of android.hardware.health@2.1-service.
@@ -78,9 +133,13 @@ cc_binary {
    vintf_fragments: ["android.hardware.health-service.example.xml"],
    defaults: [
        "libhealth_aidl_common_defaults",
        "libhealth_aidl_charger_defaults",
    ],
    static_libs: [
        "libhealth_aidl_impl",
    ],
    srcs: ["main.cpp"],
    overrides: [
        "charger",
    ],
}
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.
 */

#include <android-base/logging.h>
#include <health-impl/ChargerUtils.h>

namespace aidl::android::hardware::health::charger {

std::optional<bool> ChargerCallback::ChargerShouldKeepScreenOn() {
    return service_->ShouldKeepScreenOn();
}

bool ChargerCallback::ChargerIsOnline() {
    auto hal_health_loop_sp = hal_health_loop_.lock();
    if (hal_health_loop_sp == nullptr) {
        // Assume no charger
        return false;
    }
    return hal_health_loop_sp->charger_online();
}

void ChargerCallback::ChargerInitConfig(healthd_config* config) {
    auto hal_health_loop_sp = hal_health_loop_.lock();
    if (hal_health_loop_sp == nullptr) {
        return;
    }
    return service_->OnInit(hal_health_loop_sp.get(), config);
}

int ChargerCallback::ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
    auto hal_health_loop_sp = hal_health_loop_.lock();
    if (hal_health_loop_sp == nullptr) {
        return -1;
    }
    return hal_health_loop_sp->RegisterEvent(fd, func, wakeup);
}

void ChargerCallback::set_hal_health_loop(const std::weak_ptr<HalHealthLoop>& hal_health_loop) {
    hal_health_loop_ = std::move(hal_health_loop);
}

// Implements HalHealthLoopCallback for AIDL charger
// Adapter of (Charger, Health) ->  HalHealthLoopCallback
class LoopCallback : public HalHealthLoopCallback {
  public:
    LoopCallback(const std::shared_ptr<Health>& service, ChargerCallback* charger_callback)
        : service_(service), charger_(std::make_unique<::android::Charger>(charger_callback)) {}

    void OnHeartbeat() override {
        service_->OnHeartbeat();
        charger_->OnHeartbeat();
    }
    // Return the minimum timeout. Negative values are treated as no values.
    int OnPrepareToWait() override {
        int timeout1 = service_->OnPrepareToWait();
        int timeout2 = charger_->OnPrepareToWait();

        if (timeout1 < 0) return timeout2;
        if (timeout2 < 0) return timeout1;
        return std::min(timeout1, timeout2);
    }

    void OnInit(HalHealthLoop*, struct healthd_config* config) override {
        // Charger::OnInit calls ChargerInitConfig, which calls into the real Health::OnInit.
        charger_->OnInit(config);
    }

    void OnHealthInfoChanged(const HealthInfo& health_info) override {
        charger_->OnHealthInfoChanged(::android::ChargerHealthInfo{
                .battery_level = health_info.batteryLevel,
                .battery_status = health_info.batteryStatus,
        });
        service_->OnHealthInfoChanged(health_info);
    }

  private:
    std::shared_ptr<Health> service_;
    std::unique_ptr<::android::Charger> charger_;
};

int ChargerModeMain(const std::shared_ptr<Health>& binder,
                    const std::shared_ptr<ChargerCallback>& charger_callback) {
    LOG(INFO) << "Starting charger mode.";
    //   parent stack ==========================================
    //   current stack                                         ||
    //    ||                                                   ||
    //    V                                                    V
    // hal_health_loop => loop_callback => charger --(raw)--> charger_callback
    //    ^----------------(weak)---------------------------------'
    auto loop_callback = std::make_shared<LoopCallback>(binder, charger_callback.get());
    auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, std::move(loop_callback));
    charger_callback->set_hal_health_loop(hal_health_loop);
    return hal_health_loop->StartLoop();
}

}  // namespace aidl::android::hardware::health::charger
+10 −0
Original line number Diff line number Diff line
@@ -4,3 +4,13 @@ service vendor.health-default /vendor/bin/hw/android.hardware.health-service.exa
    group system
    capabilities WAKE_ALARM BLOCK_SUSPEND
    file /dev/kmsg w

service vendor.charger-default /vendor/bin/hw/android.hardware.health-service.example --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
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.
 */

#include <optional>
#include <type_traits>

#include <android/binder_auto_utils.h>
#include <charger/healthd_mode_charger.h>
#include <health-impl/Health.h>

#pragma once

namespace aidl::android::hardware::health::charger {

// Implements ChargerHalHealthLoopInterface for AIDL charger
// Adapter of (Health, HalHealthLoop) -> ChargerHalHealthLoopInterface
class ChargerCallback : public ::android::ChargerConfigurationInterface {
  public:
    ChargerCallback(const std::shared_ptr<Health>& service) : service_(service) {}
    std::optional<bool> ChargerShouldKeepScreenOn() override;
    bool ChargerIsOnline() override;
    void ChargerInitConfig(healthd_config* config) override;
    int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) override;

    // Override to return true to replace `ro.charger.enable_suspend=true`
    bool ChargerEnableSuspend() override { return false; }

    void set_hal_health_loop(const std::weak_ptr<HalHealthLoop>& hal_health_loop);

  private:
    std::shared_ptr<Health> service_;
    std::weak_ptr<HalHealthLoop> hal_health_loop_;
};

int ChargerModeMain(const std::shared_ptr<Health>& binder,
                    const std::shared_ptr<ChargerCallback>& charger_callback);

}  // namespace aidl::android::hardware::health::charger
Loading