linux中的硬件抽象层

来源:互联网 发布:免费刷超级会员软件 编辑:程序博客网 时间:2024/05/01 16:07


Android系统从宏观上可以看成一个图形系统,类似于QT,迷你GUI等开源的图形用户界面系统。但是android作为手机软件包,它还具有很多的其他功能是QT、MINIGUI不具备的,比如电话、定位、WIFI、sensor、摄像头等功能。Android集成了很多开源的代码,我们只需要在Linux层做好硬件的驱动程序剩下的很多软件开发工作android都是做好了的。烧写过手机固件的都知道,android的固件大概有uboot.img、boot.img(包含ramdisk和kernel),system.img,cache.img,userdata.img等。下面是一张android启动流程图,来自网络。


其中system.img可以理解为android的本体部分。

System.img最终会挂在ramdisk的/system目录下面,其内容说明如下:

system/app     这个里面主要存放的是常规下载的应用程序,可以看到都是以APK格式结尾的文件。在这个文件夹下的程序为系统默认的组件,自己安装的软件将不会出现在这里,而是/data/文件夹中。

       system/bin       这个目录下的文件都是系统的本地程序,从bin文件夹名称可以看出是binary二进制的程序,里面主要是Linux系统自带的组件。

system/etc       从文件夹名称来看保存的都是系统的配置文件,比如APN接入点设置等核心配置。

        system/fonts   字体文件夹,除了标准字体和粗体、斜体外可以看到文件体积最大的可能是中文字库,或一些unicode字库。

        system/framework  主要是一些核心的文件,从后缀名为jar可以看出是是系统平台框架。

        system/lib       lib目录中存放的主要是系统底层库,如hardware层库。

        system/media  铃声音乐文件夹,除了常规的铃声外还有一些系统提示事件音

       system/usr      用户文件夹,包含共享、键盘布局、时间区域文件等。 

现在android编译的结果呈现在上面,从功能逻辑上android的结构是这样的:


Android的一些库的运行是依赖硬件的,但是为了让android与Linux隔离开,硬件抽象层扮演了和驱动层打交道的角色,也扮演了BSP开发应用层部分的工作。有了hardware和kernel的配合,android才能稳定的运行在目标板上。

在"/system/lib/hw"下面定义了硬件抽象层编译的动态库文件。动态库文件可以理解为厨师的各类厨具,需要就颠一下,不需要就放在那儿。那么hardware层的库文件是怎么为其他库提供支持的呢?比如android的APP应用程序现在要把一幅图显示到LCD上,就需要硬件驱动的支持,APP会通过控件调用framework层的libui库,libui库根据ID号选调hardware层的动态库"/system/lib/hw/gralloc.*.so",然后硬件抽象层再继续调用驱动层的接口/dev/fb0。

Tips:

framework层调用函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中检查是否存在以下四个文件:

      gralloc.<ro.hardware>.so

      gralloc.<ro.product.board>.so

      gralloc.<ro.board.platform>.so

      gralloc.<ro.arch>.so
    只要其中的一个文件存在,  函数hw_get_module就会停止查找过程,并且调用另外一个函数load来将这个文件加载到内存中来。另一方面,如果在/system/lib/hw和/vendor/lib/hw中均不存这些文件,那么函数hw_get_module就会在目录/system/lib/hw中查找是否存在一个名称为gralloc.default.so的文件。

硬件抽象层调用关系(架构图):


Android硬件抽象层规定了一个框架,集中体现在某个模块的头文件的实现。以hardware\libhardware\include\hardware\gralloc.h为例(精简版):

/**

 * The id of this module

 */

#define GRALLOC_HARDWARE_MODULE_ID"gralloc"

 

/**

 * Name of the graphics device to open

 */

#defineGRALLOC_HARDWARE_FB0 "fb0"

#defineGRALLOC_HARDWARE_GPU0 "gpu0"

/**

 * Every hardware module must have a datastructure named HAL_MODULE_INFO_SYM

 * and the fields of this data structure mustbegin with hw_module_t

 * followed by module specific information.

 */

