AIDL for HAL in Android11+


以IR这个模块为例
实现部分: aosp\hardware\libhardware\modules\consumerir
这部分最后生成动态库,供接口调用
接口部分:aosp\hardware\interfaces\ir
这部分最后生成服务,供上层应用调用

先看实现部分,这部分以c实现,接近传统的Linux编程
首先是一系列的实现函数,然后用两个结构体串联起来,以供后续使用
第一个结构体是struct hw_module_methods_t

static struct hw_module_methods_t consumerir_module_methods = {
    .open = consumerir_open,
};

这个结构体是用来初始化这个模块的,open函数会打开这个模块并初始化,然后返回这个模块的指针,上层拿到这个指针就可以工作了

另外一个是consumerir_module_t

consumerir_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag                = HARDWARE_MODULE_TAG,
        .module_api_version = CONSUMERIR_MODULE_API_VERSION_1_0,
        .hal_api_version    = HARDWARE_HAL_API_VERSION,
        .id                 = CONSUMERIR_HARDWARE_MODULE_ID,
        .name               = "Demo IR HAL",
        .author             = "The Android Open Source Project",
        .methods            = &consumerir_module_methods,
    },
};

HAL_MODULE_INFO_SYM是一个宏定义,具体作用是用来定位模块入口的,当这个动态库被打开之后,就可以用dlsym来定位这个宏定义的地址,从而确定这个模块的入口地址
CONSUMERIR_HARDWARE_MODULE_ID是这个模块的ID,系统通过这个ID来匹配是不是目标模块

再看接口部分,这部分以cpp为主
首先是aidl文件,这部分定义了上层可以访问的一些接口、结构体变量之类的
然后是cpp文件,这部分是接口服务的主体部分

ConsumerIr::ConsumerIr() {
    const hw_module_t *hw_module = NULL;

    int ret = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &hw_module);
    if (ret != 0) {
        ALOGE("hw_get_module %s failed: %d", CONSUMERIR_HARDWARE_MODULE_ID, ret);
        return;
    }
    ret = hw_module->methods->open(hw_module, CONSUMERIR_TRANSMITTER, (hw_device_t **) &mDevice);
    if (ret < 0) {
        // note - may want to make this a fatal error - otherwise the service will crash when it's used
        ALOGE("Can't open consumer IR transmitter, error: %d", ret);
        // in case it's modified
        mDevice = nullptr;
    }
}

在上面的构造函数里,通过hw_get_module这个函数来打开目标模块,传递的CONSUMERIR_HARDWARE_MODULE_ID正是上面定义的ID,这里对应上了
然后接下来的open就是上面实现的open,这样就可以拿到目标指针了,之后就可以正常访问这个模块了

hw_get_module在aosp\hardware\libhardware\hardware.c定义,实际上是调用hw_module_exists来寻找目标模块的
目标模块的命名和存放位置必须符合HAL的规则,当找到符合规则的模块之后,进入用load函数开始加载
首先要用dlopen打开,然后用dlsym定位模块的入口,这个入口在上面用HAL_MODULE_INFO_SYM定义

/* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
if (hmi == NULL) {
    ALOGE("load: couldn't find symbol %s", sym);
    status = -EINVAL;
    goto done;
}
· Written by Link