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层的原理就简单介绍到这里,接下来我会详细分析不同的具体的模块的实现

更多相关文章

  1. Android播放视频的三种方式示例
  2. android 网络请求+json解析 最优分析
  3. 3G调试笔记之发送AT命令和APN配置
  4. android HAL知识
  5. android adb push 与 adb install 区别(两种安装APK的方法)
  6. Android文件系统保护——dmverity
  7. android ListView 中getview学习总结
  8. Android(安卓)之使用ContentProvider(内容提供者)共享数据
  9. Android(安卓)在TextView 中显示图片的4种方式

随机推荐

  1. 谷歌宣布关闭Google TV,由Android(安卓)TV
  2. Android(安卓)腾讯入门教程( 智能手表UI
  3. android 定时器(Handler Timer Thread Al
  4. 我见过的最好的DataBinding解析
  5. Android基础入门教程——7.5.1 WebView(
  6. 移动开发:Android升级ADT22后会报ClassNo
  7. AndroidManifest拾遗
  8. 从Google Analytics看国内Android开发人
  9. Android(安卓)异步更新UI的几种方式
  10. Android常用的几个命令