Android HAL硬件抽象层--模型理解

来源:互联网 发布:sql数据库培训班 编辑:程序博客网 时间:2024/06/02 22:01

        Android HAL硬件抽象层是运行在linux用户空间中程序。HAL是对设备文件操作的封装与抽象,硬件厂商为了隐藏商业秘密,不用将对硬件的控制写到内核中(写进内核就该公布源代码了),google就将硬件抽象层放到了linux内核用户空间。

        对于系统的把握,个人觉得最好是能将其抽象为一个具体的、简单的模型,只有让这个模型印在心中,学习庞大的系统时,才不会觉得自己在云里雾里。

        基于这个想法,android HAL对我来说就是一个程序框架。抽象的说它有两个目的,对底层驱动功能进行封装,提供接口供上层调用。这样理解也太空洞,所以进一步理解,可以忽略掉底层的封装,因为硬件封装这个过程很容易理解。那么对上层来说,它是这样一个框架:jni层能通过ID号,找到对应的HAL模块(.so动态链接库)并加载,可以导出其中的函数符号以调用。HAL相当于是一个供查询和使用模块的框架,总体上是查询框架,这样理解就很简单。

        每一个HAL模块都有一个ID号,每一个HAL模块都会被编译成后缀为.so的动态链接库。jni层通过HAL中通用的函数hw_get_module(ID, &module),来查询模块、加载模块,并且得到其中的函数符号,这样就实现了Java到C++的调用,原因就是因为.so动态链接库的调用。

      (启示:大型的程序,如果采用系统分层的思想,上层是否也能用这种方法来调用下层呢?有什么好处?效率如何?)

        下面具体分析HAL的工作过程:

        框架如何实现查询(还有加载)

        分析:HAL层和JNI层应该约定好ID号、ID号跟模块有映射关系、HAL协议规定了如何导出模块函数符号

    int hw_get_module( const  char *id, const struct hw_module_t **module);
        该函数是HAL层的公共函数,会被JNI调用,传递ID、和一个module指针。在查找到模块后,load函数加载到内存中:

    status = load(id, path, module);
         load函数打开一个动态链接库,并且跟根据符号 HAL_MODULE_INFO_SYM_AS_STR查找hw_module_t类型的变量,得到其地址:

    handle = dlopen(path, RTLD_NOW);    const  r char *sym = HAL_MODULE_INFO_SYM_AS_STR;    hmi = (struct hw_module_t *)dlsym(handle, sym);
        最后*module = hmi,JNI至此得到了HAL模块的操作接口hw_module_t。使用hw_module_t,JNI就可以尽情享用HAL模块中的功能啦!

        然而这里有一个很Big的疑问:源码里面找不着HAL_MODULE_INFO_SYM_AS_STR呀

        顶多可以发现 

    #define HAL_MODULE_INFO_SYM_AS_STR "HMI"
        而通过模块代码,我们看到的只有

 57 struct hello_module_t HAL_MODULE_INFO_SYM = { 58     common: { 59         tag:HARDWARE_MODULE_TAG, 60         version_major:1, 61         version_minor:0, 62         id:HELLO_HARDWARE_MODULE_ID, 63         name:HELLO_MODULE_NAME, 64         author:HELLO_MODULE_AUTHOR, 65         methods:&hello_module_methods, 66     } 67 };

    继续查看源代码,才发现了真相

    215 #define HAL_MODULE_INFO_SYM         HMI
        原来每个模块的主要结构体都叫HMI,所以才能通过符号HAL_MODULE_INFO_SYM_AS_STR找到它。

        hello_module_t怎么能被强制转化为hw_module_t *? 只能怪C语言没学好,默哀三分钟。

        至此,我们知道了Android HAL通用的入口地址,即HAL_MODULE_INFO_SYM。通过该结构体,我们可以在JNI层访问HAL层模块中,任意我们想要访问的方法啦。


======================================================================================

        后续的研究  

        JNI  ->  hw_get_module(ID, &module_t)   ->  module_t->methods.open(module,ID,*device_t)  ->  device_t->setval(val) 

        1.JNI通过hw_get_module打开模块后,用HMI符号找到了入口hw_module_t

        2.hw_module_t调用其成员变量methods的open方法,动态申请一个hw_device_t

        3.hw_device_t中调用了setval和getval等对驱动功能的抽象函数

        4.还有疑问吗得意

======================================================================================

        因此,底层的封装功能请查看hello_module_t和hello_device_t的成员变量吧

         


    



原创粉丝点击