1 HAL產生的原因
Android HAL(Hardware Abstraction Libraries)是處於user space的最下層,是Android定義的要求Linux內核空間來具體實現的驅動接口。根據Google的說法,使用user-space HAL的原因爲:
1 Not all components have standardizedkernel driver interface
2 Kernel driver are GPL which exposes anyproprietary IP
3 Android has specific requirements forhardware drivers
但這其中最重要的原因爲第二個,把控制硬件的動作都放到了user space中,在kernel driver裏面只有最簡單的讀寫寄存器的操作。Android user space的代碼就可以不必受到GPL的束縛而封裝成庫,避免了暴露硬件廠商使用的硬件型號。
2 HAL的重要性
HAL的重要性主要表現在兩個方面:
1 從學習的角度看,HAL通常是Linux內核開發者想學習整個Android系統架構時選擇的突破口,這是由於HAL所處在整個系統架構的位置決定的;同樣Android user-space的開發者,想要從APP和中間件進一步深入貫通到內核,HAL也是必經之路。如果把Kernel比作關內,Android user-space比作關外,HAL就是進出關的唯一通道,兵家必爭之地。
2 從使用的頻度來看,隨着對SOC性能要求的進一步提高,越來越多的模塊將使用硬件加速,甚至以前使用DSP來加速的一些模塊,由於性能和功耗的要求,都改用硬件實現,特別是多媒體相關的領域,GPU也幾乎成了最近2年出來的SOC的標配,Android也集成了方便使用硬件加速的標準OpenMAX, OpenGL等。
3 HAL的2種模式
3.1 直接調用(舊的模式)
1 源碼路徑:\hardware\libhardware_legacy
2 模式簡介:libhardware_legacy是將 *.so 文件當作shared library來使用,JNI以 direct function call 使用 HAL module。通過直接函數調用的方式,來操作驅動程序。
3 實例:PowerManager
JNI層:android_os_Power.cpp(frameworks\base\core\jni)
- static void
- acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)
- {
- if (idObj == NULL) {
- throw_NullPointerException(env, "id is null");
- return ;
- }
- const char *id = env->GetStringUTFChars(idObj, NULL);
- acquire_wake_lock(lock, id);
- env->ReleaseStringUTFChars(idObj, id);
- }
HAL層:Power.c(hardware\libhardware_legacy\power)
- int
- acquire_wake_lock(int lock, const char* id)
- {
- initialize_fds();
- // LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);
- if (g_error) return g_error;
- int fd;
- if (lock == PARTIAL_WAKE_LOCK) {
- fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
- }
- else {
- return EINVAL;
- }
- return write(fd, id, strlen(id));
- }
3.2 通過回調函數調用並統一接口(新的模式)
1 源碼路徑:\hardware\libhardware
2 模式簡介:hardware.c和hardware.h(hardware\libhardware\include\hardware)提供了使用這種模式的HAL的方式,並規定統一接口。上層通過hardware.c中的函數hw_get_module獲取相應module的stub,然後通過stub來訪問HAL。
3 接口源碼hardware.c和hardware.h說明
(1)Hardware.h用2個結構體規定了統一接口
- /**
- * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
- * and the fields of this data structure must begin with hw_module_t
- * followed by module specific information.
- */
- 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;
由註釋可知,每個HAL模塊都必須繼承這個結構體,繼承方式爲,定義一個結構體,其第一個元素爲hw_module_t,之後是表徵自己模塊獨有的信息的變量。
- /**
- * Every device data structure must begin with hw_device_t
- * followed by module specific public methods and attributes.
- */
- 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;
由註釋可知,每個HAL模塊必須繼承這個結構體,繼承方式類似地,定義一個結構體,其第一個元素爲hw_device_t,之後是自己模塊獨有的方法和屬性。
(2)hardware.c使用hw_get_module函數,通過id查找並加載相應HAL模塊,並獲得相應模塊的Stub。相關的解釋見這篇文章http://my.unix-center.net/~Simon_fu/?p=630。
4 實例:overlay
Service層:DisplayHardware.cpp(frameworks\base\services\surfaceflinger\displayhardware)
- void DisplayHardware::init(uint32_t dpy)
- {
- mNativeWindow = new FramebufferNativeWindow();
- framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
- mDpiX = mNativeWindow->xdpi;
- mDpiY = mNativeWindow->ydpi;
- mRefreshRate = fbDev->fps;
- mOverlayEngine = NULL;
- hw_module_t const* module;
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- overlay_control_open(module, &mOverlayEngine);
- }
- ....
- }
HAL層:Overlay.h(hardware\libhardware\include\hardware)
- /**
- * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
- * and the fields of this data structure must begin with hw_module_t
- * followed by module specific information.
- */
- struct overlay_module_t {
- struct hw_module_t common;
- };
- /**
- * Every device data structure must begin with hw_device_t
- * followed by module specific public methods and attributes.
- */
- struct overlay_control_device_t {
- struct hw_device_t common;
- /* get static informations about the capabilities of the overlay engine */
- int (*get)(struct overlay_control_device_t *dev, int name);
- /* creates an overlay matching the given parameters as closely as possible.
- * returns an error if no more overlays are available. The actual
- * size and format is returned in overlay_t. */
- overlay_t* (*createOverlay)(struct overlay_control_device_t *dev,
- uint32_t w, uint32_t h, int32_t format);
- /* destroys an overlay. This call releases all
- * resources associated with overlay_t and make it invalid */
- void (*destroyOverlay)(struct overlay_control_device_t *dev,
- overlay_t* overlay);
- /* set position and scaling of the given overlay as closely as possible.
- * if scaling cannot be performed, overlay must be centered. */
- int (*setPosition)(struct overlay_control_device_t *dev,
- overlay_t* overlay,
- int x, int y, uint32_t w, uint32_t h);
- /* returns the actual position and size of the overlay */
- int (*getPosition)(struct overlay_control_device_t *dev,
- overlay_t* overlay,
- int* x, int* y, uint32_t* w, uint32_t* h);
- /* sets configurable parameters for this overlay. returns an error if not
- * supported. */
- int (*setParameter)(struct overlay_control_device_t *dev,
- overlay_t* overlay, int param, int value);
- int (*stage)(struct overlay_control_device_t *dev, overlay_t* overlay);
- int (*commit)(struct overlay_control_device_t *dev, overlay_t* overlay);
- };
Overlay.cpp (hardware\libhardware\modules\overlay)
- static int overlay_device_open(const struct hw_module_t* module, const char* name,
- struct hw_device_t** device);
- static struct hw_module_methods_t overlay_module_methods = {
- open: overlay_device_open
- };
- struct overlay_module_t HAL_MODULE_INFO_SYM = {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: OVERLAY_HARDWARE_MODULE_ID,
- name: "Sample Overlay module",
- author: "The Android Open Source Project",
- methods: &overlay_module_methods,
- }
- };
4 後記
在理解HAL的時候,2種模式的區別萬不可糾結於上層是用JNI調用,manager調用,還是用service調用,mokoid在這方面也許會造成一些誤導。其關鍵爲:舊的模式爲直接調用,新的模式爲通過hw_get_module獲取到相應HAL模塊的stub,以回調的方式進行調用。
5 Reference
http://android.tgbus.com/Android/tutorial/201104/350065.shtml