Hal

来自个人维基
跳转至: 导航搜索

目录

三个重要结构体

  • hw_module_t
/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
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 */
    //模块方法列表,指向hw_module_methods_t*
    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函数
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
                  struct hw_device_t** device);
} hw_module_methods_t;
  • hw_device_t
/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 */
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;

定义自己的hal模块

一、在.h文件中“继承”hw_module_t、hw_device_t

//led.h

/* HAL规定不能直接使用hw_module_t结构,因此需要做这么一个继承 */
struct led_module_t {
   struct hw_module_t common;
};

struct led_control_device_t {  
   /* 自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作 */
   struct hw_device_t common;

   /*可用于具体的设备描述符,如指向/dev/xxx */
   int fd;

   /* 在这里定义自己的控制api */
   int (*set_on)(struct led_control_device_t *dev, int32_t led);
   int (*set_off)(struct led_control_device_t *dev, int32_t led);
};

/* 定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub */
#define LED_HARDWARE_MODULE_ID "led"  

二、.c文件中定义相关变量、实现相关函数

1、定义相关变量

由本文件第一节“三个重要的结构体”可知,hw_device_t包含hw_module_t类型指针,hw_module_t包含hw_module_methods_t类型指针,而上面.h头文件我们自定义的led_control_device_t结构体又包含hw_device_t结构体,因此这四个结构体的复用情况如下:

hw_module_methods_t <- hw_module_t <- hw_device_t <- led_control_device_t

也就是说,通过led_control_device_t我们可以找到hal三大结构体类型(变量),而上一小节的代码中也说明了我们自定义的一些控制api也是放在led_control_device_t中的。

因此自然而然,我们应该很容易想到我们应该首先定义一个led_control_device_t变量:

//led.c
static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};
const struct led_module_t HAL_MODULE_INFO_SYM = {
//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。
    common: {
        tag: HARDWARE_MODULE_TAG,  //这里HARDWARE_MODULE_TAG也是规范中固定死的
        version_major: 1,
        version_minor: 0,
        id: LED_HARDWARE_MODULE_ID,
        name: "Sample LED Stub",
        author: "The Mokoid Open Source Project",
        methods: &led_module_methods,  //实现了一个open的方法供jni层调用,
                                       //从而实例化led_control_device_t
    }
};

从上面可以看出,实际并不是这样的,这里并没有定义led_control_device_t变量,却定义了led_module_t变量,而这个函数仅包括了一个hw_module_methods_t类型指针,而hw_module_methods_t中却只有一个open函数,那其他接口函数是如何传给jni的呢?

其实,关键也就在于这个open函数(可以先查看下一节的led_device_open函数),正是通过这个函数将hw_device_t类型指针返回给上层jni的,而在led_control_device_t结构体中,hw_device_t类型指针是第一个变量(规范要求必须为第一个变量),如此在jni上通过将hw_device_t类型指针的强制转换为led_control_device_t类型,则完成了接口函数的传递过程。

如果对这个感兴趣的话可以参阅下这篇文章:Android中HAL如何向上层提供接口总结


2、定义相关函数

有哪些函数需要定义呢?我们先来统计一下,我们按照以下“包含”关系自底向上来进行统计:

hw_module_methods_t <- hw_module_t <- hw_device_t <- led_control_device_t

(1)hw_module_methods_t中的open函数;

(2)hw_module_t中无;

(3)hw_device_t中的close函数;

(4)led_control_device_t中自定义的api函数

统计是准确的:

//led.c
int led_device_close(struct hw_device_t* device)
{
	struct led_control_device_t* ctx = (struct led_control_device_t*)device;
	if (ctx) {
		free(ctx);
	}
	return 0;
}

int led_on(struct led_control_device_t *dev, int32_t led)
{
	LOGI("LED Stub: set %d on.", led);

	return 0;
}

int led_off(struct led_control_device_t *dev, int32_t led)
{
	LOGI("LED Stub: set %d off.", led);

	return 0;
}

static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device) 
{
	struct led_control_device_t *dev;

	dev = (struct led_control_device_t *)malloc(sizeof(*dev));
	memset(dev, 0, sizeof(*dev));

	dev->common.tag =  HARDWARE_DEVICE_TAG;
	dev->common.version = 0;
	dev->common.module = module;
	dev->common.close = led_device_close;

	dev->set_on = led_on;
	dev->set_off = led_off;

	*device = &dev->common;

success:
	return 0;
}

思考

为什么hal在往上传接口时要以hw_module_t类型给出,然后在jni中对指针进行强制转换,而不直接以用户定义的类型(如led_control_device_t)传出?


参考资料:

Android HAL实例解析-刘洪涛的专栏

Android中HAL如何向上层提供接口总结

注:

本文引用的是台湾的Jollen的mokoid工程代码