文章出处: http://blog.sina.com.cn/s/blog_6a8b794001015jx7.html
一、Android系统通过HAL访问linux驱动的过程
1、Native Service通过调用hw_get_module函数获取hw_module_t结构的实例module(获取HAL stub);
2、通过module中hw_module_methods_t结构的实例指针methods获得打开具体设备的HAL的open方法;
3、在HAL的open方法的实现中调用C库的open函数打开linux设备文件(获取文件描述符),进而通过其他的文件操作函数实现对设备的控制(此部分可以看作是linux应用编程,注意Android libc库与glibc的不同);
二、非常重要的三个Android HAL结构
typedef struct hw_module_t {
} hw_module_t;
typedef struct hw_module_methods_t {
const char *id,
struct hw_device_t **device);
} hw_module_methods_t;
typedef struct hw_device_t {
} hw_device_t;
三、HAL stub编程
1、编程思路
(a) 因为Native Service希望获取HAL stub,所以应创建一个hw_module_t实例
(b) 因为hw_module_t实例中需要一个hw_module_methods实例的指针,所以在创建hw_module_t实例前应先声明或者创建一个hw_module_methods_t实例;
(c) 因为hw_module_methods_t实例中需要一个HAL的open方法,所以在创建hw_module_methods_t实例前应先声明一个HAL的open方法(实现放在创建hw_module_t实例后);
(d) 实现HAL的open方法,此方法是非常重要的,负责申请结构空间、填充结构成员信息、注册具体API、打开Linux设备(其实打开方法也是个API);
一般它首先声明一个hw_device_t结构指针、为之分配空间并清空所分配的空间,然后填充hw_device_t结构成员信息,其中需要填充一个hw_module_t实例的指针,这是将open方法先声明后实现的原因;因为hw_device_t结构还需要填充一个HAL的close方法,所以在(c)步骤中添加此方法的声明,与open方法“配对”;
观察open方法的形参我们知道可以通过第二个形参向外输出hw_device_t结构指针,这个指针是在实现JNI方法时声明的,我们可以暂不关心,只需要记住它是给上层提供的接口;
以上两步工作完成后,便可在此方法中调用C库的open方法打开Linux设备文件,获取设备文件描述符(HAL接口Kernel的重要步骤),进而添加或调用其他操作Linux设备的方法——C库的文件操作方法即所谓的具体的API(注意Android C库与glibc的异同);
(e) 实现Linux设备的其他操作方法,并将声明添加到(c)步骤中
2、编程思路拓展
4、一个led的HAL stub编程实例(步骤遵从思路)
// (1)
typedef struct led_module_t {
} led_module_t;
typedef struct led_control_device_t {
} led_control_device_t;
// (2)
int led_device_open(const struct hw_module_t *module,
const char *id,
struct hw_device_t **device);
int led_device_close(struct hw_device_t *device);
struct hw_module_methods_t led_module_methods {
};
const struct led_module_t HAL_MODULE_INFO_SYM {
},
};
int led_device_open(const struct hw_module_t *module,
const char *id,
struct hw_device_t **device)
{
}
……
……
xxx_module_t结构的实例名称必须为HAL_MODULE_INFO_SYM,这是Android的游戏规则,暂不详解;
HAL对上层提供接口是通过输出hw_device_t结构指针实现的,在JNI方法的实现中会将此指针强制转换为自定义的xxx_control_device_t(此例是led_control_device_t)结构指针,实现对xxx_control_device_t的fd及方法成员的访问,因此,hw_device_t必须为xxx_control_device_t自定义结构的第一个成员;
四、补充
Android系统的应用层是JAVA,而其kernel是C,Android系统通过JNI方法实现JAVA对C的调用;
历史原因使Android系统有了HAL,它的角色相当于一个中间人,对上层,它负责给JNI提供调用kernel的方法,对下层,它所提供的方法包含能够访问kernel的函数,即kernel提供给上层的API,如:open、read、write、ioctl等;
下面,我们通过对比Android系统架构和Linux系统架构来增加理解:
Android系统架构(HAL)
Android系统架构(无HAL)
Linux系统架构
1、Linux系统架构
Android是基于Linux的扩展,所以我们先来看一下Linux系统架构;
从软件架构的角度来看,Linux分为user层、kernel层,这两层是C实现的(应用层还可用C++实现);
---------------------------------------------------------------
extern system_call();
operation()
---------------------------------------------------------------
system_call()
{
}
device_operateion()
{
}
---------------------------------------------------------------
---------------------------------------------------------------
2、Android系统架构
从Android系统架构(无HAL)框图可知,Android系统架构比Linux系统架构多了Application、Application Framework两层,这就是android的应用层(JAVA);
Android将Linux的应用层(用户C程序+函数库)添加一个Android Runtime作为其中间层,并将中间层和kernel层统称Android的系统层(C/C++);
HAL所调用的API来自Libraries,真正能和kernel打交道的是API,所以,Android系统架构(HAL)框图并不准确,HAL并非一个独立的具有隔离作用的层,而是从某方面性质上宣称它是一个Layer,其实它相当于Linux系统中的用户C程序组,只是它不仅要完成在Linux系统中用户C程序所要完成的工作,还要向上给JNI提供完成这些工作的接口,实现从JAVA调用C获取kernel系统服务的机制;因此,我个人认为Android系统架构(无HAL)框图更为恰当,HAL的存在只是为了在概念上更好的表述和理解Android系统而已;
Android的整个系统服务调用流程我只从HAL开始往下较为清晰,对JNI方法有初步了解,尚未完全清晰理解,JAVA层则几乎未涉及,此次学习只能暂时到此为止了!
学习资源:
http://blog.csdn.net/k229650014/article/details/5801397
http://www.cnblogs.com/armlinux/archive/2012/01/14/2396768.html