实现 Health 2.1

在 Android 11 中,所有 healthd 代码都被重构为 libhealthlooplibhealth2impl,然后进行了修改以实现 health@2.1 HAL。这两个库通过 health@2.0-impl-2.1(静态的 2.1 的直通实现)静态关联。通过静态链接库,health@2.0-impl-2.1 可以执行与 healthd 相同的工作,例如运行 healthd_mainloop 和轮询。在 init 中,health@2.1-service 会将接口 IHealth 的实现注册到 hwservicemanager。在使用 Android 8.x 或 9 供应商映像和 Android 11 框架升级设备时,供应商映像可能不会提供 health@2.1 服务。与旧版供应商映像的向后兼容性按照废弃时间表强制执行。

要确保向后兼容性,请执行以下操作:

  1. 尽管这是一个系统守护进程,healthd 会将 IHealth 注册到 hwservicemanager。将 IHealth 添加到系统清单中(实例名称为“backup”)。
  2. 框架和 storaged 通过 hwbinder(而不是 binder)与 healthd 进行通信。
  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 的板级变量。在系统/供应商 build 拆分过程中,无法为系统模块定义板级值。这些值会在已废弃的函数 healthd_board_init 中替换。

在 health@2.1 中,供应商可以在传递到运行状况实现类构造函数之前替换 healthd_config 结构体中的这两个周期性间隔值。运行状况实现类应继承自 android::hardware::health::V2_1::implementation::Health

实现 Health 2.1 服务

如需了解如何实现 Health 2.1 服务,请参阅 hardware/interfaces/health/2.1/README.md

Health 客户端

health@2.0 具有以下客户端:

  • chargerlibbatterymonitorhealthd_common 代码的使用在 health@2.0-impl 中封装。
  • recoverylibbatterymonitor 的链接封装在 health@2.0-impl 中。对 BatteryMonitor 的所有调用都会替换为对 Health 实现类的调用。
  • BatteryManagerBatteryManager.queryProperty(int id)IBatteryPropertiesRegistrar.getProperty 的唯一客户端。 IBatteryPropertiesRegistrar.getPropertyhealthd 提供,并直接读取 /sys/class/power_supply

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

  • BatteryService。在 Android 9 及更高版本中,BatteryService 使用 HealthServiceWrapper 来决定是使用来自 vendor 的默认 Health 服务实例还是使用来自 healthd 的备用 Health 服务实例。然后,BatteryService 通过 IHealth.registerCallback 监听健康事件。

  • Storaged。在 Android 9 及更高版本中,storaged 使用 libhealthhalutils 来决定是使用来自 vendor 的默认 Health 服务实例还是使用来自 healthd 的备用 Health 服务实例。然后,storaged 会通过 IHealth.registerCallback 侦听健康事件,并检索存储信息。

SELinux 更改

health@2.1 HAL 在平台中包含以下 SELinux 变更:

  • android.hardware.health@2.1-service 添加到 file_contexts

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

# 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-impl-2.1 会访问以下内核接口以检索电池信息:

  • /sys/class/power_supply/*/capacity_level(在运行状况 2.1 中添加)
  • /sys/class/power_supply/*/capacity
  • /sys/class/power_supply/*/charge_counter
  • /sys/class/power_supply/*/charge_full
  • /sys/class/power_supply/*/charge_full_design(在运行状况 2.1 中添加)
  • /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/*/time_to_full_now(在运行状况 2.1 中添加)
  • /sys/class/power_supply/*/type
  • /sys/class/power_supply/*/voltage_max
  • /sys/class/power_supply/*/voltage_now

默认情况下,使用 libbatterymonitor 的任何设备特定的 Health HAL 实现都会访问这些内核接口,除非它们在运行状况实现类构造函数中被替换。

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

Health 2.1 中使用的某些内核接口(如 /sys/class/power_supply/*/capacity_level/sys/class/power_supply/*/time_to_full_now)可能是可选的。不过,为了防止因缺少内核接口而导致错误的框架行为,建议您在编译 Health HAL 2.1 服务之前按需挑选 CL 1398913

测试

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

电池信息要求

运行状况 2.0 HAL 对 HAL 接口提供了一组要求,但相应的 VTS 测试在强制执行这些要求方面相对较为宽松。 在 Android 11 中,添加了新的 VTS 测试,以便在搭载 Android 11 及更高版本的设备上强制执行以下要求:

  • 当前的电池和平均电池状况必须为微单位 (~A)。
  • 当前电量和平均电池电量的符号必须正确无误。具体而言:
    • 当电池状态为 UNKNOWN 时,电流 == 0
    • 当电池状态为 CHARGING 时,电流 > 0
    • 当电池电量为 NOT_CHARGING 时,电流 <= 0
    • 当前电量状态低于 DISCHARGING
    • 电池状态为 FULL 时不强制执行
  • 电池状态必须正确无误,才能连接电源。具体而言:
    • 当且仅当连接电源时,电池状态必须是 CHARGINGNOT_CHARGINGFULL 之一;
    • 当且仅当电源源断开连接时,电池状态必须为 DISCHARGING

如果您在实现中使用 libbatterymonitor 并从内核接口传递值,请确保 sysfs 节点报告正确的值:

  • 确保使用正确的电量和单位对电池进行报告。这包括以下 sysfs 节点:
    • /sys/class/power_supply/*/current_avg
    • /sys/class/power_supply/*/current_max
    • /sys/class/power_supply/*/current_now
    • 正值表示传入电池的当前电量。
    • 值应以微单位 ($A) 表示。
  • 确保以微量 (VV) 为单位报告电池电压。这包括以下 sysfs 节点:
    • /sys/class/power_supply/*/voltage_max
    • /sys/class/power_supply/*/voltage_now
    • 请注意,默认 HAL 实现将 voltage_now 除以 1000,并报告以毫安 (mV) 为单位的值。请参阅 @1.0::HealthInfo

如需了解详情,请参阅 Linux 电源类