2. 传统HAL (Legacy HAL) 架构详解:libhardware架构、模块加载机制、hw_module_t与hw_device_t结构体

在Android系统演进过程中,传统HAL(Legacy HAL)是早期(Android 4.x及之前)定义的硬件抽象层标准,其核心实现位于 libhardware 库中。理解这一架构是掌握后续HAL演进(如Camera HAL3)的基础。本章将深入剖析libhardware的模块化设计、动态加载机制以及核心数据结构。

2.1 libhardware 架构概述

libhardware 是Android系统中最底层的硬件抽象库,它定义了一套统一的接口规范,使得上层Framework(如Camera Service、Audio Service)无需关心具体硬件实现细节。其核心设计思想是:模块化与动态加载。

核心目标: 将硬件驱动细节封装在共享库(.so)中,通过标准接口进行加载与调用,实现Framework与硬件解耦。

下图展示了libhardware在Android系统架构中的位置及其与上下层的关系:

libhardware 架构在 Android 系统中的位置 Android Framework (CameraService, AudioFlinger) libhardware (HAL 标准接口层) hw_get_module() / hw_device_t 标准结构 camera.xxx.so audio.xxx.so gralloc.xxx.so Linux Kernel (Camera / Audio / GPU 驱动) 图:libhardware 作为中间层,向下屏蔽驱动差异,向上提供统一接口

2.2 模块加载机制:hw_get_module()

传统HAL的核心加载函数是 hw_get_module(),它负责根据模块ID和厂商实现,动态加载对应的共享库(.so)。其工作流程如下:

  1. 确定模块ID: 上层服务传入预定义的模块ID(如 CAMERA_HARDWARE_MODULE_ID)。
  2. 搜索路径: 系统按照优先级顺序搜索以下路径:
    • /vendor/lib/hw/ (厂商定制路径,优先)
    • /system/lib/hw/ (系统默认路径)
  3. 文件名匹配: 搜索形如 <MODULE_ID>.<variant>.so 的文件,其中 variant 由硬件属性(如 ro.product.board)决定。
  4. 动态加载: 使用 dlopen() 加载共享库,并通过 dlsym() 获取 HAL_MODULE_INFO_SYM 符号(即 hw_module_t 结构体)。
  5. 返回模块: 将加载的 hw_module_t 指针返回给调用者。
关键点: 文件名中的 variant 机制允许同一模块ID对应不同硬件平台的实现,例如 camera.msm8998.so 和 camera.exynos8890.so 可以共存。

以下是 hw_get_module() 的核心逻辑伪代码:

// 位于 hardware/libhardware/hardware.c
int hw_get_module(const char *id, const hw_module_t **module) {
    // 1. 获取硬件 variant(如 board 名)
    char variant[PROPERTY_VALUE_MAX];
    property_get("ro.product.board", variant, "");

    // 2. 构造搜索路径列表
    const char *paths[] = {
        "/vendor/lib/hw",
        "/system/lib/hw"
    };

    // 3. 遍历路径,尝试加载
    for (int i = 0; i < 2; i++) {
        char filename[PATH_MAX];
        // 构造文件名:<id>.<variant>.so
        snprintf(filename, sizeof(filename), "%s/%s.%s.so",
                 paths[i], id, variant);

        // 4. 使用 dlopen 加载
        void *handle = dlopen(filename, RTLD_NOW);
        if (handle) {
            // 5. 获取 HAL_MODULE_INFO_SYM 符号
            hw_module_t *hmi = (hw_module_t *)dlsym(handle, HAL_MODULE_INFO_SYM_AS_STR);
            if (hmi) {
                *module = hmi;
                return 0;
            }
        }
    }
    return -ENOENT; // 未找到模块
}

2.3 核心数据结构:hw_module_t 与 hw_device_t

传统HAL定义了两个核心结构体,它们是所有硬件模块交互的基础:

2.3.1 hw_module_t:模块描述符

