我的Android系统学习笔记——HAL

来源:互联网 发布:sqlserver数据恢复 编辑:程序博客网 时间:2024/05/01 09:26

我的Android系统学习笔记——HAL

by 蓝终恒

 

一、Android系统通过HAL访问linux驱动的过程

 

1、Native Service通过调用hw_get_module函数获取hw_module_t结构的实例module(获取HAL stub);

2、通过modulehw_module_methods_t结构的实例指针methods获得打开具体设备的HALopen方法;

3、HALopen方法的实现中调用C库的open函数打开linux设备文件(获取文件描述符),进而通过其他的文件操作函数实现对设备的控制(此部分可以看作是linux应用编程,注意Android libc库与glibc的不同);

 

二、非常重要的三个Android HAL结构

       Android源码的/hardware/libhardware/include/hardware/hardware.h中定义了三个关键结构体hw_module_thw_module_methods_thw_device_t,具体结构如下:

 

typedef struct hw_module_t {

      

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

 

      

       uint32_t reserved[32 - 7];

hw_module_t;

 

 

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;

 

 

typedef struct hw_device_t {

      

       uint32_t tag;

 

      

       uint32_t version;

 

      

       struct hw_module_t *module;

 

      

       uint32_t reserverd[12];

 

      

       int (*close)(struct hw_device_t *device);

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实例中需要一个HALopen方法,所以在创建hw_module_methods_t实例前应先声明一个HALopen方法(实现放在创建hw_module_t实例后);

(d) 实现HALopen方法,此方法是非常重要的,负责申请结构空间、填充结构成员信息、注册具体API、打开Linux设备(其实打开方法也是个API);

一般它首先声明一个hw_device_t结构指针、为之分配空间并清空所分配的空间,然后填充hw_device_t结构成员信息,其中需要填充一个hw_module_t实例的指针,这是将open方法先声明后实现的原因;因为hw_device_t结构还需要填充一个HALclose方法,所以在(c)步骤中添加此方法的声明,与open方法“配对”;

观察open方法的形参我们知道可以通过第二个形参向外输出hw_device_t结构指针,这个指针是在实现JNI方法时声明的,我们可以暂不关心,只需要记住它是给上层提供的接口;

以上两步工作完成后,便可在此方法中调用C库的open方法打开Linux设备文件,获取设备文件描述符(HAL接口Kernel的重要步骤),进而添加或调用其他操作Linux设备的方法——C库的文件操作方法即所谓的具体的API(注意Android C库与glibc的异同);

(e) 实现Linux设备的其他操作方法,并将声明添加到(c)步骤中

 

2、编程思路拓展

       一般而言,建议在系统底层的编程中也尽量以面向对象的编程思想为指导,所以,我们应该首先将hw_module_thw_device_t结构和其他相关的变量、函数封装起来——自定义HAL结构,然后在以上编程思路的基础上稍作改变;其实,这也是HAL stub编程所要求的!

 

4、一个ledHAL stub编程实例(步骤遵从思路)

// (1)

typedef struct led_module_t {

       struct hw_module_t common;

} led_module_t;

 

typedef struct led_control_device_t {

       struct hw_device_t common;

      

      

       int fd;

       int (*set_on)(struct led_control_device_t *led_dev, int32_t led_n);

       int (*set_off)(struct led_control_device_t *led_dev, int32_t led_n);

} 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 {

       open: led_device_open,

};

 

 

const struct led_module_t HAL_MODULE_INFO_SYM {

       common: {

              tag: HARDWARE_MODULE_TAG,

              version_major: 1,

              version_minor: 0,

              id: LED_HARDWARE_MODULE_ID,

              name: “simple led stub”,

              author: “Lan Zhongheng”,

              methods: &led_module_methods,

},

};

 

 

int led_device_open(const struct hw_module_t *module,

const char *id,

struct hw_device_t **device)

{

       led_control_device_t *led_dev;

       led_dev = (led_control_device_t*)malloc(sizeof(led_control_device_t));

       memset(led_dev, 0, sizeof(led_control_device_t));

 

       led_dev->common.tag = HARDWARE_DEVICE_TAG;

       led_dev->common.version = 0;

       led_dev->common.module = module;

       led_dev->common.close = led_device_close;

      

      

       led_dev->set_on = led_on;

       led_dev->set_off = led_off;

 

       led_dev->fd = open(LED_DEVICE, O_RDWR);

       if (led_dev->fd < 0)

              return -1;

 

       *device = &(led_dev->common);

 

      

       //led_off(led_dev, LED1);

       //led_on(led_dev, LED2);

 

       return 0;

}

 

 

……

……

 

       编程时需要我们注意的地方以橙色和红色标识,它们是HAL能够工作的关键;
xxx_module_t结构的实例名称必须为HAL_MODULE_INFO_SYM,这是Android的游戏规则,暂不详解; 

HAL对上层提供接口是通过输出hw_device_t结构指针实现的,在JNI方法的实现中会将此指针强制转换为自定义的xxx_control_device_t(此例是led_control_device_t)结构指针,实现对xxx_control_device_tfd及方法成员的访问,因此,hw_device_t必须为xxx_control_device_t自定义结构的第一个成员;

 

 

四、补充

 

Android系统的应用层是JAVA,而其kernelCAndroid系统通过JNI方法实现JAVAC的调用;

历史原因使Android系统有了HAL,它的角色相当于一个中间人,对上层,它负责给JNI提供调用kernel的方法,对下层,它所提供的方法包含能够访问kernel的函数,即kernel提供给上层的API,如:openreadwriteioctl等;

下面,我们通过对比Android系统架构和Linux系统架构来增加理解:

 我的Android系统学习笔记——HAL

 

Android系统架构(HAL

 我的Android系统学习笔记——HAL

 

Android系统架构(无HAL)

 我的Android系统学习笔记——HAL

 

Linux系统架构

 

       补充一下基础概念:所谓的API函数,被包含在用户层的函数库中,APIkernel是产生系统调用,对用户程序是提供产生系统调用的方法;所谓的接口,是对外公开声明的函数、变量,即汇编语言中所说的标号或符号,外部程序通过接口可以引用某些自己不具备的服务

 

1、Linux系统架构

Android是基于Linux的扩展,所以我们先来看一下Linux系统架构;

从软件架构的角度来看,Linux分为user层、kernel层,这两层是C实现的(应用层还可用C++实现);

       从系统服务流程的角度来看,Linux有调用服务的user层、执行系统调用的服务层、支持系统调用的内核函数(服务模块);

       所以,在Linux系统中访问设备的流程为:用户层程序直接产生系统调用(系统开发人员)或者通过API函数间接产生系统调用陷入kernel层,在kernel层找到用户程序所需的服务,这里说的是访问设备,则找的是device driver,通过device driver最终实现对硬件设备的访问;

       以代码示意整个流程:

---------------------------------------------------------------

      

       main()

       {

              operation();

}     

 

extern system_call();
operation()

       {

              system_call();

}                                            user

---------------------------------------------------------------

                                                  kernel     

 

system_call()

{

        datatype (*system_service)();

        system_service = find_sys_service();

        system_service();

}

 

 

device_operateion()    // this is one of system service module functions(methods)

{

       

}

---------------------------------------------------------------

               device                         硬件层

---------------------------------------------------------------

 

2、Android系统架构

Android系统架构(无HAL)框图可知,Android系统架构比Linux系统架构多了ApplicationApplication Framework两层,这就是android的应用层(JAVA);

AndroidLinux的应用层(用户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

0 0
原创粉丝点击