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启动流程图,来自网络。

Android Image Asset不支持中文_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 Image Asset不支持中文_驱动_02

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 Image Asset不支持中文_linux驱动_03

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模块 

mmm hardware/libhardware/modules/hello

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

参考文章:




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