hw_module_t 描述一个硬件模块的元信息,每个共享库必须导出一个该类型的实例,并命名为 HAL_MODULE_INFO_SYM(通常为 HMI)。

// 位于 hardware/libhardware/include/hardware/hardware.h
typedef struct hw_module_t {
    /** 标签,必须设置为 HARDWARE_MODULE_TAG */
    uint32_t tag;

    /** 模块主版本号 */
    uint16_t version_major;

    /** 模块次版本号 */
    uint16_t version_minor;

    /** 模块 ID,如 "camera"、"audio" */
    const char *id;

    /** 模块名称(可读字符串) */
    const char *name;

    /** 模块作者 */
    const char *author;

    /** 模块自定义方法,用于打开设备 */
    struct hw_module_methods_t *methods;

    /** 保留字段,用于扩展 */
    void *dso;

    /** 保留字段,用于未来使用 */
    uint32_t reserved[32-7];
} hw_module_t;
字段 说明 典型值/作用
tag 魔数标记 必须为 HARDWARE_MODULE_TAG,用于校验结构体有效性
version_major/minor 版本号 标识模块接口版本,如 Camera HAL 1.0 对应 major=1, minor=0
id 模块标识 与 hw_get_module() 的 id 参数匹配
methods 方法表指针 指向 hw_module_methods_t,其中包含 open() 函数

2.3.2 hw_device_t:设备实例描述符

hw_device_t 代表一个已打开的硬件设备实例。通过 hw_module_methods_t::open() 创建,上层服务通过该结构体与硬件交互。

// 位于 hardware/libhardware/include/hardware/hardware.h
typedef struct hw_device_t {
    /** 标签,必须设置为 HARDWARE_DEVICE_TAG */
    uint32_t tag;

    /** 设备版本号 */
    uint32_t version;

    /** 指向所属模块的指针 */
    struct hw_module_t *module;

    /** 保留字段,用于扩展 */
    uint32_t reserved[12];

    /** 关闭设备的方法 */
    int (*close)(struct hw_device_t *device);
} hw_device_t;
注意: hw_device_t 本身是一个“基类”结构体。具体的硬件类型(如 Camera、Audio)会在此基础上扩展,添加自己的操作函数指针。例如,Camera HAL1 的 camera_device_t 在 hw_device_t 之后追加了 ops 字段。

2.4 模块与设备的关系:open/close 生命周期

下图展示了从模块加载到设备打开、使用的完整生命周期:

hw_module_t 与 hw_device_t 生命周期 1. hw_get_module() 2. 获取 hw_module_t 3. module->methods->open() 4. 创建 hw_device_t 5. 使用设备操作 6. device->close() 图:模块加载 → 设备打开 → 设备使用 → 设备关闭的完整流程

2.5 传统HAL的局限性

尽管libhardware架构设计简洁,但随着硬件复杂度提升,其局限性逐渐暴露:

局限性 具体表现 影响
接口僵化 hw_device_t 的扩展依赖厂商自定义,缺乏标准化 不同厂商的同一类型设备(如Camera)接口不统一,Framework适配困难
同步阻塞模型 所有操作默认同步,不支持异步回调或Buffer管理 高吞吐场景(如Camera预览/录像)性能瓶颈明显
无生命周期管理 设备打开/关闭完全由上层控制,缺乏引用计数或状态机 多客户端并发访问时容易产生资源冲突
版本演进困难 修改 hw_module_t 或 hw_device_t 需要所有厂商同步更新 引入新特性(如Camera HAL3)必须设计全新的接口体系
总结: 传统HAL(Legacy HAL)通过 libhardware 实现了基础的硬件抽象,其模块加载机制和 hw_module_t/hw_device_t 结构体奠定了Android HAL的基石。然而,其同步、静态的设计已无法满足现代多媒体硬件的需求,这也直接催生了后续更先进的HAL接口定义(如Camera HAL3、Audio HAL 4.0等)。