实现“运行状况”

所有 healthd 代码均已重构为 health@2.0-impl 和 libhealthservice,然后均已经过修改以实现 health@2.0 HAL。这两个库通过 health@2.0-service 进行静态关联,这使得 health@2.0-service 能够完成之前由 healthd 完成的作业(即运行 healthd_mainloop 并完成轮询)。在 init 中,health@2.0-service 会将接口 IHealth 的实现注册到 hwservicemanager。在升级搭载 Android 8.x 供应商映像和 Android 9 框架的设备时,供应商映像可能不提供 health@2.0 服务。这项服务是按照弃用时间表强制执行的。

为了解决此问题:

  1. healthd 会将 IHealth 注册到 hwservicemanager(尽管它是系统守护进程)。IHealth 会被添加到系统清单中(实例名称为“backup”)。
  2. 框架和 storaged 会通过 healthd(而不是 hwbinder)与 binder 进行通信。
  3. 框架和 storaged 的代码会进行更改,以获取实例“default”(如果有),然后获取“backup”。
    • C++ 客户端代码会使用 libhealthhalutils 中定义的逻辑。
    • Java 客户端代码会使用 HealthServiceWrapper 中定义的逻辑。
  4. 在广泛推出 IHealth/default 实例且弃用 Android 8.1 供应商映像后,就可以弃用 IHealth/backup 实例和 healthd 了。如需了解详情,请参阅弃用 health@1.0

针对 healthd 的板级编译变量

BOARD_PERIODIC_CHORES_INTERVAL_* 是用于编译 healthd 的板级变量。板级值用于分隔系统编译部分和供应商编译部分,无法针对系统模块定义进行定义。在 health@2.0 中,供应商可以在 healthd_mode_ops->init 中覆盖这两个值(方法是弃用 health@2.0-service.<device> 中的 libhealthservice 依赖项并重新实现此函数)。

静态实现库

与其他 HAL 实现库不同,实现库 health@2.0-impl 是一个静态库,health@2.0-service、charger、recovery 和旧版 healthd 均关联到此库。

health@2.0.impl 会实现 IHealth(如上所述),并旨在封装 libbatterymonitorlibhealthd.BOARD。这些 health@2.0-impl 用户不得直接使用 BatteryMonitorlibhealthd 中的函数,而应该将这些调用替换为对 Health 类的调用(即实现 IHealth 接口)。为了进一步进行泛化,healthd_common 代码也会包含在 health@2.0-impl 中。新的 healthd_common 包含 health@2.0-service、charger 和 healthd 之间公用代码的剩余部分,并会调用 IHealth 方法(而不是 BatteryMonitor)。

实现 Health 2.0 服务

在为设备实现 health@2.0 服务时,如果默认实现:

  • 足以用于设备,则直接使用 android.hardware.health@2.0-service
  • 不足以用于设备,则创建 android.hardware.health@2.0-service.(device) 可执行文件并包括:

    #include <health2/service.h>
    int main() { return health_service_main(); }
    

然后:

  • 如果板级 libhealthd:

    • 确实存在,则与其关联。
    • 不存在,则提供针对 healthd_board_inithealthd_board_battery_update 函数的空实现。
  • 如果板级 BOARD_PERIODIC_CHORES_INTERVAL_* 变量:

    • 已定义,则创建设备特定的 HealthServiceCommon.cpp(从 hardware/interfaces/health/2.0/utils/libhealthservice 中复制),并在 healthd_mode_service_2_0_init 中对其进行自定义。
    • 未定义,则静态关联到 libhealthservice
  • 如果设备:

    • 应该实现 getStorageInfogetDiskStats API,则在 get_storage_infoget_disk_stats 函数中提供实现。
    • 不应该实现这些 API,则静态关联到 libstoragehealthdefault
  • 更新必要的 SELinux 权限。

如需了解详情,请参阅 hardware/interfaces/health/2.0/README.md

Health 客户端

