实现“运行状况”
所有 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 服务。这项服务是按照弃用时间表强制执行的。
为了解决此问题:
healthd
会将IHealth
注册到hwservicemanager
(尽管它是系统守护进程)。IHealth
会被添加到系统清单中(实例名称为“backup”)。- 框架和
storaged
会通过healthd
(而不是hwbinder
)与binder
进行通信。 - 框架和
storaged
的代码会进行更改,以获取实例“default”(如果有),然后获取“backup”。- C++ 客户端代码会使用
libhealthhalutils
中定义的逻辑。 - Java 客户端代码会使用
HealthServiceWrapper
中定义的逻辑。
- C++ 客户端代码会使用
- 在广泛推出 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
(如上所述),并旨在封装 libbatterymonitor
和 libhealthd.BOARD
。这些 health@2.0-impl 用户不得直接使用 BatteryMonitor
,也不得直接使用 libhealthd
中的函数;而应该将这些调用替换为对 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_init
和healthd_board_battery_update
函数的空实现。
-
如果板级
BOARD_PERIODIC_CHORES_INTERVAL_*
变量:- 已定义,则创建设备特定的
HealthServiceCommon.cpp
(从hardware/interfaces/health/2.0/utils/libhealthservice
中复制),并在healthd_mode_service_2_0_init
中对其进行自定义。 - 未定义,则静态关联到
libhealthservice
。
- 已定义,则创建设备特定的
-
如果设备:
- 应该实现
getStorageInfo
和getDiskStats
API,则在get_storage_info
和get_disk_stats
函数中提供实现。 - 不应该实现这些 API,则静态关联到
libstoragehealthdefault
。
- 应该实现
-
更新必要的 SELinux 权限。
-
通过在恢复映像中安装直通实现来实现恢复中的 HAL。例如:
// Android.bp cc_library_shared { name: "android.hardware.health@2.0-impl-<device>", recovery_available: true, relative_install_path: "hw", static_libs: [ "android.hardware.health@2.0-impl", "libhealthd.<device>" // Include the following or implement device-specific storage APIs "libhealthstoragedefault", ], srcs: [ "HealthImpl.cpp", ], overrides: [ "android.hardware.health@2.0-impl-default", ], }
// HealthImpl.cpp #include <health2/Health.h> #include <healthd/healthd.h> using android::hardware::health::V2_0::IHealth; using android::hardware::health::V2_0::implementation::Health; extern "C" IHealth* HIDL_FETCH_IHealth(const char* name) { const static std::string providedInstance{"default"}; if (providedInstance != name) return nullptr; return Health::initInstance(&gHealthdConfig).get(); }
# device.mk PRODUCT_PACKAGES += android.hardware.health@2.0-impl-<device>
如需了解详情,请参阅 hardware/interfaces/health/2.0/README.md。
Health 客户端
health@2.0 具有以下客户端:
- charger。
libbatterymonitor
和healthd_common
代码的使用情况信息封装在 health@2.0-impl 中。 - recovery。
libbatterymonitor
的链接封装在 health@2.0-impl 中。对Health
实现类的调用取代了对BatteryMonitor
的所有调用。 -
BatteryManager。
BatteryManager.queryProperty(int id)
是IBatteryPropertiesRegistrar.getProperty
(由healthd
提供并直接读取/sys/class/power_supply
)的唯一客户端。出于安全方面的考虑,不允许应用直接调用 Health HAL。在 Android 9 中,Binder 服务
IBatteryPropertiesRegistrar
由BatteryService
(而非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_server
和storaged
使用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
在被移除之前继续正常发挥作用)编写的。