前言
Android HAL是Hardware Abstract Layer的缩写,顾名思义,就是硬件抽象层的意思,为什么要搞这么个东西呢,大概是以下原因吧:
- 软件设计的角度
抽象层概念是很多软件在设计时都采用的一种设计方法,可以达到抽象和隔离上下层的目的,这样子下层实现变化时,上层逻辑不用改动,这种设计方法在很多开源软件上都可以看到,比如Linux内核的vfs、minigui的gal和ial、ffmpeg、opengl等。 - 版权方面
Android基于Linux内核实现,Linux是GPL许可,即对源码的修改都必须开源,而Android是ASL许可,即可以随意使用源码,无需开源,因此将原本应该位于Linux内核的硬件驱动逻辑转移到Android平台来,就可以不必开源,从而保护了厂家的利益。因此Android就提供了一套访问硬件抽象层动态库的接口,各厂商在Android的硬件抽象层实现特定硬件的操作细节,并编译成so库,以库的形式提供给用户使用。
Android HAL支持以下模块:
module和device概念
Android HAL定义了两个概念,一个概念是module,即代表上图中的一个模块,表示一个so库,在程序中用hw_module_t表示;一个概念是device,代表module内一个抽象的设备,可以有多个,不一定要对应实际的硬件,在程序中用hw_device_t表示。以上两个结构体只定义通用的接口,每个具体的模块会继承定义本模块自己的接口。以gralloc图像buffer管理模块为例,相关结构体定义如下:
可见gralloc定义了一个private_module_t类型的module,定义了一个framebuffer_device_t类型和一个alloc_device_t类型的两个device。
HAL调用流程
上层应用按如下方式调用HAL接口:
- 调用hw_get_module获取module信息,之后就可以强转成特定模块定义的接口然后调用。hw_get_module先加载id指定模块对应的so库,然后加载符号地址(变量地址),最后将相关信息保存到module中返回,如果是gralloc模块,返回的module就是一个private_module_t类型变量。hw_get_module定义如下:
int hw_get_module(const char *id, const struct hw_module_t **module)
关键代码如下:
#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
struct hw_module_t *hmi = NULL;
handle = dlopen(path, RTLD_NOW);
/* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
hmi->dso = handle;
其中path根据平台配置和指定的id拼接出来的,最后的路径类似这样子的:
/system/lib64/hw/gralloc.msm8952.so
- 调用模块的open方法获取指定的device信息,之后就可以强转成特定设备定义的接口然后调用。open接口是由具体模块实现的,定义如下:
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
open函数的实现是根据设备id加载指定的device信息,这个加载一般是分配一个对应的device结构体变量,然后填充相关的函数指针等信息,最后将该结构体返回。如果是gralloc模块,返回的device就是一个framebuffer_device_t或者alloc_device_t变量了。
HAL调用示例
以下是GraphicBufferAllocator和GraphicBufferMapper调用gralloc模块的示例代码。
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
gralloc_open(module, &mAllocDev);
}
static inline int gralloc_open(const struct hw_module_t* module,
struct alloc_device_t** device) {
return module->methods->open(module,
GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device);
}
status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
uint32_t* stride)
{
err = mAllocDev->alloc(mAllocDev, static_cast(width),
static_cast(height), format, static_cast(usage), handle,
&outStride);
return err;
}
GraphicBufferMapper::GraphicBufferMapper()
: mAllocMod(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
mAllocMod = reinterpret_cast(module);
}
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
{
err = mAllocMod->registerBuffer(mAllocMod, handle);
return err;
}