Android HAL層,即硬件抽象層,是Google響應廠家“希望不公開源碼”的要求推出的新概念
1,源代碼和目標位置
源代碼: /hardware/libhardware目錄,該目錄的目錄結構如下:
/hardware/libhardware/hardware.c編譯成libhardware.so,目標位置爲/system/lib目錄
/hardware/libhardware/include/hardware目錄下包含如下頭文件:
hardware.h 通用硬件模塊頭文件
copybit.h copybit模塊頭文件
gralloc.h gralloc模塊頭文件
lights.h 背光模塊頭文件
overlay.h overlay模塊頭文件
qemud.h qemud模塊頭文件
sensors.h 傳感器模塊頭文件
/hardware/libhardware/modules目錄下定義了很多硬件模塊
這些硬件模塊都編譯成xxx.xxx.so,目標位置爲/system/lib/hw目錄
2,HAL層的實現方式
JNI->通用硬件模塊->硬件模塊->內核驅動接口
具體一點:JNI->libhardware.so->xxx.xxx.so->kernel
具體來說:android frameworks中JNI調用/hardware/libhardware/hardware.c中定義的hw_get_module函數來獲取硬件模塊,
然後調用硬件模塊中的方法,硬件模塊中的方法直接調用內核接口完成相關功能
3,通用硬件模塊(libhardware.so)
(1)頭文件爲:/hardware/libhardware/include/hardware/hardware.h
頭文件中主要定義了通用硬件模塊結構體hw_module_t,聲明瞭JNI調用的接口函數hw_get_module
hw_module_t定義如下:
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
/** major version number for the module */
uint16_t version_major;
/** minor version number of the module */
uint16_t version_minor;
/** Identifier of module */
const char *id;
/** Name of this module */
const char *name;
/** Author/owner/implementor of the module */
const char *author;
/** Modules methods */
struct hw_module_methods_t* methods; //硬件模塊的方法
/** module's dso */
void* dso;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
硬件模塊方法結構體hw_module_methods_t定義如下:
typedef struct hw_module_methods_t {
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
只定義了一個open方法,其中調用的設備結構體參數hw_device_t定義如下:
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
hw_get_module函數聲明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
參數id爲模塊標識,定義在/hardware/libhardware/include/hardware目錄下的硬件模塊頭文件中,
參數module是硬件模塊地址,定義了/hardware/libhardware/include/hardware/hardware.h中
(2)hardware.c中主要是定義了hw_get_module函數如下:
#define HAL_LIBRARY_PATH "/system/lib/hw"
static const char *variant_keys[] = {
"ro.hardware",
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[0]));
int hw_get_module(const char *id, const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++)
{
if (i < HAL_VARIANT_KEYS_COUNT)
{
if (property_get(variant_keys[i], prop, NULL) == 0)
{
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH, id, prop);
}
else
{
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH, id);
}
if (access(path, R_OK))
{
continue;
}
/* we found a library matching this id/variant */
break;
}
status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+1) {
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
status = load(id, path, module);
}
return status;
}
從源代碼我們可以看出,hw_get_module完成的主要工作是根據模塊id尋找硬件模塊動態連接庫地址,然後調用load函數去打開動態連接庫
並從動態鏈接庫中獲取硬件模塊結構體地址。硬件模塊路徑格式如下:
HAL_LIBRARY_PATH/id.prop.so
HAL_LIBRARY_PATH定義爲/system/lib/hw
id是hw_get_module函數的第一個參數所傳入,prop部分首先按照variant_keys數組中的名稱逐一調用property_get獲取對應的系統屬性,
然後訪問HAL_LIBRARY_PATH/id.prop.so,如果找到能訪問的就結束,否則就訪問HAL_LIBRARY_PATH/id.default.so
舉例如下:
假定訪問的是背光模塊,id定義爲"lights"則系統會按照如下的順序去訪問文件:
/system/lib/hw/lights.[ro.hardware屬性值].so
/system/lib/hw/lights.[ro.product.board屬性值].so
/system/lib/hw/lights.[ro.board.platform屬性值].so
/system/lib/hw/lights.[ro.arch屬性值].so
/system/lib/hw/lights.default.so
所以開發硬件模塊的時候Makefile文件(Android.mk)中模塊的命名LOCAL_MODULE要參考上面的內容,否則就會訪問不到沒作用了。
load函數的關鍵部分代碼如下:
handle = dlopen(path, RTLD_NOW); //打開動態鏈接庫
if (handle == NULL) {
char const *err_str = dlerror();
LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym); //從動態鏈接庫中獲取硬件模塊結構體的指針
if (hmi == NULL) {
LOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
HAL_MODULE_INFO_SYM_AS_STR是硬件模塊在動態鏈接庫中的標誌,定義在hardware.h中如下:
#define HAL_MODULE_INFO_SYM HMI
#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
4,硬件模塊
硬件模塊的開發主要是完成/hardware/libhardware/include/hardware目錄下對應的頭文件中的內容,主要是硬件模塊頭文件和hardware.h中
的結構體中定義了一些函數指針,調用內核提供的接口將具體的函數實現,然後編譯成指定名稱的動態鏈接庫放到/system/lib/hw目錄下即可。
用一句話來概括:硬件模塊的開發就是定義一個hardware.h中定義的hw_module_t結構體,結構體名稱爲宏HAL_MODULE_INFO_SYM,然後實現結構體
的相關內容即可。
5,內核驅動
主要是要向用戶層開放接口,讓硬件模塊和內核可以交互。
HAL開發基礎
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.