官术网_书友最值得收藏!

3.2.2 硬件抽象層接口方式

1.hardware模塊的方式

Android的libhardware庫提供一種不依賴編譯時綁定,可以動態(tài)加載硬件抽象層,硬件模塊方式的硬件抽象層架構(gòu)如圖3-7所示。

圖3-7 硬件模塊方式的硬件抽象層

在libhardware的接口中定義了通用的內(nèi)容和各個硬件模塊的id,每一個硬件模塊需要被實現(xiàn)成所要求的接口形式,并生成單獨的動態(tài)庫文件(*.so)。

在使用硬件抽象層的過程中,Android系統(tǒng)的框架層將調(diào)用libhardware的接口,根據(jù)每一個模塊的id,將在指定路徑動態(tài)打開(dlopen)各個硬件模塊,然后找到符號(dlsym),調(diào)用硬件模塊中的各個接口。

接口的調(diào)用方式是一致的,只是在不同系統(tǒng)所打開的硬件模塊是不相同的。

Android仿真器的環(huán)境中,包含的硬件模塊如下所示:

    # ls /system/lib/hw
    sensors.goldfish.so
    gralloc.default.so

其中,gralloc.default.so表示默認(rèn)的Gralloc模塊(用于顯示),sensors.goldfish.so表示默認(rèn)的傳感器模塊。

libhardware的接口在以下目錄中定義:

    hardware/libhardware/include/hardware/hardware.h

struct hw_module_t結(jié)構(gòu)體用于定義了硬件模塊的格式,如下所示:

    typedef struct hw_module_t {
        uint32_t tag;                       /* tag,需要被初始化為HARDWARE_MODULE_TAG */
        uint16_t version_major;           /* 主版本號 */
        uint16_t version_minor;           /* 次版本號*/
        const char *id;                    /* 模塊標(biāo)識 */
        const char *name;                  /* 模塊的名稱 */
        const char *author;                /* 模塊作者 */
        struct hw_module_methods_t* methods;      /* 模塊方法 */
        void* dso;                                     /* 模塊的dso */
        uint32_t reserved[32-7];                    /* 填充字節(jié),為以后使用 */
    } hw_module_t;

struct hw_module_t結(jié)構(gòu)體定義了一個硬件模塊的信息。在各個具體硬件模塊中,需要以這個結(jié)構(gòu)體為第一個成員,即表示“繼承”了這個結(jié)構(gòu)體。

struct hw_module_methods_t是一個表示模塊方法的結(jié)構(gòu)體,如下所示:

    typedef struct hw_module_methods_t {
        /** 打開設(shè)備的方法 */
        int (*open)(const struct hw_module_t* module, const char* id,
              struct hw_device_t** device);
    } hw_module_methods_t;

struct hw_module_methods_t結(jié)構(gòu)體只包含了一個打開模塊的函數(shù)指針,這個結(jié)構(gòu)體也作為struct hw_module_t結(jié)構(gòu)體的一個成員。

struct hw_device_t表示一個硬件設(shè)備,如下所示

    typedef struct hw_device_t {
        uint32_t tag;                       /* tag 需要被初始化為HARDWARE_DEVICE_TAG */
        uint32_t version;                  /* hw_device_t的版本號 */
        struct hw_module_t* module;                      /* 引用這個設(shè)備屬于的硬件模塊 */
        uint32_t reserved[12];                            /* 填充保留字節(jié) */
        int (*close)(struct hw_device_t* device);     /* 關(guān)閉設(shè)備 */
    } hw_device_t;

struct hw_device_t也是需要被具體實現(xiàn)的結(jié)構(gòu)體包含使用的,一個硬件模塊可以包含多個硬件設(shè)備。

硬件的具體的調(diào)用流程如下所示:

(1)通過id得到硬件模塊。

(2)從硬件模塊中得到hw_module_methods_t,打開得到硬件設(shè)備hw_device_t。

(3)調(diào)用hw_device_t中的各個方法(不同模塊所實現(xiàn)的)。

(4)調(diào)用方程,通過hw_device_t的close關(guān)閉設(shè)備。

模塊打開到使用的流程,如圖3-8所示。

圖3-8 硬件模塊方式的調(diào)用方式

在以上的流程中,還需要libhareware提供一個得到模塊的函數(shù),各個函數(shù)就是hw_get_module,如下所示:

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

hw_get_module()函數(shù)的實現(xiàn)在hardware/libhardware/目錄的hardware.c文件中,其內(nèi)容如下所示:

    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",     // 得到默認(rèn)模塊的名稱
                      HAL_LIBRARY_PATH, id);
            }
            if (access(path, R_OK)) {
              continue;
            }
            break;                                                           // 找到模塊,然后退出
        }
        status = -ENOENT;
        if (i < HAL_VARIANT_KEYS_COUNT+1) {
            status = load(id, path, module);
        }
        return status;
    }

hw_get_module()函數(shù)的內(nèi)容可見,執(zhí)行的是一個動態(tài)查找的過程,找到硬件動態(tài)庫(*.so)打開,當(dāng)沒有動態(tài)庫的時候,將打開默認(rèn)的庫文件(*.default.so)。

