Android硬件抽象層模塊編寫規(guī)范

硬件抽象層模塊編寫規(guī)范

硬件抽象層最終都會生成.so文件,放到系統(tǒng)對應的目錄中。在系統(tǒng)使用的時候,系統(tǒng)會去對應目錄下加載so文件,實現(xiàn)硬件抽象層的功能。因此硬件抽象層的加載過程就是我們使用so的一個接口。先了解加載過程從源頭了解抽象層模塊兒的編寫規(guī)范。

1、硬件抽象層加載過程

系統(tǒng)在加載so的過程中,會去兩個目錄下查找對應id的so文件。這兩個目錄分別是/system/lib/hw和/vendor/lib/hw。

so文件的名字分為兩個部分例如id.prop.so,第一部分是模塊id。第二部分是系統(tǒng)prop的值,獲取順序為“ro.hardware”、“ro.producat.board”、“ro.board.platform”、“ro.arch”,如果prop都找不到的話,就用default。(不是找不到prop的值,是找不到prop值對應的so文件)。

負責加載硬件抽象層模塊的函數(shù)是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文件之后,調(diào)用方法load方法去加載對應的so文件,并返回hw_module_t結構體。load方法源碼在上面程序中。

load方法首先調(diào)用dlopen加載對應的so文件到內(nèi)存中。然后用dlsym方法找到變量HAL_MODULE_INFO_SYM_AS_STR符號對應的地址,這個地址也就是一個hw_module_t結構體,然后從這個結構體中拿出id比對load方法出入的id是否一致,如果是的話表示打開成功。加載過程完成。

HAL_MODULE_INFO_SYM_AS_STR這個符號值為HMI,也就是必須要保證這個符號之后是一個hw_module_t。接下來的規(guī)范中有這個要求。

到此,模塊加載完成

2、硬件抽象層模塊編寫規(guī)范

硬件抽象層有兩個結構體,一個是hw_module_t和hw_device_t,定義在hardware.h中。

首先說一下hw_module_t的編寫規(guī)范。

1、必須要有一個“自定義硬件抽象層結構體”,且結構體第一個變量類型要為hw_module_t。

2、必須存在一個HARDWARE_MODULE_INFO_TAG的符號,且指向“自定義硬件抽象層結構體”。在加載的時候根據(jù)這個符號找到地址,并把地址的轉(zhuǎn)變?yōu)閔w_module_t,這也是為什么第一條中hw_module_t必須要在第一個的原因。

3、hw_module_t的tag必須為HARDWARE_MODULE_TAG

4、結構體中要有一個方法列表,其中要有一個open方法。用open方法獲得hw_device_t

接下來說一下hw_device_t的編寫規(guī)范

1、必須要有一個“自定義硬件設備結構體”,且結構體第一個變量類型要為hw_device_t。

2、hw_device_t的tag必須為HARDWARE_DEVICE_TAG

3、要有一個close函數(shù)指針,來關閉設備

按照上面規(guī)范編寫的硬件抽象層就可以由系統(tǒng)加載并正確獲取到device。具體的應用層邏輯在device中實現(xiàn)。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容