HAL层开发框架介绍

Android HAL层即硬件抽象层是Google响应厂家“希望不公开源码”的要求推出的概念
1,源代码和目标位置
源代码: /hardware/libhardware目录,该目录的目录结构如下:
/hardware/libhardware/hardware.c编译成libhardware.so,目标位置为/system/lib目录

Android.mk中lib文件默认使用LOCAL_MODULE_PATH是等于TARGET_OUT_SHARED_LIBRARIES的。
/hardware/libhardware/include/hardware目录下包含如下头文件:
hardware.h 通用硬件模块头文件hw_module_t和hw_get_module_by_class的定义
copybit.h copybit模块头文件
gralloc.h gralloc模块头文件
lights.h  背光模块头文件
overlay.h overlay模块头文件
qemud.h  qemud模块头文件
sensors.h 传感器模块头文件
/hardware/libhardware/modules目录下定义了很多硬件模块
这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录

2,HAL层的实现方式
JNI->通用硬件模块->硬件模块->内核驱动接口
具体一点:JNI->libhardware.so->xxx.xxx.so->kernel
具体来说:android frameworks中JNI调用/hardware/libhardware/hardware.c中定义的hw_get_module函数来获取硬件模块,

然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能

3,通用硬件模块(libhardware.so)
(1)头文件为:
/hardware/libhardware/include/hardware/hardware.h
头文件中主要定义了通用硬件模块结构体hw_module_t,声明了JNI调用的接口函数
hw_get_module
hw_module_t定义如下:

typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_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 for future use */
    uint32_t reserved[32-7];

} hw_module_t;
硬件模块方法结构体hw_module_methods_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;
只定义了一个open方法,其中调用的设备结构体参数hw_device_t定义如下:
typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;

    /** version number for hw_device_t */
    uint32_t version;

    /** reference to the module this device belongs 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;
hw_get_module
函数声明如下:
int hw_get_module(const char *id, const struct hw_module_t **module);
参数id为模块标识,定义在/hardware/libhardware/include/hardware目录下的硬件模块头文件中,
参数module是硬件模块地址,定义了/hardware/libhardware/include/hardware/hardware.h中

(2)hardware.c中主要是定义了hw_get_module函数和hw_get_module_by_class函数。Load函数3个函数的实现。
从源代码我们可以看出,hw_get_module完成的主要工作是根据模块id寻找硬件模块动态连接库地址,然后调用load函数去打开动态连接库
并从动态链接库中获取硬件模块结构体地址。硬件模块路径格式如下:
HAL_LIBRARY_PATH/id.prop.so
HAL_LIBRARY_PATH
定义为/system/lib/hw
id是hw_get_module函数的第一个参数所传入,prop部分首先按照variant_keys数组中的名称逐一调用property_get获取对应的系统属性,

然后访问HAL_LIBRARY_PATH/id.prop.so,如果找到能访问的就结束,否则就访问HAL_LIBRARY_PATH/id.default.so
举例如下:

假定访问的是camera模块,id定义为"camera"则系统会按照如下的顺序去访问文件:
/system/lib/hw/ camera.[ro.hardware属性值].so[ro.hardware]: [nufront-ns115-stick]
/system/lib/hw/ camera.[ro.product.board属性值
].so[ro.product.board]: []
/system/lib/hw/ camera.[ro.board.platform属性值
].so[ro.board.platform]: [ns115]
/system/lib/hw/ camera.[ro.arch属性值
].so so[ro. arch]: []
/system/lib/hw/ camera.default.so

系统中实际有的文件是最后一个/system/lib/hw/ gralloc.default.so
所以开发硬件模块的时候Makefile文件(Android.mk)中模块的命名LOCAL_MODULE要参考上面的内容,否则就会访问不到没作用了。
CAMERA_HARDWARE_MODULE_ID是hw_get_module函数的关键参数。
4,硬件模块
硬件模块的开发主要是完成/hardware/libhardware/include/hardware目录下对应的头文件中的内容,主要是硬件模块头文件和hardware.h中
的结构体中定义了一些函数指针,调用内核提供的接口将具体的函数实现,然后编译成指定名称的动态链接库放到/system/lib/hw目录下即可。
用一句话来概括:硬件模块的开发就是定义一个hardware.h中定义的hw_module_t结构体,结构体名称为宏HAL_MODULE_INFO_SYM,然后实现结构体
的相关内容即可。
5,内核驱动
主要是要向用户层开放接口,让硬件模块和内核可以交互。

6,HAL编译方法

应该是全部编译。

Camera HAL module执行过程分析

1.  其初始化过程如下:
system.loadlibrary(“camera_runtime”)->JNI_load()->register_android_hardware_Camera-> AndroidRuntime::registerNativeMethods

2.   

System.loadLibrary("led_runtime")->JNI_OnLoad()->registerMethods()-> ->env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0]))

 Mediaserver-> onFirstRef 中使用下面的代码load camera的so文件到内存中。 

 if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,

                (const hw_module_t **)&mModule) < 0) {

        LOGE("Could not load camera HAL module");

        mNumberOfCameras = 0;

    }

在这里可以调用直接initWalle初始化camera的HAL层。

或者在是cameraserver的connect函数中初始化。

上面两者都是使用下面的代码调用HAL的。module->methods->open

static hw_module_methods_t camera_module_methods = {

            open : HAL_camera_device_open

};

extern "C" {

    struct camera_module HAL_MODULE_INFO_SYM = {

      common : {

          tag           : HARDWARE_MODULE_TAG,

          version_major : 1,

          version_minor : 0,

          id            : CAMERA_HARDWARE_MODULE_ID,

          name          : "NS115 camera HAL",

          author        : "Nufront Corporation",

          methods       : &camera_module_methods,

          dso:           NULL,

          reserved:      {0},

      },

      get_number_of_cameras : HAL_getNumberOfCameras,

      get_camera_info       : HAL_getCameraInfo

    };

}

上面的结构体被module->methods->open调用了。如此就完成了 app到底层的初始化工作。

2.接下来看一下 hw_get_module()函数。

hw_get_module()->property_get(variant_keys[i],prop,NULL)->__system_property_get(key, value) ->__system_property_find(const char *name)-> __system_property_read(pi, 0, value)-> load(id, prop, &hmi)->snprintf(path,sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant)-> handle = dlopen(path, RTLD_NOW)-> const char *sym = HAL_MODULE_INFO_SYM_AS_STR; hmi = (const struct hw_module_t *)dlsym(handle, sym)

其实就是把camera的so文件camera.default.so文件load进来。

3. 最后我们看一下 property_get(variant_keys[i],prop,NULL)

这个其实就是获取 ro.hardware属性,我们关心的就是这个值是什么。

简单的获取方法是adb shell中getprop直接去找需要的人名字的数值。

代码流程上则需要更详细的了解property_set和property_get的实现了。

 

 至于dlopen和dlsym怎是so文件操作的标准函数。需要另外详细了解了。

 

 

你可能感兴趣的:(HAL层开发框架介绍)