在hw_get_module()函數(shù)中調(diào)用的load()函數(shù),其主要內(nèi)容如下所示:

    static int load(const char *id,
            const char *path,
            const struct hw_module_t **pHmi)
    {
        int status;
        void *handle;
        struct hw_module_t *hmi;
        handle = dlopen(path, RTLD_NOW);       /* 進行動態(tài)庫的打開 */
        const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
        hmi = (struct hw_module_t *)dlsym(handle, sym);
        /*  ……省略部分內(nèi)容 */
    }

load()函數(shù)實際上執(zhí)行了一個動態(tài)的打開(dlopen)和動態(tài)取出符號(dlsym)的過程。這個過程解除了在編譯階段的Android本地框架對特有的硬件模塊依賴。

硬件模塊的調(diào)用方式如下所示:

    xxx_module_t * gModule;
    xxx_device_t * gDevice;
    {
        xxx_module_t const* module;
        err = hw_get_module(XXXX_HARDWARE_MODULE_ID, (const hw_module_t **)&module);
        if (err == 0)
            gModule = (xxxx_module_t*)module;
        gModule->ModuleFunction();          /* 調(diào)用模塊中的函數(shù) */
        gDevice->DeviceFunction();          /* 調(diào)用設(shè)備中的函數(shù) */
    }

通常情況下,硬件模塊的調(diào)用者是Android中的本地框架層。

libhardware的接口頭文件中,除了hardware.h之外,其他各個頭文件是相互并列的,每一個文件表示了一種硬件抽象層。

lights.h(背光和指示燈模塊)

copybit.h(位復(fù)制模塊)

overlay.h(疊加視頻抽象層模塊)

qemud.h(QEMU的守護進程模塊)

sensors.h(傳感器模塊)

gralloc.h(gralloc模塊,用于顯示,Eclair版本新增)

2.直接接口方式

hardware_legacy庫中提供了一些各自獨立的接口,由用戶實現(xiàn)后形成庫,被直接連接到系統(tǒng)中。這是實現(xiàn)硬件抽象層最簡單也是最直接的方式。hardware_legacy的頭文件路徑為:

hardware/libhardware_legacy/include/hardware_legacy

Android中的藍(lán)牙庫bluedroid與之類似,也是采用同樣的方式,其頭文件的路徑為:

system/bluetooth/bluedroid/include/bluedroid/bluetooth.h

hardware_legacy庫中包含了幾個C接口的文件,如GPS ,power,wifi,vibrator等,同時在hardware_legacy庫中也包含了power,wifi,vibrator這幾個系統(tǒng)的實現(xiàn)和GPS在仿真器上的實現(xiàn)。在開發(fā)一個新的硬件系統(tǒng)時,可以根據(jù)需要去實現(xiàn)這幾個庫,也可以使用系統(tǒng)默認(rèn)的實現(xiàn)方式。

這種做法實際上并沒有完全將硬件抽象層和Android的本地框架分開,其好處是接口的定義和實現(xiàn)比較簡單。

3.C++的繼承實現(xiàn)方式

使用C++類的繼承方式實現(xiàn)硬件抽象層,也是Android中的一種方式。為了使用這種方式,Android平臺定義了C++的接口。由具體的實現(xiàn)者繼承實現(xiàn)這些接口,同時在Android系統(tǒng)中,通常也有通用的實現(xiàn)方式,可以作為一個簡易的實現(xiàn)或者“樁(stub)”的作用。

使用C++類的繼承方式的硬件抽象層結(jié)構(gòu)如圖3-9所示。

圖3-9 使用C++類的繼承方式的硬件抽象層結(jié)構(gòu)

在這種實現(xiàn)方式中,具體的硬件抽象層通常要求被編譯成為指定的名稱的動態(tài)庫,由本地框架庫連接它;通用的實現(xiàn)被編譯成靜態(tài)庫(*.a),本地框架庫連接這些靜態(tài)庫的時候,其實就是包含了它們在其中。使用特定硬件抽象層還是通用的硬件抽象層,通常需要根據(jù)宏來指定。

Camera和Audio系統(tǒng)使用的是C++類的繼承的方式。

4.直接調(diào)用驅(qū)動

在Android中有一些比較簡單的子系統(tǒng),并沒有在“物理”上存在的硬件抽象層,也就是說,實現(xiàn)其硬件抽象功能的部分不在單獨的代碼中。例如,由JNI部分代碼直接調(diào)用的驅(qū)動程序的設(shè)備節(jié)點或者使用sys文件系統(tǒng)。

Alarm子系統(tǒng)就是采用的這種方式,在JNI中直接調(diào)用驅(qū)動程序。此外,在Android的JNI代碼中,還包含一些對sys文件系統(tǒng)的訪問,例如switch等。

主站蜘蛛池模板: 安顺市| 新田县| 静安区| 界首市| 虎林市| 青阳县| 石狮市| 曲麻莱县| 海林市| 前郭尔| 邵东县| 兴仁县| 宜兰市| 辽阳县| 龙江县| 泰宁县| 百色市| 黑水县| 莎车县| 镇平县| 高邑县| 深州市| 岳普湖县| 江口县| 遵义市| 普兰店市| 丰台区| 鄄城县| 汶上县| 柳州市| 盐池县| 淮北市| 遂川县| 夏河县| 黄陵县| 沭阳县| 阿合奇县| 景东| 富阳市| 甘孜| 水富县|