智能手机中包含许多处理器,每个处理器都针对不同的任务进行了优化。不过,Android 仅在一个处理器上运行,即应用处理器 (AP)。AP 经过调优,针对游戏等屏幕用例提供出色的性能,但是它过于耗电,无法持续支持会频繁出现短时处理量爆发的功能,即使屏幕关闭时耗电也非常快。较小的处理器能够更有效地处理这些工作负载,在不显著影响续航时间的情况下完成各项任务。然而,这些低功耗处理器中的软件环境较为受限,并且差别很大,导致跨平台开发变得非常困难。
Context Hub 运行时环境 (CHRE) 通过简单、标准化的嵌入式 API,为在低功耗处理器上运行应用提供了一个通用平台。CHRE 使原始设备制造商 (OEM) 及其信赖的合作伙伴能够便捷地从 AP 中分流处理任务,从而节省电量并改进用户体验的各个方面,同时它还支持一类始终开启并能感知情境的功能,特别是通过机器学习感知环境的功能。
主要概念
CHRE 是一种软件环境,一种名为 nanoapp 的小型原生应用可以在此环境下在低功耗处理器上运行,并通过通用的 CHRE API 与底层系统进行交互。为了加快 CHRE API 的正确实现,AOSP 中提供了一个 CHRE 的跨平台参考实现。该参考实现包含通用代码以及通过一系列平台抽象层 (PAL) 实现的底层硬件和软件的抽象。nanoapp 几乎总是与 Android 中运行的一个或多个客户端应用相关联,这些应用通过实行访问限制的 ContextHubManager
系统 API 与 CHRE 和 nanoapp 进行交互。
整体看来,CHRE 的架构和整个 Android 架构有相似之处。但是,它们有一些重要的区别:
- CHRE 仅支持运行以原生代码(C 或 C++)开发的 nanoapp,不支持 Java。
- 由于资源限制和安全限制,CHRE 无法供任意第三方 Android 应用使用。只有系统信任的应用才能访问它。
CHRE 和传感器中枢的概念之间还有一个显著的区别。虽然通常会使用相同的硬件来实现传感器中枢和 CHRE,但 CHRE 本身不会提供 Android Sensors HAL 所需的传感器功能。CHRE 与 Context Hub HAL 相关联,并且充当设备专用传感器框架的客户端,无需涉及 AP 即可接收传感器数据。
图 1. CHRE 框架架构
Context Hub HAL
Context Hub 硬件抽象层 (HAL) 是 Android 框架与设备的 CHRE 实现之间的接口,在 hardware/interfaces/contexthub
中做了定义。Context Hub HAL 定义了 Android 框架中用于发现可用情境中枢及其 nanoapp 的 API,通过传递消息与这些 nanoapp 进行交互,并且允许加载和卸载 nanoapp。system/chre/host
中提供了与 CHRE 参考实现相关的 Context Hub HAL 参考实现。
如果本文档与 HAL 定义之间存在冲突,应以 HAL 定义为准。
初始化
当 Android 启动时,ContextHubService 会调用 getHubs()
HAL 函数来确定设备上是否有任何可用的情境中枢。这是一个屏蔽式的一次性调用,因此它必须快速完成以避免启动延迟,并且必须返回准确的结果,因为之后无法引入新的情境中枢。
加载和卸载 nanoapp
情境中枢可以添加一组包含在设备映像中并在 CHRE 启动时加载的 nanoapp。这些都称为预加载的 nanoapp,并且应包含在对 queryApps()
的第一次响应中。
Context Hub HAL 还支持在运行时通过 loadNanoApp()
和 unloadNanoApp()
函数动态加载和卸载 nanoapp。向 HAL 提供的 nanoapp 应采用设备 CHRE 硬件和软件实现专用的二进制格式。
如果加载 nanoapp 的实现涉及将其写入非易失性内存(例如连接到运行 CHRE 的处理器的闪存存储设备),则 CHRE 实现必须始终在这些动态 nanoapp 处于禁用状态时启动。也就是说,在通过 HAL 接收 enableNanoapp()
请求之前,系统不会执行 nanoapp 的任何代码。预加载的 nanoapp 可以在启用状态下初始化。
Context Hub 重启
尽管在正常操作过程中,CHRE 不会重启,但有时也可能需要从意外情况中恢复,例如在尝试访问未映射的内存地址时。在这些情况下,CHRE 独立于 Android 重新启动。HAL 通过 RESTARTED
事件通知 Android,而此类事件必须在 CHRE 重新初始化为能够接受新请求(例如 queryApps()
)之后才能发送。
CHRE 系统概览
CHRE 围绕事件驱动型架构而设计,其中主要计算单元是传递给 nanoapp 事件处理入口点的事件。虽然 CHRE 框架支持多线程,但绝不会从多个线程并行执行某个 nanoapp。CHRE 框架通过三个 nanoapp 入口点(nanoappStart()
、nanoappHandleEvent()
和 nanoappEnd()
)之一或通过先前的 CHRE API 调用中提供的回调,与给定的 nanoapp 进行交互,而 nanoapp 则通过 CHRE API 与 CHRE 框架和底层系统进行交互。CHRE API 提供了一系列基本功能以及用于访问情境信号(包括传感器、GNSS、Wi-Fi、WWAN 和音频)的工具,并且可以进行扩展,增加额外的供应商专用功能,以供供应商专用 nanoapp 使用。
构建系统
尽管 Context Hub HAL 和其他必要的 AP 端组件均是和 Android 一起构建的,但在 CHRE 中运行的代码可能会有使其与 Android 构建系统不兼容的要求,例如需要专用的工具链。因此,AOSP 中的 CHRE 项目基于 GNU Make 提供了一个简化的构建系统,用于将 nanoapp 以及 CHRE 框架(后者为可选操作)编译为可与系统集成的库。如果设备制造商希望添加对 CHRE 的支持,则应在 AOSP 中集成对其目标设备的构建系统支持。
CHRE API 是采用 C99 语言标准编写的,而参考实现使用的是 C++11 受限子集,适合资源有限的应用。
CHRE API
CHRE API 是 C 头文件的集合,这些头文件用于定义 nanoapp 和系统之间的软件接口。此 API 旨在让 nanoapp 代码在支持 CHRE 的所有设备上兼容,这意味着无需修改 nanoapp 的源代码来支持新的设备类型。不过,可能仍需要针对目标设备的处理器指令集或应用二进制接口 (ABI) 专门重新编译 nanoapp 的源代码。CHRE 架构和 API 设计还可确保 nanoapp 兼容不同版本的 CHRE API 中的二进制文件,这意味着如果系统实现的 CHRE API 版本与编译 nanoapp 所针对的目标 API 不同,nanoapp 无需重新编译即可在该系统上运行。换句话说,如果 nanoapp 二进制文件在支持 CHRE API v1.3 的设备上运行,然后该设备升级到支持 CHRE API v1.4,同一 nanoapp 二进制文件将继续正常运行。同样,nanoapp 可以在 CHRE API v1.2 上运行,并可在运行时确定它是否需要 API v1.3 的功能来实现其功能或是否可能通过功能优雅降级来实现正常运行。
CHRE API 的新版本会随 Android 一起发布,但由于 CHRE 实现是供应商实现的一部分,因此设备支持的 CHRE API 版本不一定与 Android 版本相关联。
版本摘要
与 Android HIDL 版本控制方案一样,CHRE API 遵循语义版本控制。主要版本编号可以表明二进制兼容性,次要版本编号则在引入向后兼容的功能时递增。CHRE API 包含源代码注解,可标识哪个版本引入了函数或参数,例如 @since v1.1
。
CHRE 实现还通过 chreGetVersion()
公开平台专用补丁版本,这会表明在实现过程中何时进行了问题修复或次要更新。
版本 1.0 (Android 7)
添加了对传感器和核心 nanoapp 功能(例如事件和计时器)的支持。
版本 1.1 (Android 8)
引入了通过 GNSS 位置信息和原始测量数据、Wi-Fi 扫描和移动网络信息实现的位置信息功能,并进行了常规优化以支持 nanoapp 间通信,而且还进行了其他改进。
版本 1.2 (Android 9)
添加了对来自低功耗麦克风、Wi-Fi RTT 范围变化、AP 唤醒和休眠通知以及其他改进的数据的支持。
版本 1.3 (Android 10)
增强了与传感器校准数据相关的功能,添加了对根据需要刷新批量传感器数据的支持,定义了步数检测传感器类型,并通过额外的准确率字段扩展了 GNSS 位置事件。
版本 1.4 (Android 11)
添加了对 5G 移动网络信息、nanoapp 调试转储和其他改进的支持。
强制性系统功能
虽然情境信号的来源(例如传感器)被归类为可选功能领域,但所有 CHRE 实现都需要几个核心功能。这包括核心系统 API,例如用于设置计时器、在应用处理器上向客户端发送消息以及接收消息、执行日志记录等的 API。如需了解完整详情,请参阅 API 标头。
除了 CHRE API 中编码的核心系统功能之外,Context Hub HAL 级别还指定了强制性的 CHRE 系统级功能。其中最重要的一个功能是能够动态加载和卸载 nanoapp。
C/C++ 标准库
为了最大限度地减少内存用量和系统复杂性,CHRE 实现只需支持一部分标准 C 和 C++ 库以及需要运行时支持的语言功能。根据这些原则,一些功能因其内存和广泛的操作系统级依赖项而被明确排除,而另一些功能则被更合适的 CHRE 专用 API 代替。以下所列功能(非完整列表)并非面向 nanoapp 提供:
- C++ 异常和运行时类型信息 (RTTI)
- 标准库多线程支持,包括 C++11 标头
<thread>
、<mutex>
、<atomic>
、<future>
- C 和 C++ 标准输入/输出库
- C++ 标准模板库 (STL)
- C++ 标准正则表达式库
- 通过标准函数(例如
malloc
、calloc
、realloc
、free
、operator new
)和其他本身使用动态分配的标准库函数进行动态内存分配,例如std::unique_ptr
- 本地化和 Unicode 字符支持
- 日期和时间库
- 用于修改常规程序流的函数,包括
<setjmp.h>
、<signal.h>
、abort
、std::terminate
- 访问主机环境,包括
system
、getenv
- 未包含在 C99 或 C++11 语言标准中的 POSIX 和其他库
在很多情况下,CHRE API 函数和实用程序库都提供了等效功能。例如,chreLog
可用于以 Android logcat 系统为目标的调试日志记录,其中较为传统的程序可以使用 printf
或 std::cout
。
在其他情况下,则需要一些标准库功能。平台实现可以通过静态库公开这些功能,以纳入 nanoapp 二进制文件,或通过动态链接 nanoapp 和系统实现。其中包括但不限于:
- 字符串和数组实用程序:
memcmp
、memcpy
、memmove
、memset
、strlen
数学库:常用的单精度浮点函数:
- 基本运算:
ceilf
、fabsf
、floorf
、fmaxf
、fminf
、fmodf
、roundf
、lroundf
、remainderf
- 指数函数和幂函数:
expf
、log2f
、powf
、sqrtf
- 三角函数和双曲函数:
sinf
、cosf
、tanf
、asinf
、acosf
、atan2f
、tanhf
- 基本运算:
虽然某些底层平台支持其他功能,但除非将 nanoapp 的外部依赖项限制到 CHRE API 函数和已批准的标准库函数范围,否则它不会被视为可跨 CHRE 移植。
可选功能
为了提升硬件和软件,CHRE API 分为多个功能区域,从 API 角度来看这些功能区域被视为可选项。虽然可能不需要这些功能来支持兼容的 CHRE 实现,但可能需要它们来支持特定 nanoapp。即使平台不支持一组给定的 API,引用这些函数的 nanoapp 也必须能够进行构建和加载。
传感器
CHRE API 能够从加速度计、陀螺仪、磁力计、环境光传感器和近程传感器等传感器请求获取数据。 这些 API 旨在提供与 Android 传感器 API 类似的功能集,包括支持批处理传感器样本以减少耗电量。与在 AP 上运行相比,在 CHRE 中处理传感器数据可以显著降低动态信号的能耗和处理延迟时间。
GNSS
CHRE 提供用于从全球导航卫星系统 (GNSS) 请求获取位置数据的 API,其中包括 GPS 和其他卫星星座。这包括请求定期位置信息更正以及原始测量数据,尽管两者都是独立的功能。由于 CHRE 具有指向 GNSS 子系统的直接链接,因此与基于 AP 的 GNSS 请求相比,耗电量会下降,因为该 AP 可在位置会话的整个生命周期中保持休眠状态。
Wi-Fi
CHRE 提供了与 Wi-Fi 芯片交互的功能,主要用于位置用途。虽然 GNSS 非常适合户外位置定位,但 Wi-Fi 扫描结果可以在室内和开发区域中提供准确的位置信息。除了免除唤醒 AP 进行扫描所需的开销之外,CHRE 还可以监听 Wi-Fi 固件为连接目的执行的 Wi-Fi 扫描结果,为了节约能耗,通常不会将此结果传送到 AP。使用连接扫描进行情境匹配有助于减少执行的 Wi-Fi 扫描总数,从而节省电量。
CHRE API v1.1 中添加了对 Wi-Fi 的支持,其中包括监测扫描结果和按需触发扫描的功能。这些功能已在 v1.2 中进行了扩展,并且能够针对支持该功能的接入点执行往返时间 (RTT) 测量,从而精准地确定相对位置。
WWAN
CHRE API 能够检索服务小区及其邻域的小区的识别信息,通常用于粗略位置定位。
音频
CHRE 可以处理来自低功耗麦克风的批量音频数据,这通常会利用用于实现 SoundTrigger HAL 的硬件。在 CHRE 中处理音频数据可以使其与其他数据(例如移动传感器)融合。
参考实现
CHRE 框架的参考代码包含在 system/chre
项目的 AOSP 中(在 C++11 中实现)。虽然不是严格要求,但建议所有 CHRE 实现都基于此代码库,这有助于确保实现一致性,并加快新功能的采用速度。此代码可以视为对核心 Android 框架的模拟,因为它是应用使用的 API 的开源实现,可用作兼容性的基准和标准。虽然可以使用供应商专用功能对其进行自定义和扩展,但建议保证通用代码尽可能接近参考代码。与 Android 的 HAL 类似,CHRE 参考实现使用各种平台抽象化,以便能够适应任何满足最低要求的设备。
如需了解技术详情和移植指南,请参阅 system/chre
项目中包含的 README 文件。