1. Display HAL 初始化流程分析

Display HAL 初始化流程分析 学习卡片

任务说明

本案例以 Android 8.0 及以上版本的 Display HAL 为对象,分析其从动态库加载到设备句柄创建完成的完整初始化链路。目标是通过阅读 AOSP 源码路径(hardware/libhardware 与 hardware/rockchip/display 等厂商实现),梳理 HAL 模块的加载机制、open 调用约定以及 hw_device_t 的创建过程,并最终通过一个最小可复现的 C 程序验证该初始化流程的核心环节。

初始化流程总览

Android Display HAL 的初始化遵循 hw_get_module → module->methods->open → device_create 的三段式结构。上层 SurfaceFlinger 通过 hw_get_module 按模块 ID 查找并加载 HAL 动态库,随后调用模块的 open 方法创建具体的设备实例。设备实例以 hw_device_t 为基类,厂商实现通过结构体嵌套方式扩展出 hwc_device_t(HWC 1.x)或 hwc2_device_t(HWC 2.x)。

Display HAL 初始化时序 SurfaceFlinger HWC2::Device hw_get_module HAL_MODULE_INFO_SYM module->open() hwc2_open hw_device_t hwc2_device_t 1. 按ID加载.so 2. 调用open回调 3. 创建设备实例 关键结构体布局 hw_module_t tag: HARDWARE_MODULE_TAG id: "gralloc"/"hwcomposer" methods: open 函数指针 hw_device_t tag: HARDWARE_DEVICE_TAG module: 指向所属模块 close: 资源释放回调 hwc2_device_t (厂商扩展) hw_device_t common; // 基类 function_table: HWC2 API private_data: 厂商私有数据

核心代码路径分析

以下代码展示 HAL 模块加载与设备创建的最小可复现实现。该程序模拟了 hw_get_module 的查找逻辑,并演示厂商如何通过 open 回调创建 hw_device_t 实例。为保持案例独立可运行,此处使用本地结构体定义替代 AOSP 头文件依赖。

// display_hal_init_demo.c
// 编译: gcc -o display_hal_init_demo display_hal_init_demo.c
// 运行: ./display_hal_init_demo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ---- 模拟 AOSP hardware.h 核心定义 ---- */
#define HARDWARE_MODULE_TAG   0x484D4F44  // 'HMOD'
#define HARDWARE_DEVICE_TAG   0x48444556  // 'HDEV'

struct hw_module_t;
struct hw_device_t;

typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
} hw_module_methods_t;

typedef struct hw_module_t {
    uint32_t tag;
    const char* id;
    const char* name;
    const hw_module_methods_t* methods;
} hw_module_t;

typedef struct hw_device_t {
    uint32_t tag;
    struct hw_module_t* module;
    void (*close)(struct hw_device_t* device);
} hw_device_t;

/* ---- 厂商 Display HAL 实现 ---- */
typedef struct display_device_t {
    struct hw_device_t common;
    int display_count;
    char* vendor_data;
} display_device_t;

static int display_device_close(struct hw_device_t* dev) {
    if (dev) {
        display_device_t* d = (display_device_t*)dev;
        free(d->vendor_data);
        free(d);
        printf("[display HAL] device closed and freed\n");
    }
    return 0;
}

static int display_device_open(const struct hw_module_t* module,
                               const char* id,
                               struct hw_device_t** device) {
    if (strcmp(id, "display") != 0) {
        fprintf(stderr, "unknown device id: %s\n", id);
        return -1;
    }
    
    display_device_t* dev = calloc(1, sizeof(display_device_t));
    if (!dev) return -1;
    
    // 初始化基类 hw_device_t
    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.module = (struct hw_module_t*)module;
    dev->common.close = display_device_close;
    
    // 初始化厂商扩展字段
    dev->display_count = 2;  // 假设双屏
    dev->vendor_data = strdup("rockchip_display_ctx");
    
    *device = &dev->common;
    printf("[display HAL] open() called, id=%s, display_count=%d\n",
           id, dev->display_count);
    return 0;
}

/* ---- 模块定义,对应 AOSP 中的 HAL_MODULE_INFO_SYM ---- */
static struct hw_module_t display_module = {
    .tag = HARDWARE_MODULE_TAG,
    .id = "display",
    .name = "Rockchip Display HAL",
    .methods = &(hw_module_methods_t){ .open = display_device_open },
};

/* ---- 模拟 hw_get_module 的查找与加载 ---- */
// 真实系统中此函数通过 dlopen 加载 /vendor/lib64/hw/display.*.so
// 并查找名为 HAL_MODULE_INFO_SYM 的符号
static int hw_get_module_sim(const char* id, hw_module_t** module) {
    if (strcmp(id, "display") == 0) {
        *module = &display_module;
        printf("[loader] module '%s' found (simulated dlopen)\n", id);
        return 0;
    }
    return -1;
}

int main(void) {
    hw_module_t* mod = NULL;
    hw_device_t* dev = NULL;
    
    // 第一步: 加载模块
    if (hw_get_module_sim("display", &mod) != 0) {
        fprintf(stderr, "failed to load display module\n");
        return 1;
    }
    printf("[main] module loaded: %s (tag=0x%x)\n", mod->name, mod->tag);
    
    // 第二步: 调用 open 创建设备
    if (mod->methods->open(mod, "display", &dev) != 0) {
        fprintf(stderr, "failed to open display device\n");
        return 1;
    }
    
    // 第三步: 验证设备句柄
    if (dev->tag != HARDWARE_DEVICE_TAG) {
        fprintf(stderr, "invalid device tag\n");
        return 1;
    }
    display_device_t* d = (display_device_t*)dev;
    printf("[main] device created: displays=%d, vendor=%s\n",
           d->display_count, d->vendor_data);
    
    // 清理
    dev->close(dev);
    return 0;
}

验证方法与判定标准

执行以下步骤验证初始化流程的正确性:

  1. 将上述代码保存为 display_hal_init_demo.c,运行 gcc -o display_hal_init_demo display_hal_init_demo.c 编译,确认无错误无警告;
  2. 运行 ./display_hal_init_demo,观察输出顺序:应先打印模块加载信息,再打印 open() called,最后打印设备创建信息与关闭信息;
  3. 判定通过标准:程序退出码为 0,且输出中依次出现 module loaded、open() called、device created、device closed 四类关键日志,表明模块加载、open 回调、设备实例化与资源释放的完整闭环已打通。

预期输出(与代码逻辑严格对应):

[loader] module 'display' found (simulated dlopen)
[main] module loaded: Rockchip Display HAL (tag=0x484d4f44)
[display HAL] open() called, id=display, display_count=2
[main] device created: displays=2, vendor=rockchip_display_ctx
[display HAL] device closed and freed

本案例通过模拟 AOSP 的 HAL 加载与 open 机制,完整呈现了 Display HAL 初始化中 hw_module_t 查找、hw_device_t 创建及厂商扩展结构体初始化的核心路径。真实系统中 hw_get_module 的 dlopen 细节与厂商 open 内部的硬件资源申请逻辑,可在本框架基础上按需扩展。