Google 致力于为黑人社区推动种族平等。查看具体举措

动态可用的 HAL

Android 9 支持在不使用或不需要 Android 硬件子系统时动态关停这些子系统。例如,如果用户未使用 WLAN,WLAN 子系统就不应占用内存、耗用电量或使用其他系统资源。早期版本的 Android 中,在 Android 手机启动的整个期间,Android 设备上的 HAL/驱动程序都会保持开启状态。

实现动态关停涉及连接数据流以及执行动态进程,下文对此进行了详细介绍。

对 HAL 定义所做的更改

要实现动态关停,需要有关于哪些进程为哪些 HAL 接口提供服务的信息(此类信息之后在其他情况中也可能很有用),还需要确保在设备启动时不启动进程,而且在进程退出后,直到系统再次请求启动它们之前,都不重新启动它们。

# some init.rc script associated with the HAL
service vendor.some-service-name /vendor/bin/hw/some-binary-service
    # init language extension, provides information of what service is served
    # if multiple interfaces are served, they can be specified one on each line
    interface android.hardware.light@2.0::ILight default
    # restarted if hwservicemanager dies
    # would also cause the hal to start early during boot if oneshot wasn't set
    class hal
    # will not be restarted if it exits until it is requested to be restarted
    oneshot
    # will only be started when requested
    disabled
    # ... other properties

对 init 和 hwservicemanager 所做的更改

为了实现动态关停,还需要让 hwservicemanager 告知 init 启动所请求的服务。在 Android 9 中,init 包含三个额外的控制消息(例如,ctl.start):ctl.interface_startctl.interface_stopctl.interface_restart。这些消息可用于指示 init 打开或关闭特定硬件接口。如果系统请求使用某个服务但该服务未注册,hwservicemanager 会请求启动该服务。不过,动态 HAL 不需要使用以上任何消息。

确定 HAL 退出

在 Android 9 中,必须手动确定 HAL 退出。对于 Android 10 及更高版本,还可以使用自动生命周期确定 HAL 退出。

为了实现动态关停,需要多个政策来决定何时启动和关停 HAL。如果 HAL 出于任何原因而决定退出,当系统再次需要用到它时,它将使用以下信息和基础架构自动重新启动:HAL 定义中提供的信息,以及更改后的 inithwservicemanager 提供的基础架构。这可能会涉及多个不同的策略,包括:

  • 如果有人对 HAL 调用关闭命令或类似的 API,则 HAL 可能会选择自行调用退出命令。此行为必须在相应的 HAL 接口中指定。
  • HAL 可在任务完成后关停(记录在 HAL 文件中)。

自动生命周期

Android 10 为内核和 hwservicemanager 添加了更多支持,可让 HAL 在没有任何客户端时自动关停。如需使用此功能,请完成对 HAL 定义所做的更改部分的所有步骤,并执行以下操作:

  • 使用 LazyServiceRegistrar 而不是成员函数 registerAsService 通过 C++ 注册服务,例如:
    // only one instance of LazyServiceRegistrar per process
    LazyServiceRegistrar registrar;
    registrar.registerAsService(myHidlService /* , "default" */);
  • 验证 HAL 客户端是否仅在使用时保留对顶级 HAL(通过 hwservicemanager 注册的接口)的引用。为了避免出现延迟,如果该引用在继续执行的 hwbinder 线程上被丢弃,客户端还应该在丢弃引用后调用 IPCThreadState::self()->flushCommands(),以确保 Binder 驱动程序在相关引用计数发生变化时收到通知。