Agenda:
首先做一个简单的概述:
Android 为什么要有HAL层?为什么不能将这层接口写在内核空间中?
我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。那么假如把HAL层和内核层整合在一起,就必须公开,这样就会损害厂家的利益,因为功能上的逻辑可是代表着这个公司的核心技术。所以就有了HAL层,这一层主要是功能上的逻辑实现,运行在用户空间。
下面是与硬件抽象层相关的各个层的关系:
首先在驱动上对硬件直接进行操作,但是这些操作都是最基本的,例如读写寄存器等等。而在HAL层是程序员为了实现一个特定功能,设计编写具体的操作逻辑。在HAL层是c代码,JNI层通过封装HAL层的接口为上层提供接口。
HAL 层具体介绍:
在/hardware/libhardware/include/hardware$ vi hello.h
这里面的代码为:
#ifndef ANDROID_HELLO_INTERFACE_H #define ANDROID_HELLO_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS /*定义模块ID*/ #define HELLO_HARDWARE_MODULE_ID "hello" /*硬件模块结构体*/ struct hello_module_t { struct hw_module_t common; }; /*硬件接口结构体*/ struct hello_device_t { struct hw_device_t common; int fd; int (*set_val)(struct hello_device_t* dev, int val); int (*get_val)(struct hello_device_t* dev, int* val); }; __END_DECLS #endif
首先介绍代码结构:HAL层代码一般放在hardware/libhardware中,这里我们假设内核中有个hello.so驱动模块,相应的在HAL层定义hal层模块为hello.default.so。
hello.h 里面按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。
进入到hardware/libhardware/modules目录,新建hello目录,并添加hello.c文件。 hello.c的内容较多,我们分段来看。
首先是包含相关头文件和定义相关结构:
#define LOG_TAG "HelloStub" #include <hardware/hardware.h> #include <hardware/hello.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #define DEVICE_NAME "/dev/hello" #define MODULE_NAME "Hello" #define MODULE_AUTHOR "shyluo@gmail.com" /*设备打开和关闭接口*/ static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device); static int hello_device_close(struct hw_device_t* device); /*设备访问接口*/ static int hello_set_val(struct hello_device_t* dev, int val); static int hello_get_val(struct hello_device_t* dev, int* val); /*模块方法表*/ static struct hw_module_methods_t hello_module_methods = { open: hello_device_open }; /*模块实例变量*/ struct hello_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: HELLO_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &hello_module_methods, } };
static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { struct hello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t)); if(!dev) { LOGE("Hello Stub: failed to alloc space"); return -EFAULT; } memset(dev, 0, sizeof(struct hello_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (hw_module_t*)module; dev->common.close = hello_device_close; dev->set_val = hello_set_val;dev->get_val = hello_get_val; if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev); return -EFAULT; } *device = &(dev->common); LOGI("Hello Stub: open /dev/hello successfully."); return 0; }