typedef struct gralloc_module_t {

   struct hw_module_t common;

     int (*registerBuffer)(structgralloc_module_t const* module,

            buffer_handle_t handle);

int(*unregisterBuffer)(struct gralloc_module_t const* module,

            buffer_handle_t handle);

int(*lock)(struct gralloc_module_t const* module,

            buffer_handle_t handle, int usage,

            int l, int t, int w, int h,

            void** vaddr);

int(*unlock)(struct gralloc_module_t const* module,

           buffer_handle_t handle);

    /* reserved for future use */

    int (*perform)(struct gralloc_module_tconst* module,

            int operation, ... );

 

    /* reserved for future use */

    void* reserved_proc[7];

}gralloc_module_t;

/**

 * Every device data structure must begin withhw_device_t

 * followed by module specific public methodsand attributes.

 */

typedef struct framebuffer_device_t {

   struct hw_device_t common;

 

    /* flags describing some attributes of theframebuffer */

    const uint32_t  flags;

   

    /* dimensions of the framebuffer in pixels*/

    const uint32_t  width;

    const uint32_t  height;

 

    /* frambuffer stride in pixels */

    const int       stride;

    /* framebuffer pixel format */

    const int      format;

    /* resolution of the framebuffer's displaypanel in pixel per inch*/

    const float     xdpi;

    const float     ydpi;

    /* framebuffer's display panel refresh ratein frames per second */

    const float     fps;

    /* min swap interval supported by thisframebuffer */

    const int       minSwapInterval;

    /* max swap interval supported by thisframebuffer */

    const int       maxSwapInterval;

 

    int reserved[8];

        int (*setSwapInterval)(structframebuffer_device_t* window,

            int interval);

    int (*setUpdateRect)(structframebuffer_device_t* window,

            int left, int top, int width, intheight);

    int (*post)(struct framebuffer_device_t*dev, buffer_handle_t buffer);

    int (*compositionComplete)(structframebuffer_device_t* dev);

    void* reserved_proc[8];

}framebuffer_device_t;

1、     每一个hardware硬件模块都有一个ID;

2、     每一个hardware模块必须有一个继承struct hw_module_t common;的结构体;

3、     每一个hardware模块必须有一个继承struct hw_device_t common;的结构体;

structhw_module_t的继承者担负了“联络员”的任务,在/system/lib/hw下面有若干了hardware module,本地框架层通过ID找到对应的模块。

structhw_device_t的继承者承担了对驱动操作方法的包装的任务。

structhw_module_t和struct hw_device_t的内容定义在hardware\libhardware\include\hardware\hardware.h如下:

/**

 * Every hardware module must have a datastructure named HAL_MODULE_INFO_SYM

 * and the fields of this data structure mustbegin with hw_module_t

 * followed by module specific information.

 */

typedef struct hw_module_t {

    /** tag must be initialized toHARDWARE_MODULE_TAG */

    uint32_t tag;

 

    /** major version number for the module */

    uint16_t version_major;

 

    /** minor version number of the module */

    uint16_t version_minor;

 

    /** Identifier of module */

    const char *id;

 

    /** Name of this module */

    const char *name;

 

    /** Author/owner/implementor of the module*/

    const char *author;

 

    /** Modules methods */

    struct hw_module_methods_t*methods;

 

    /** module's dso */

    void* dso;

 

    /** padding to 128 bytes, reserved forfuture use */

    uint32_t reserved[32-7];

 

}hw_module_t;

 

typedef struct hw_module_methods_t {

    /** Open a specific device */

    int (*open)(const struct hw_module_t* module,const char* id,

            struct hw_device_t** device);

 

}hw_module_methods_t;

 

/**

 * Every device data structure must begin withhw_device_t

 * followed by module specific public methodsand attributes.

 */

typedef struct hw_device_t {

    /** tag must be initialized toHARDWARE_DEVICE_TAG */

    uint32_t tag;

 

    /** version number for hw_device_t */

    uint32_t version;

 

    /** reference to the module this devicebelongs to */

    struct hw_module_t* module;

 

    /** padding reserved for future use */

    uint32_t reserved[12];

 

    /** Close this device */

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

 

}hw_device_t;

 

到此我们总结一下硬件具体的调用流程,也是hardware层的工作流程:

1、        通过ID找到硬件模块,structhw_module_t common的结构体的继承者;

2、        通过硬件模块找到hw_module_methods_t,打开操作,获得设备的hw_device_t;

