准备在S5PV210的android系统中实现GPS功能,程序已经写好了,也可以编译出gps.s5pc110.so的库,但是不知道上层怎么调用这个库,在GPS相关的Android.mk中也没有找到,很是纳闷。通过分析hardware module才知道是怎么回事,之前并没有详细的了解hardware module,现在简单的分析一下。
HAL层的hardware module主要实现文件为:
hardware/libhardware/hareware.c
hardware/libhardware/include/hardware/hardware.h
重要的结构体:
- typedef struct hw_device_t {
- uint32_t tag;
/** tag must be initialized
to HARDWARE_DEVICE_TAG
*/ 标识符
- uint32_t version;
/** version number
for hw_device_t */ 版本号
- struct hw_module_t* module;
/** reference
to the module this device belongs
to */ 该硬件属于哪个module
- uint32_t reserved[12];
/** padding reserved
for future use */
- int (*close)(struct hw_device_t* device);
/** Close this device
*/ 关闭设备操作
- } hw_device_t;
表示一个硬件设备,存储了各种硬件设备的公共属性和方法
- typedef struct hw_module_t {
- uint32_t tag;
/** tag must be initialized
to HARDWARE_MODULE_TAG
*/ 标识符
- uint16_t version_major;
/** major version number
for the module */ 主版本号
- uint16_t version_minor;
/** minor version number of the module
*/ 次版本号
- const char
*id; /** Identifier of module
*/ id,决定了库的文件名
- const char
*name; /** Name of this module
*/ 模块的名字
- const char
*author; /** Author/owner/implementor of
the module */ 模块作者
- struct hw_module_methods_t* methods;
/** Modules methods
*/ 模块的操作方法
- void* dso;
/** module's dso
*/
- uint32_t reserved[32-7];
/** padding
to 128 bytes, reserved
for future use */
- } hw_module_t;
描述一个硬件模块
- typedef struct hw_module_methods_t {
- int (*open)(const struct hw_module_t*
module, const char* id,
- struct hw_device_t** device);
- } hw_module_methods_t;
定义了操作设备的方法,只有一个open函数
hareware.c分析:
- /** Base path of the hal modules
*/ 指定硬件模块库存放的路径
- #define HAL_LIBRARY_PATH1 "/system/lib/hw"
- #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
下面这个用于搜索不同的库文件名:
- /**
- * There are a
set of variant filename for modules. The
form of the filename
- * is
"<MODULE_ID>.variant.so" so for the led module the Dream variants
- * of base "ro.product.board",
"ro.board.platform"
and "ro.arch" would be:
- *
- * led.trout.so
- * led.msm7k.so
- * led.ARMV6.so
- * led.default.so
- */
- static const char
*variant_keys[]
= {
- "ro.hardware",
- "ro.product.board",
- "ro.board.platform",
- "ro.arch"
- };
库的名称要根据实际的product或board指定
在210平台GPS模块库的文件名可以为:
gps.s5pc110.so
gps.ARMV7.so
gps.default.so
hw_get_module函数作用是在系统中查找模块的库文件
根据硬件模块的id参数和指定的查找路径,配合product,board等变量,最终指定到一个so库文件
- int hw_get_module(const char
*id,
const struct hw_module_t **module)
---------------------------------------------------------------------------------
- /*
Loop through the configuration variants looking
for a module */
- for (i=0
; i<HAL_VARIANT_KEYS_COUNT+1
; i++)
{
- if (i
< HAL_VARIANT_KEYS_COUNT)
{
- if
(property_get(variant_keys[i], prop,
NULL)
== 0)
{
- continue;
- }
- snprintf(path, sizeof(path),
"%s/%s.%s.so", //system/lib/hw/*.*.so
- HAL_LIBRARY_PATH1, id, prop);
- if
(access(path, R_OK)
== 0) break;
- snprintf(path, sizeof(path),
"%s/%s.%s.so",
- HAL_LIBRARY_PATH2, id, prop);
- if
(access(path, R_OK)
== 0) break;
- } else
{
- snprintf(path, sizeof(path),
"%s/%s.default.so", //如果没查到硬件属性,使用默认的库文件名system/lib/hw/*.default.so
- HAL_LIBRARY_PATH1, id);
- //这里是本篇的关键地方,snprintf() 将 id HAL_LIBRARY_PATH1 等的值赋给path,
- if
(access(path, R_OK)
== 0) break;
- }
- }
创建GPS modules分析:
下面这段话很重要,说明了如何构建一个模块
- /**
- * 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.
- */
可以说这是andorid中标准的构建模块的写法
- const struct hw_module_t HAL_MODULE_INFO_SYM
= {
- .tag = HARDWARE_MODULE_TAG,
- .version_major
= 1,
- .version_minor
= 0,
- .id = GPS_HARDWARE_MODULE_ID,
- .name =
"XC-GPS Module",
- .author =
"WWW.XCEMBED.COM",
- .methods =
&hw_module_methods,
- };
通过分析hw_get_module函数我们知道,id是用来指定模块库文件名的,给GPS_HARDWARE_MODULE_ID赋值
#define GPS_HARDWARE_MODULE_ID "gps"
实际上GPS_HARDWARE_MODULE_ID并不是在代码中这样定义的,可能是在某个编译脚本里,我暂时还没找到
指定methods:
- static struct hw_module_methods_t hw_module_methods
= {
- .open = open_gps
- };
只有一个open_gps函数,当模块加载时就会执行open_gps:
- static int open_gps(const struct hw_module_t* module, char
const* name,
- struct hw_device_t** device)
- {
- struct gps_device_t *gps_device
= malloc(sizeof(struct gps_device_t));
- if (gps_device)
- {
- memset(gps_device, 0, sizeof(*gps_device));
- gps_device->common.tag
= HARDWARE_DEVICE_TAG;
- gps_device->common.version
= 0;
- gps_device->common.module
= (struct hw_module_t*)module;
- gps_device->get_gps_interface
= gps_get_hardware_interface;
- *device
= (struct hw_device_t*)gps_device;
- return 0;
- }
- return 1;
- }
每个硬件设备都应该有一个类似xxxx_device_t的结构体,里面包含了hw_device_t
gps的设备结构体定义如下:
- struct gps_device_t {
- struct hw_device_t common;
- const GpsInterface*
(*get_gps_interface)(struct gps_device_t* dev);
- };
在open函数中给这个模块所包含的hw_device_t赋值
get_gps_interface函数用来得到GPS的操作接口
- const GpsInterface* gps_get_hardware_interface(struct gps_device_t* dev)
- {
- return &_GpsInterface;
- }
接下来,程序的主体部分就是实现_GpsInterface里面所定义的所有操作
HAL层的模块是由具体的上一层JNI来调用,以后再分析。