1. 程式人生 > >HAL層開發

HAL層開發

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,核心驅動
主要是要向用戶層開放介面,讓硬體模組和核心可以互動。