3、        调用hw_device_t中的各种操作硬件的方法;

4、        调用完成,通过hw_device_t的close关闭设备。

下面是一个hardware层的helloworld的例子,目的是了解其原理,也为阅读androidHAL源码提供一个范本。

进入到在hardware/libhardware/include/hardware目录,新建hello.h文件:

#ifndefANDROID_HELLO_INTERFACE_H

#defineANDROID_HELLO_INTERFACE_H

#include<hardware/hardware.h>

 

__BEGIN_DECLS

 

/*定义模块ID*/

#defineHELLO_HARDWARE_MODULE_ID "hello"

 

/*硬件模块结构体*/

structhello_module_t {

         struct hw_module_t common;

};

 

/*硬件接口结构体*/

structhello_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

进入到hardware/libhardware/modules目录,新建hello目录,并添加hello.c文件

#defineLOG_TAG "HelloStub"

 

#include<hardware/hardware.h>

#include<hardware/hello.h>

#include<fcntl.h>

#include<errno.h>

#include<cutils/log.h>

#include<cutils/atomic.h>

 

/*驱动程序接口/dev/hello*/

#defineDEVICE_NAME "/dev/hello"

#defineMODULE_NAME "Hello"

 

/*设备打开和关闭接口*/

staticint hello_device_open(const struct hw_module_t* module, const char* name,struct hw_device_t** device);

staticint hello_device_close(struct hw_device_t* device);

 

/*设备访问接口*/

staticint hello_set_val(struct hello_device_t* dev, int val);

staticint hello_get_val(struct hello_device_t* dev, int* val);

 

/*模块方法表*/

staticstruct hw_module_methods_t hello_module_methods = {

         open: hello_device_open

};

 

/*模块实例变量*/

structhello_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: “mr shao”,

                   methods:&hello_module_methods,

         }

};

static int hello_device_open(const structhw_module_t* module, const char* name, struct hw_device_t** device) {

         structhello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(structhello_device_t));

        

         if(!dev){

                   LOGE("HelloStub: 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("HelloStub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);

                   return-EFAULT;

         }

 

         *device= &(dev->common);

         LOGI("HelloStub: open /dev/hello successfully.");

 

         return0;

}

static int hello_device_close(structhw_device_t* device) {

         structhello_device_t* hello_device = (struct hello_device_t*)device;

 

         if(hello_device){

                   close(hello_device->fd);

                   free(hello_device);

         }

        

         return0;

}

 

static int hello_set_val(structhello_device_t* dev, int val) {

         LOGI("HelloStub: set value %d to device.", val);

 

         write(dev->fd,&val, sizeof(val));

 

         return0;

}

 

static int hello_get_val(structhello_device_t* dev, int* val) {

         if(!val){

                   LOGE("HelloStub: error val pointer");

                   return-EFAULT;

         }

 

         read(dev->fd,val, sizeof(*val));

 

         LOGI("HelloStub: get value %d from device", *val);

 

         return0;

}

继续在hello目录下新建Android.mk文件:

 LOCAL_PATH := $(call my-dir)

      include$(CLEAR_VARS)

     LOCAL_MODULE_TAGS := optional

     LOCAL_PRELINK_MODULE := false

      LOCAL_MODULE_PATH:= $(TARGET_OUT_SHARED_LIBRARIES)/hw

     LOCAL_SHARED_LIBRARIES := liblog

      LOCAL_SRC_FILES:= hello.c

      LOCAL_MODULE :=hello.default

      include$(BUILD_SHARED_LIBRARY)

 注意,LOCAL_MODULE的定义规则,hello后面跟有default,hello.default能够保证我们的模块总能被硬象抽象层加载到。关于Android.mk的用法请参考:

例说如何编译android模块 http://blog.csdn.net/eliot_shao/article/details/50441219

mmm hardware/libhardware/modules/hello

      编译成功后,就可以在out/target/product/generic/system/lib/hw目录下看到hello.default.so文件了。

参考文章:

http://blog.csdn.net/luoshengyang/article/details/6573809

http://blog.csdn.net/eliot_shao/article/details/50441219

http://blog.csdn.net/luoshengyang/article/details/7747932

《Android板级支持与硬件相关子系统》韩超 第二章

 

0 0