health AIDL: Add readme
Test: none
Bug: 177269435
Change-Id: I54e69d7789c6e1246bb126a27f9463e04407314e
diff --git a/health/aidl/README.md b/health/aidl/README.md
new file mode 100644
index 0000000..53a4f91
--- /dev/null
+++ b/health/aidl/README.md
@@ -0,0 +1,293 @@
+# 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]: #