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
http://my.unix-center.net/~Simon_fu/?p=630