health@2.0 具有以下客户端:

  • chargerlibbatterymonitorhealthd_common 代码的使用情况信息封装在 health@2.0-impl 中。
  • recoverylibbatterymonitor 的链接封装在 health@2.0-impl 中。对 Health 实现类的调用取代了对 BatteryMonitor 的所有调用。
  • BatteryManagerBatteryManager.queryProperty(int id)IBatteryPropertiesRegistrar.getProperty(由 healthd 提供并直接读取 /sys/class/power_supply)的唯一客户端。

    出于安全方面的考虑,不允许应用直接调用 Health HAL。在 Android 9 中,Binder 服务 IBatteryPropertiesRegistrarBatteryService(而非 healthd)提供,BatteryService 会将调用委派给 Health HAL 以检索请求的信息。

  • BatteryService。在 Android 9 中,BatteryService 使用 HealthServiceWrapper 来确定要使用的 Health 服务实例(来自供应商的“default”实例或来自 healthd 的“backup”实例)。然后,它通过 IHealth.registerCallback 侦听 Health 事件。

  • Storaged。在 Android 9 中,storaged 使用 libhealthhalutils 来确定要使用的 Health 服务实例(来自供应商的“default”实例或来自 healthd 的“backup”实例)。然后,它通过 IHealth.registerCallback 侦听 Health 事件并检索存储信息。

SELinux 变更

新的 health@2.0 HAL 包括以下 SELinux 变更:

  • 将 health@2.0-service 添加到 file_contexts
  • 允许 system_serverstoraged 使用 hal_health
  • 允许 system_server (BatteryService) 注册 batteryproperties_service (IBatteryPropertiesRegistrar)。
  • 允许 healthd 提供 hal_health
  • 移除允许 system_server/storaged 通过 Binder 调用 healthd 的规则。
  • 移除允许 healthd 注册 batteryproperties_service (IBatteryPropertiesRegistrar) 的规则。

对于具有自己实现的设备,一些供应商 SELinux 变更可能是必须的。例如:

# device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
/vendor/bin/hw/android\.hardware\.health@2\.0-service.<device> u:object_r:hal_health_default_exec:s0

# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
# Add device specific permissions to hal_health_default domain, especially
# if it links to board-specific libhealthd or implements storage APIs.

内核接口

healthd 守护进程和默认实现 android.hardware.health@2.0-service 会访问以下内核接口以检索电池信息:

  • /sys/class/power_supply/*/capacity
  • /sys/class/power_supply/*/charge_counter
  • /sys/class/power_supply/*/charge_full
  • /sys/class/power_supply/*/current_avg
  • /sys/class/power_supply/*/current_max
  • /sys/class/power_supply/*/current_now
  • /sys/class/power_supply/*/cycle_count
  • /sys/class/power_supply/*/health
  • /sys/class/power_supply/*/online
  • /sys/class/power_supply/*/present
  • /sys/class/power_supply/*/status
  • /sys/class/power_supply/*/technology
  • /sys/class/power_supply/*/temp
  • /sys/class/power_supply/*/type
  • /sys/class/power_supply/*/voltage_max
  • /sys/class/power_supply/*/voltage_now

默认情况下,使用 libbatterymonitor 的任何设备特定的 Health HAL 实现都会访问这些内核接口(除非它们在 healthd_board_init(struct healthd_config*) 中被覆盖)。

如果这些文件缺失或者无法从 healthd 或默认服务访问这些文件(例如,文件是一个指向供应商专用文件夹的符号链接,因 SELinux 政策配置错误而拒绝访问),则文件无法访问。因此,即使使用的是默认实现,也可能需要进行其他的供应商特定 SELinux 变更。

测试

Android 9 包括专门为 health@2.0 HAL 编写的新 VTS 测试。如果设备声明在设备清单中提供 health@2.0 HAL,则该设备必须通过相应的 VTS 测试。这些测试是为“default”实例(确保设备正确实现 HAL)和“backup”实例(确保 healthd 在被移除之前继续正常发挥作用)编写的。