書名: Android系統(tǒng)級深入開發(fā)作者名: 韓超 梁泉本章字?jǐn)?shù): 2189字更新時間: 2018-12-29 13:39:30
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等。
- Mastering Visual Studio 2017
- LabVIEW 2018 虛擬儀器程序設(shè)計
- 數(shù)字媒體應(yīng)用教程
- JavaScript:Functional Programming for JavaScript Developers
- Twilio Best Practices
- JavaScript+Vue+React全程實例
- 人人都是網(wǎng)站分析師:從分析師的視角理解網(wǎng)站和解讀數(shù)據(jù)
- Hands-On JavaScript for Python Developers
- App Inventor 2 Essentials
- 算法設(shè)計與分析:基于C++編程語言的描述
- JavaScript悟道
- Learning Concurrency in Python
- 大學(xué)計算機應(yīng)用基礎(chǔ)(Windows 7+Office 2010)(IC3)
- 程序員必會的40種算法
- Learning Redux