当前位置: 首页>编程语言>正文

Android硬件抽象层模块编写规范

硬件抽象层模块编写规范

硬件抽象层最终都会生成.so文件,放到系统对应的目录中。在系统使用的时候,系统会去对应目录下加载so文件,实现硬件抽象层的功能。因此硬件抽象层的加载过程就是我们使用so的一个接口。先了解加载过程从源头了解抽象层模块儿的编写规范。

1、硬件抽象层加载过程

系统在加载so的过程中,会去两个目录下查找对应id的so文件。这两个目录分别是/system/lib/hw和/vendor/lib/hw。

so文件的名字分为两个部分例如id.prop.so,第一部分是模块id。第二部分是系统prop的值,获取顺序为“ro.hardware”、“ro.producat.board”、“ro.board.platform”、“ro.arch”,如果prop都找不到的话,就用default。(不是找不到prop的值,是找不到prop值对应的so文件)。

负责加载硬件抽象层模块的函数是hw_get_module,所在的文件是/hardware/libhardware/hardware.c如下:

/** Base path of the hal modules */

#if defined(__LP64__)

#define HAL_LIBRARY_PATH1 "/system/lib64/hw"

#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"

#else

#define HAL_LIBRARY_PATH1 "/system/lib/hw"

#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"

#endif

/**

 * There are a set of variant filename for modules. The form of the filename

* is ".variant.so" so for the led module the Dream variants 

 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:

 *

 * led.trout.so

 * led.msm7k.so

 * led.ARMV6.so

 * led.default.so

 */

static const char *variant_keys[] = {

    "ro.hardware",  /* This goes first so that it can pick up a different

                       file on the emulator. */

    "ro.product.board",

    "ro.board.platform",

    "ro.arch"

};

static const int HAL_VARIANT_KEYS_COUNT =

    (sizeof(variant_keys)/sizeof(variant_keys[0]));

/**

 * Load the file defined by the variant and if successful

 * return the dlopen handle and the hmi.

 * @return 0 = success, !0 = failure.

 */

static int load(const char *id,

        const char *path,

        const struct hw_module_t **pHmi)

{

    int status;

    void *handle;

    struct hw_module_t *hmi;

    /*

     * load the symbols resolving undefined symbols before

     * dlopen returns. Since RTLD_GLOBAL is not or'd in with

     * RTLD_NOW the external symbols will not be global

     */

    handle = dlopen(path, RTLD_NOW);

    if (handle == NULL) {

        char const *err_str = dlerror();

        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");

        status = -EINVAL;

        goto done;

    }

    /* 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;

    }

    /* Check that the id matches */

    if (strcmp(id, hmi->id) != 0) {

        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);

        status = -EINVAL;

        goto done;

    }

    hmi->dso = handle;

    /* success */

    status = 0;

    done:

    if (status != 0) {

        hmi = NULL;

        if (handle != NULL) {

            dlclose(handle);

            handle = NULL;

        }

    } else {

        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",

                id, path, *pHmi, handle);

    }

    *pHmi = hmi;

    return status;

}

/*

 * Check if a HAL with given name and subname exists, if so return 0, otherwise

 * otherwise return negative.  On success path will contain the path to the HAL.

 */

static int hw_module_exists(char *path, size_t path_len, const char *name,

                            const char *subname)

{

    snprintf(path, path_len, "%s/%s.%s.so",

             HAL_LIBRARY_PATH2, name, subname);

    if (access(path, R_OK) == 0)

        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",

             HAL_LIBRARY_PATH1, name, subname);

    if (access(path, R_OK) == 0)

        return 0;

    return -ENOENT;

}

int hw_get_module_by_class(const char *class_id, const char *inst,

                           const struct hw_module_t **module)

{

    int i;

    char prop[PATH_MAX];

    char path[PATH_MAX];

    char name[PATH_MAX];

    char prop_name[PATH_MAX];

    if (inst)

        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);

    else

        strlcpy(name, class_id, PATH_MAX);

    /*

     * Here we rely on the fact that calling dlopen multiple times on

     * the same .so will simply increment a refcount (and not load

     * a new copy of the library).

     * We also assume that dlopen() is thread-safe.

     */

    /* First try a property specific to the class and possibly instance */

    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);

    if (property_get(prop_name, prop, NULL) > 0) {

        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {

            goto found;

        }

    }

    /* Loop through the configuration variants looking for a module */

    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {

        if (property_get(variant_keys[i], prop, NULL) == 0) {

            continue;

        }

        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {

            goto found;

        }

    }

    /* Nothing found, try the default */

    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {

        goto found;

    }

    return -ENOENT;

found:

    /* load the module, if this fails, we're doomed, and we should not try

     * to load a different variant. */

    return load(class_id, path, module);

}

int hw_get_module(const char *id, const struct hw_module_t **module)

{

    return hw_get_module_by_class(id, NULL, module);

}

找到so文件之后,调用方法load方法去加载对应的so文件,并返回hw_module_t结构体。load方法源码在上面程序中。

load方法首先调用dlopen加载对应的so文件到内存中。然后用dlsym方法找到变量HAL_MODULE_INFO_SYM_AS_STR符号对应的地址,这个地址也就是一个hw_module_t结构体,然后从这个结构体中拿出id比对load方法出入的id是否一致,如果是的话表示打开成功。加载过程完成。

HAL_MODULE_INFO_SYM_AS_STR这个符号值为HMI,也就是必须要保证这个符号之后是一个hw_module_t。接下来的规范中有这个要求。

到此,模块加载完成

2、硬件抽象层模块编写规范

硬件抽象层有两个结构体,一个是hw_module_t和hw_device_t,定义在hardware.h中。

首先说一下hw_module_t的编写规范。

1、必须要有一个“自定义硬件抽象层结构体”,且结构体第一个变量类型要为hw_module_t。

2、必须存在一个HARDWARE_MODULE_INFO_TAG的符号,且指向“自定义硬件抽象层结构体”。在加载的时候根据这个符号找到地址,并把地址的转变为hw_module_t,这也是为什么第一条中hw_module_t必须要在第一个的原因。

3、hw_module_t的tag必须为HARDWARE_MODULE_TAG

4、结构体中要有一个方法列表,其中要有一个open方法。用open方法获得hw_device_t

接下来说一下hw_device_t的编写规范

1、必须要有一个“自定义硬件设备结构体”,且结构体第一个变量类型要为hw_device_t。

2、hw_device_t的tag必须为HARDWARE_DEVICE_TAG

3、要有一个close函数指针,来关闭设备

按照上面规范编写的硬件抽象层就可以由系统加载并正确获取到device。具体的应用层逻辑在device中实现。


https://www.xamrdz.com/lan/5sx2016152.html

相关文章: