智能手机包含多个处理器,每个处理器都针对执行不同的任务进行了优化。但是,Android 只能在一个处理器上运行:应用处理器 (AP)。AP 经过调整,可在屏幕开启的使用场景(如游戏)中提供出色的性能,但它功耗过高,无法支持始终需要频繁、短暂地进行处理的功能,即使在屏幕关闭时也是如此。较小的处理器能够更高效地处理这些工作负载,在完成任务的同时,不会对电池续航时间产生明显影响。但是,这些低功耗处理器中的软件环境更受限制,并且差异可能很大,从而导致跨平台开发变得困难。
Context Hub Runtime Environment (CHRE) 提供了一个通用平台,用于在低功耗处理器上运行应用,并提供简单、标准化、对嵌入式友好型 API。借助 CHRE,设备 OEM 及其受信任的合作伙伴可以轻松地从 AP 卸载处理任务,从而节省电池电量、改善用户体验的各个方面,并支持一类始终开启、感知情境的功能,尤其是那些涉及将机器学习应用于环境感知的功能。
主要概念
CHRE 是一个软件环境,小型原生应用程序(称为微应用)在其中于低功耗处理器上执行,并通过通用的 CHRE API 与底层系统交互。为了加速 CHRE API 的正确实现,AOSP 中包含了一个跨平台的 CHRE 参考实现。该参考实现包括通用代码和抽象,通过一系列平台抽象层 (PAL) 实现对底层硬件和软件的抽象。微应用几乎总是与一个或多个在 Android 中运行的客户端应用相关联,这些客户端应用通过受限访问的 ContextHubManager
系统 API 与 CHRE 和微应用交互。
从高层次来看,CHRE 的架构与整个 Android 架构之间可以进行类比。然而,两者之间存在一些重要的区别:
- CHRE 仅支持运行以原生代码(C 或 C++)开发的微应用;不支持 Java。
- 由于资源限制和安全限制,CHRE 不向任何第三方 Android 应用开放使用。只有系统信任的应用才能访问它。
还需要区分 CHRE 的概念和传感器中枢的概念。虽然通常使用相同的硬件来实现传感器中枢和 CHRE,但 CHRE 本身不提供 Android 传感器 HAL 所需的传感器功能。CHRE 与 Context Hub HAL 相关联,并且它充当设备特定传感器框架的客户端,以接收传感器数据,而无需涉及 AP(应用处理器)。
图 1. CHRE 框架架构
Context Hub HAL
Context Hub 硬件抽象层 (HAL) 是 Android 框架和设备 CHRE 实现之间的接口,定义于 hardware/interfaces/contexthub
。Context Hub HAL 定义了 Android 框架通过其发现可用 Context Hub 及其微应用、通过消息传递与这些微应用交互以及允许加载和卸载微应用的 API。与 CHRE 参考实现配合使用的 Context Hub HAL 参考实现可在 system/chre/host
中找到。
如果本文档与 HAL 定义之间存在冲突,则以 HAL 定义为准。
初始化
当 Android 启动时,ContextHubService 调用 getHubs()
HAL 函数来确定设备上是否有任何可用的 Context Hub。这是一个阻塞式的一次性调用,因此它必须快速完成以避免延迟启动,并且它必须返回准确的结果,因为之后不能引入新的 Context Hub。
加载和卸载微应用
Context Hub 可以包含一组微应用,这些微应用包含在设备映像中,并在 CHRE 启动时加载。这些微应用被称为预加载微应用,应包含在对 queryApps()
的首次响应中。
Context Hub HAL 还支持在运行时通过 loadNanoApp()
和 unloadNanoApp()
函数动态加载和卸载微应用。微应用以特定于设备 CHRE 硬件和软件实现的二进制格式提供给 HAL。
如果加载微应用的实现涉及将其写入非易失性存储器(例如连接到运行 CHRE 的处理器的闪存存储器),则 CHRE 实现必须始终以禁用状态启动这些动态微应用。这意味着在收到通过 HAL 发送的 enableNanoapp()
请求之前,不会执行任何微应用的代码。预加载的微应用可以在启用状态下初始化。
Context Hub 重启
虽然 CHRE 在正常运行期间预计不会重启,但在出现意外情况(例如尝试访问未映射的内存地址)时,可能需要重启以进行恢复。在这些情况下,CHRE 与 Android 独立重启。HAL 通过 RESTARTED
事件通知 Android 这一点,只有在 CHRE 重新初始化到可以接受新请求(例如 queryApps()
)的程度后,才必须发送该事件。
CHRE 系统概述
CHRE 围绕事件驱动架构设计,其中计算的主要单元是传递给微应用的事件处理入口点的事件。虽然 CHRE 框架可以是多线程的,但给定的微应用永远不会从多个线程并行执行。CHRE 框架通过三个微应用入口点(nanoappStart()
、nanoappHandleEvent()
和 nanoappEnd()
)之一或通过先前 CHRE API 调用中提供的回调与给定的微应用交互,而微应用通过 CHRE API 与 CHRE 框架和底层系统交互。CHRE API 提供了一组基本功能以及用于访问上下文信号(包括传感器、GNSS、Wi-Fi、WWAN 和音频)的工具,并且可以通过额外的供应商特定功能进行扩展,供供应商特定的微应用使用。
构建系统
虽然 Context Hub HAL 和其他必要的 AP 端组件与 Android 一起构建,但在 CHRE 中运行的代码可能具有使其与 Android 构建系统不兼容的要求,例如需要专门的工具链。因此,AOSP 中的 CHRE 项目提供了一个基于 GNU Make 的简化构建系统,用于编译微应用,以及(可选)将 CHRE 框架编译为可以与系统集成的库。添加 CHRE 支持的设备制造商应将针对其目标设备的构建系统支持集成到 AOSP 中。
CHRE API 按照 C99 语言标准编写,参考实现使用适用于资源受限应用的 C++11 受限子集。
CHRE API
CHRE API 是 C 头文件的集合,定义了微应用和系统之间的软件接口。它旨在使微应用代码在所有支持 CHRE 的设备上兼容,这意味着微应用的源代码无需修改即可支持新的设备类型,尽管可能需要专门为目标设备的处理器指令集或应用程序二进制接口 (ABI) 重新编译。CHRE 架构和 API 设计还确保微应用在不同版本的 CHRE API 之间是二进制兼容的,这意味着微应用无需重新编译即可在实现不同版本 CHRE API 的系统上运行,与微应用编译所针对的目标 API 相比。换句话说,如果微应用二进制文件在支持 CHRE API v1.3 的设备上运行,并且该设备升级为支持 CHRE API v1.4,则相同的微应用二进制文件将继续运行。同样,微应用可以在 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)
包括对传感器和核心微应用功能(例如事件和计时器)的支持。
版本 1.1(Android 8)
通过 GNSS 定位和原始测量、Wi-Fi 扫描和移动网络信息引入了定位功能,以及对启用微应用到微应用通信的一般改进和其他改进。
版本 1.2(Android 9)
增加了对来自低功耗麦克风的数据、Wi-Fi RTT 测距、AP 唤醒和休眠通知以及其他改进的支持。
版本 1.3(Android 10)
增强了与传感器校准数据相关的功能,增加了对按需刷新批处理传感器数据的支持,定义了步数检测传感器类型,并使用额外的精度字段扩展了 GNSS 定位事件。
版本 1.4(Android 11)
增加了对 5G 蜂窝信息、微应用调试转储和其他改进的支持。
强制性系统功能
虽然上下文信号源(如传感器)被归类为可选功能区域,但一些核心功能是所有 CHRE 实现都必需的。这包括核心系统 API,例如用于设置计时器、向应用程序处理器上的客户端发送和接收消息、日志记录等的 API。有关完整详细信息,请参阅 API 标头。
除了 CHRE API 中编纂的核心系统功能外,Context Hub HAL 级别还指定了强制性的 CHRE 系统级功能。其中最重要的是动态加载和卸载微应用的能力。
C/C++ 标准库
为了最大限度地减少内存使用和系统复杂性,CHRE 实现仅需支持标准 C 和 C++ 库以及需要运行时支持的语言功能的子集。遵循这些原则,某些功能由于其内存和广泛的操作系统级依赖性而被明确排除,而另一些功能则因为它们被更合适的 CHRE 特定 API 所取代而被排除。以下功能并非旨在提供给微应用(尽管并非详尽列表):
- 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
。
相比之下,某些标准库功能是必需的。平台实现有责任通过静态库公开这些功能以包含在微应用二进制文件中,或通过微应用和系统之间的动态链接来公开这些功能。这包括但不限于:
- 字符串和数组实用程序:
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
- 基本运算:
虽然某些底层平台支持其他功能,但除非微应用将其外部依赖项限制为 CHRE API 函数和批准的标准库函数,否则该微应用不会被视为在 CHRE 实现之间可移植。
可选功能
为了促进硬件和软件,CHRE API 分为功能区域,从 API 的角度来看,这些功能区域被认为是可选的。虽然这些功能可能不是支持兼容 CHRE 实现所必需的,但它们可能是支持特定微应用所必需的。即使平台不支持给定的 API 集,引用这些功能的微应用也必须能够构建和加载。
传感器
CHRE API 提供了从传感器(包括加速度计、陀螺仪、磁力计、环境光传感器和接近传感器)请求数据的能力。这些 API 旨在提供类似于 Android 传感器 API 的功能集,包括支持批处理传感器样本以降低功耗。与在 AP 上运行相比,在 CHRE 中处理传感器数据可以实现更低的功耗和更低的运动信号处理延迟。
GNSS
CHRE 提供 API,用于从全球导航卫星系统 (GNSS)(包括 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 中处理音频数据可以使其与其他数据(如运动传感器)融合。
参考实现