当前位置: 代码迷 >> Android >> android系统硬件抽象层(HAL)原理及兑现之原理
  详细解决方案

android系统硬件抽象层(HAL)原理及兑现之原理

热度:16   发布时间:2016-05-01 10:44:41.0
android系统硬件抽象层(HAL)原理及实现之原理

Android系统硬件抽象层(HAL)原理

android开发过程中,我们经常看到HAL这个概念,这就android的硬件抽象层的(Hardwaere Abstraction Layer)缩写,它是Goolge应某些厂商不希望公开源码所添加的一个适配层,能以封闭源码的方式提供硬件驱动模块,目的就是把android framework层和linux kernel层隔离开来,使android系统不至于过度的依赖linux kernel层的实现,也就是说android framework可以不考虑linux kernel如何实现的情况下独立开发

??????Android HAL层位于android系统和linuxkernel之间,如下图所示:

?

?

?

?

Android java应用层(app

?

Android java框架层(framework

?

?

?

Android本地框架层(native

?

?

硬件抽象层(HAL

?

硬件抽象层实现

?

驱动层(linuxkernel

在移植系统或添加新的模块时都需要androidHAL层进行修改或者添加实现,androidHAL层在android的源码位置:

hardware/libhardware/

hardware/libhardware_legacy/

hardware/xxxx/

有的还位与其他位置。AndroidHAL层的实现方式有几种方式:

1,hardware模块的方式

2,C/C++继承方式

3,直接调用驱动接口方式

4,直接接口方式

下面我从这几种方式作一下简单的分析

?

《一》首先分析一下hardware模块方式的实现,这种方式是一种不依赖编译时绑定的实现,它可以动态的加载硬件抽象层就是说可以通过ID来动态的打开(dlopen)一个硬件模块,然后找到符号(dlsym)进行调用。

?

Android native framework-(根据不同的ID)àlibhardware.so-(dlopen)->/system/hw/*.so->drivers

?

接下来分析一下HAL这个抽象的框架,具体的代码在源码的

hardware/libhardware/hardware.c

hardware/libhardware/include/hardware/hardware.h位置

来看看hardware.h这个头文件,我们可以发现在这个头文件中主要定义的三个结构体

?

struct hw_device_t

struct hw_module_t

struct hw_module_methods_t

hw_device_t:表示硬件设备,存储了各种硬件设备的公共属性和方法,如果需要移植或者添加新硬件,那么都需要使用该结构进行注册,其中的tag必须初始化。结构体hw_module_t在进行加载的时候用于判断属于哪个module

typedef struct hw_device_t {
uint32_t tag;?//tag
需要被初始化为HARDWARE_DEV

uint32_t version;?//hw_device_t的版本号

struct hw_module_t* module;?//引用这个设备属于的硬件模块

uint32_t reserved[12];?//填充保留字节

int (*close)(struct hw_device_t* device);?//关闭设备

} hw_device_t;

typedef struct hw_module_t {
???????
?uint32_t tag;?//tag需要被初始化为HARDWARE_MODULE_TAG

uint16_t version_major;?//主版本号

uint16_t version_minor;?//次版本号

const char *id;?//模块标识符

const char *name;?//模块名称

const char *author;?//模块作者

struct hw_module_methods_t* methods;?//模块方法

void* dso;??//模块的dso

uint32_t reserved[32-7];?//填充字节,为以后使用

} hw_module_t;?

hw_module_methods_t:该结构体用于定义操作设备的各种方法operations,这里只定义一个open方法。如果要执行打开设备等操作可以在JNI层使用“module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t** )device);”

typedef struct hw_module_methods_t {
??????? ??? int (*open)(const struct hw_module_t* module, const char* id,struct hw_device_t** device);?//
打开设备的方法

} hw_module_methods_t;

?

其中struct hw_device_t表示一个硬件设备

Struct hw_module_t表示硬件模块的格式

Sttruct hw_module_methods_t表示模块的方法

(三个结构体可以看到hw_device_t包含hw_module_t, hw_module_t保含hw_module_methods_t,这是面向对象的思想的体现,呵呵呵)

在加载某个模块的时候会调用hw_get_module这个方法,这个方法就可以获得相应的HAL,代码如下所示:

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];

??? /*
???? * Here we rely on the fact that calling dlopen multiple times on
???? * the same .so will simply increment a refcount (and not load
???? * a new copy of the library).
???? * We also assume that dlopen() is thread-safe.
???? */

??? /* Loop through the configuration variants looking for a module */
??? for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
??????? if (i < HAL_VARIANT_KEYS_COUNT) {
?????//
获取ro.hardware/ro.product.board/ro.board.platform/ro.archkey的值。
?????? 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",
??????????????????? HAL_LIBRARY_PATH, id);
??????? }
??????? if (access(path, R_OK)) {
??????????? continue;
??????? }
??????? /* we found a library matching this id/variant */
??????? break;
??? }

??? status = -ENOENT;
??? if (i < HAL_VARIANT_KEYS_COUNT+1) {
??????? /* load the module, if this fails, we're doomed, and we should not try
???????? * to load a different variant. */
??????? status = load(id, path, module);//
调用load()函数打开动态链接库
??? }

??? return status;
}

?

在该方法中可以看出,android系统通过系统的属性查找硬件,根据ID和找到的路径加载相应的.so库文件在hw_get_module中有一个重要的方法

Load

static int load(const char *id,const char *path,const struct hw_module_t **pHmi)
{
??? int status;
??? void *handle;
??? struct hw_module_t *hmi;

/*
???? * load the symbols resolving undefined symbols before
???? * dlopen returns. Since RTLD_GLOBAL is not or'd in with
???? * RTLD_NOW the external symbols will not be global
???? */
??? handle = dlopen(path, RTLD_NOW);//
打开动态库
??? if (handle == NULL) {
??????? char const *err_str = dlerror();
??????? LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
??????? status = -EINVAL;
??????? goto done;
??? }

??? /* 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”这个导出符号,并获取其地址
??? if (hmi == NULL) {
??????? LOGE("load: couldn't find symbol %s", sym);
??????? status = -EINVAL;
??????? goto done;
??? }

?/* Check that the id matches */
??? if (strcmp(id, hmi->id) != 0) {
??????? LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
??????? status = -EINVAL;
??????? goto done;
??? }

??? hmi->dso = handle;

??? /* success */
??? status = 0;

??? done:
??? if (status != 0) {
??????? hmi = NULL;
??????? if (handle != NULL) {
??????????? dlclose(handle);
??????????? handle = NULL;
??????? }
??? } else {
??????? LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
??????????????? id, path, *pHmi, handle);
??? }

??? *pHmi = hmi;

??? return status;
}

从上可以简单得出硬件的具体调用过程,大致是这样的

首先通过ID找到硬件模块

然后硬件模块得到methods打开设备(hw_device_t

再后调用设备的各个方法

最后使用完毕后通过设备的close方法关闭

?

《二》C/C++继承方式

这种方式最典型的有CAMERAAUDIO两个系统,这种方式是在android系统中定义了C++接口如camera中的CameraHardwareInterface.h,其中定义了操作camera的各个方法,这些方法有具体的实现者来实现,一般情况下硬件抽象层会被编译成动态或静态库,由本地框架调用或链接,具体在camera中分析

后两种方式在分析具体模块时再做具体分析

?

HAL层的原理就简单介绍到这里,接下来我会详细分析不同的具体的模块的实现

  相关解决方案