创建 HAL 接口

您必须使用 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.bpAndroid.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