您必须使用 HIDL 来描述所有用于有条件地编译框架的构建标志。相关的构建标志必须分组并包含在单个 .hal
文件中。使用 HIDL 指定配置项包括以下好处
- 版本化(要添加新的配置项,供应商/OEM 必须显式扩展 HAL)
- 文档完善
- 使用 SELinux 进行访问控制
- 通过 供应商测试套件对配置项进行健全性检查(范围检查、项之间的相互依赖性检查等)
- C++ 和 Java 中的自动生成 API
识别框架使用的构建标志
首先识别用于有条件地编译框架的构建配置,然后放弃过时的配置以缩小集合。例如,为 surfaceflinger
识别出以下构建标志集
TARGET_USES_HWC2
TARGET_BOARD_PLATFORM
TARGET_DISABLE_TRIPLE_BUFFERING
TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
NUM_FRAMEBUFFER_SURFACE_BUFFERS
TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
VSYNC_EVENT_PHASE_OFFSET_NS
SF_VSYNC_EVENT_PHASE_OFFSET_NS
PRESENT_TIME_OFFSET_FROM_VSYNC_NS
MAX_VIRTUAL_DISPLAY_DIMENSION
创建 HAL 接口
子系统的构建配置通过 HAL 接口访问,而用于提供配置值的接口则分组在 HAL 包 android.hardware.configstore
中(当前版本为 1.0)。例如,要为 surfaceflinger
创建 HAL 接口文件,请在 hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
中创建
package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { // TO-BE-FILLED-BELOW };
创建 .hal
文件后,运行 hardware/interfaces/update-makefiles.sh
以将新的 .hal
文件添加到 Android.bp
和 Android.mk
文件中。
为构建标志添加函数
对于每个构建标志,向接口添加一个新函数。例如,在 hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
中
interface ISurfaceFlingerConfigs { disableTripleBuffering() generates(OptionalBool ret); forceHwcForVirtualDisplays() generates(OptionalBool ret); enum NumBuffers: uint8_t { USE_DEFAULT = 0, TWO = 2, THREE = 3, }; numFramebufferSurfaceBuffers() generates(NumBuffers ret); runWithoutSyncFramework() generates(OptionalBool ret); vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret); presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret); maxVirtualDisplayDimension() generates(OptionalInt32 ret); };
添加函数时
- 名称要简洁。 避免将 makefile 变量名转换为函数名,并记住
TARGET_
和BOARD_
前缀不再是必需的。 - 添加注释。 帮助开发人员理解配置项的用途、它如何更改框架行为、有效值以及其他相关信息。
函数返回类型可以是 Optional[Bool|String|Int32|UInt32|Int64|UInt64]
。类型在同一目录的 types.hal
中定义,并使用一个字段包装原始值,该字段指示该值是否由 HAL 指定;如果未指定,则使用默认值。
struct OptionalString { bool specified; string value; };
在适当的时候,定义最能代表配置项类型的枚举,并将该枚举用作返回类型。在上面的示例中,定义了 NumBuffers
枚举来限制有效值的数量。在定义此类自定义数据类型时,添加一个字段或一个枚举值(例如,USE_DEFAULT
)以表示该值是否由 HAL 指定。
单个构建标志不必成为 HIDL 中的单个函数。模块所有者也可以将密切相关的构建标志聚合到一个结构中,并让一个函数返回该结构(这样做可以减少函数调用的次数)。
例如,将两个构建标志聚合到 hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
中的单个结构中的一个选项是
interface ISurfaceFlingerConfigs { // other functions here struct SyncConfigs { OptionalInt64 vsyncEventPhaseoffsetNs; OptionalInt64 presentTimeoffsetFromSyncNs; }; getSyncConfigs() generates (SyncConfigs ret); // other functions here };
单个 HAL 函数的替代方案
作为对所有构建标志使用单个 HAL 函数的替代方案,HAL 接口还提供了简单的函数,例如 getBoolean(string key)
和 getInteger(string key)
。实际的 key=value
对存储在单独的文件中,HAL 服务通过读取/解析这些文件来提供值。
虽然这种方法易于定义,但它不包括 HIDL 提供的优势(强制版本控制、易于编写文档、访问控制),因此不建议使用。
单个和多个接口
配置项的 HAL 接口设计提供两种选择
- 涵盖所有配置项的单个接口
- 多个接口,每个接口涵盖一组相关的配置项
单个接口更简单,但随着更多配置项添加到单个文件中,可能会变得难以维护。此外,访问控制不够精细,因此被授予接口访问权限的进程可以读取所有配置项(无法授予对部分配置项的访问权限)。或者,如果不授予访问权限,则无法读取配置项。
由于这些问题,Android 使用多个接口,并为一组相关的配置项使用单个 HAL 接口。例如,用于 surfaceflinger
相关配置项的 ISurfaceflingerConfigs
和用于蓝牙相关配置项的 IBluetoothConfigs
。