




已阅读5页,还剩15页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android HAL框架及Sensor HAL stub的实现方法收集网络上的这部分信息,系统整理如下,如发现有谬误或有更好的建议,请联系: 第一部分 Android HAL框架1.1. HAL简介Android 的 HAL(Hardware Abstract Layer硬件抽象层)是Google因应厂商希望不公开源码的要求下,所推出的新观念,其架构如下图。虽然 HAL 现在的抽象程度还不足,现阶段实作还不是全面符合 HAL的架构规划,不过也确实给了我们很好的思考空间。图1:Android HAL 架构规划这是 Patrick Brady (Google) 在2008 Google I/O 所发表的演讲Anatomy & Physiology of an Android中,所提出的 Android HAL 架构图。从这张架构图我们知道,HAL 的目的是为了把 Android framework 与 Linux kernel 完整隔开。让 Android 不至过度依赖 Linux kernel,有点像是kernel independent的意思,让 Android framework 的开发能在不考虑驱动程序的前提下进行发展。在 Android 原始码里,HAL 主要的实作储存于以下目录:1. hardware/libhardware_legacy/ - 过去的实作、采取链接库模块的观念进行2. hardware/libhardware/ - 新版的实作、调整为 HAL stub 的观念3. hardware/ril/ - Radio Interface Layer在 HAL 的架构实作成熟前(即图1的规划),我们先就目前 HAL 现况做一个简单的分析。另外,目前 Android 的 HAL实作,仍旧散布在不同的地方,例如 Camera、WiFi 等,因此上述的目录并不包含所有的 HAL 程序代码。1.2. HAL的过去和现在(1)HAL的过去:图2:Android HAL / libhardware_legacy过去的 libhardware_legacy 作法,比较是传统的module方式,也就是将 *.so 档案当做shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。透过直接函数呼叫的方式,来操作驱动程序。当然,应用程序也可以不需要透过 JNI 的方式进行,直接以加载 *.so 檔(dlopen)的做法呼叫*.so 里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。(2)HAL的现状:图3:Android HAL / libhardware现在的 libhardware 作法,就有stub的味道了。HAL stub 是一种代理人(proxy)的概念,stub 虽然仍是以 *.so檔的形式存在,但 HAL 已经将 *.so 档隐藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则是向 HAL 取得特定模块(stub)的 operations,再 callback 这些操作函数。这种以 indirect function call 的实作架构,让HAL stub 变成是一种包含关系,即 HAL 里包含了许许多多的 stub(代理人)。Runtime 只要说明类型,即 module ID,就可以取得操作函数。对于目前的HAL,可以认为Android定义了HAL层结构框架,通过几个接口访问硬件从而统一了调用方式。(3)HAL_legacy和HAL的对比:HAL_legacy:旧式的HAL是一个模块,采用共享库形式,在编译时会调用到。由于采用function call形式调用,因此可被多个进程使用,但会被mapping到多个进程空间中,造成浪费,同时需要考虑代码能否安全重入的问题(thread safe)。HAL:新式的HAL采用HAL module和HAL stub结合形式,HAL stub不是一个share library,编译时上层只拥有访问HAL stub的函数指针,并不需要HAL stub。上层通过HAL module提供的统一接口获取并操作HAL stub,so文件只会被mapping到一个进程,也不存在重复mapping和重入问题。1.3. HAL module的架构HAL moudle主要分为三个结构:struct hw_module_t;struct hw_module_methods_t;struct hw_device_t;它们的继承关系如下图:图4:Android HAL结构继承关系1.4. HAL的使用方法(1)Native code通过hw_get_module调用获取HAL stub:hw_get_module (LED_HARDWARE_MODULE_ID, (const hw_module_t*)&module)(2)通过继承hw_module_methods_t的callback来open设备:module-methods-open(module, LED_HARDWARE_MODULE_ID, (struct hw_device_t*)device);(3)通过继承hw_device_t的callback来控制设备:sLedDevice-set_on(sLedDevice, led);sLedDevice-set_off(sLedDevice, led);1.5. HAL stub编写方法(1)定义自己的HAL结构体,编写头文件led.h, hardware/hardware.hstruct led_module_t struct hw_module_t common;struct led_control_device_t struct hw_device_t common; int fd; /* file descriptor of LED device */ /* supporting control APIs go here */ int (*set_on)(struct led_control_device_t *dev, int32_t led); int (*set_off)(struct led_control_device_t *dev, int32_t led);继承关系如下图:图5:HAL stub与HAL module继承关系(2)设计led.c 完成功能实现和HAL stub注册(2.1)led_module_methods继承hw_module_methods_t,实现open的callbackstruct hw_module_methods_t led_module_methods = open: led_device_open;(2.2)用HAL_MODULE_INFO_SYM实例led_module_t,这个名称不可修改tag:需要制定为 HARDWARE_MODULE_TAGid:指定为 HAL Stub 的 module IDmethods:struct hw_module_methods_t,为 HAL 所定义的methodconst struct led_module_t HAL_MODULE_INFO_SYM = common: 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, /* supporting APIs go here. */;(2.3)open是一个必须实现的callback API,负责申请结构体空间,填充信息,注册具体操作API接口,打开Linux驱动。 由于存在多重继承关系,只需对子结构体hw_device_t对象申请空间即可。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; /* * Initialize Led hardware here. */ dev-fd = open(LED_DEVICE, O_RDONLY); if (dev-fd fd; switch (led) case LED_C608: ioctl(fd, 1, &led); break; case LED_C609: ioctl(fd, 1, &led); break; default: return -1; return 0;int led_off(struct led_control_device_t *dev, int32_t led) int fd; LOGI(LED Stub: set %d off., led); fd = dev-fd; switch (led) case LED_C608: ioctl(fd, 2, &led); break; case LED_C609: ioctl(fd, 2, &led); break; default: return -1; return 0;第二部分 Android HAL的调用Android 对硬件的调用, google 推荐使用 HAL 的方式进行调用,对于 Andriod HAL 的写法,可以参考 android 源码里的 hardware 目录下几个模块的模版。 在看 HAL 的编写方法的过程中,会发现整个模块貌似没有一个入口。一般说来模块都要有个入口,比如应用程序有 main 函数,可以为加载器进行加载执行, dll 文件有 dllmain ,而对于我们自己写的动态链接库,我们可以对库中导出的任何符号进行调用。 问题来了, Android 中的 HAL 是比较具有通用性的,需要上层的函数对其进行加载调用, Android 的 HAL 加载器是如何实现对不同的 Hardware Module 进行通用性的调用的呢? 带着这个疑问查看 Android 源码,会发现 Android 中实现调用 HAL 是通过 hw_get_module 实现的。 int hw_get_module(const char *id, const struct hw_module_t *module); 这是其函数原型, id 会指定 Hardware 的 id ,这是一个字符串,比如 sensor 的 id 是 #define SENSORS_HARDWARE_MODULE_ID sensors ,如果找到了对应的 hw_module_t 结构体,会将其指针放入 *module 中。看看它的实现。 /* Loop through the configuration variants looking for a module */ for (i=0 ; iHAL_VARIANT_KEYS_COUNT+1 ; i+) if (i HAL_VARIANT_KEYS_COUNT) / 获取 ro.hardware/duct.board/ro.board.platform/ro.arch 等 key 的值。 if (property_get(variant_keysi, prop, NULL) = 0) continue; snprintf(path, sizeof(path), %s/%s.%s.so, HAL_LIBRARY_PATH, id, prop); / 如果开发板叫做 mmdroid, 那么这里的 path 就是 system/lib/hw/sensor.mmdroid.so else snprintf(path, sizeof(path), %s/%s.default.so, HAL_LIBRARY_PATH, id);/ 默认会加载 /system/lib/hw/sensor.default.so if (access(path, R_OK) continue; /* we found a library matching this id/variant */ break; status = -ENOENT; if (i id) != 0) LOGE(load: id=%s != hmi-id=%s, id, hmi-id); status = -EINVAL; goto done; hmi-dso = handle; /* success */ status = 0; done: if (status != 0) hmi = NULL; if (handle != NULL) dlclose(handle); handle = NULL; else LOGV(loaded HAL id=%s path=%s hmi=%p handle=%p, id, path, *pHmi, handle); / 凯旋而归 *pHmi = hmi; return status; 从上面的代码中,会发现一个很奇怪的宏 HAL_MODULE_INFO_SYM_AS_STR ,它直接被定义为了 #define HAL_MODULE_INFO_SYM_AS_STR HMI ,为何根据它就能从动态链接库中找到这个 hw_module_t 结构体呢?我们查看一下我们用到的 hal 对应的 so 就可以了,在 linux 中可以使用 readelf XX.so s 查看。 Symbol table .dynsym contains 28 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000594 0 SECTION LOCAL DEFAULT 7 2: 00001104 0 SECTION LOCAL DEFAULT 13 3: 00000000 0 FUNC GLOBAL DEFAULT UND ioctl 4: 00000000 0 FUNC GLOBAL DEFAULT UND strerror 5: 00000b84 0 NOTYPE GLOBAL DEFAULT ABS _exidx_end 6: 00000000 0 OBJECT GLOBAL DEFAULT UND _stack_chk_guard 7: 00000000 0 FUNC GLOBAL DEFAULT UND _aeabi_unwind_cpp_pr0 8: 00000000 0 FUNC GLOBAL DEFAULT UND _errno 9: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _bss_end_ 10: 00000000 0 FUNC GLOBAL DEFAULT UND malloc 11: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _bss_start_ 12: 00000000 0 FUNC GLOBAL DEFAULT UND _android_log_print 13: 00000b3a 0 NOTYPE GLOBAL DEFAULT ABS _exidx_start 14: 00000000 0 FUNC GLOBAL DEFAULT UND _stack_chk_fail 15: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _bss_end_ 16: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _bss_start 17: 00000000 0 FUNC GLOBAL DEFAULT UND memset 18: 00000000 0 FUNC GLOBAL DEFAULT UND _aeabi_uidiv 19: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _end_ 20: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _edata 21: 00001188 0 NOTYPE GLOBAL DEFAULT ABS _end 22: 00000000 0 FUNC GLOBAL DEFAULT UND open 23: 00080000 0 NOTYPE GLOBAL DEFAULT ABS _stack 24: 00001104 128 OBJECT GLOBAL DEFAULT 13 HMI 25: 00001104 0 NOTYPE GLOBAL DEFAULT 13 _data_start 26: 00000000 0 FUNC GLOBAL DEFAULT UND close 27: 00000000 0 FUNC GLOBAL DEFAULT UND free 从上面中,第 24 个符号,名字就是“ HMI ”,对应于 hw_module_t 结构体。再去对照一下 HAL 的代码。 /* * The COPYBIT Module */ struct copybit_module_t HAL_MODULE_INFO_SYM = common: tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: COPYBIT_HARDWARE_MODULE_ID, name: QCT MSM7K COPYBIT Module, author: Google, Inc., methods: ©bit_module_methods ; 这里定义了一个名为 HAL_MODULE_INFO_SYM 的 copybit_module_t 的结构体, common 成员为 hw_module_t 类型。注意这里的 HAL_MODULE_INFO_SYM 变量必须为这个名字,这样编译器才会将这个结构体的导出符号变为“ HMI ”,这样这个结构体才能被 dlsym 函数找到! 综上,我们知道了 andriod HAL 模块也有一个通用的入口地址,这个入口地址就是 HAL_MODULE_INFO_SYM 变量,通过它,我们可以访问到 HAL 模块中的所有想要外部访问到的方法。第三部分 Sensor HAL stub的实现方法理解了Android HAL的框架原理,就比较容易实现sensor HAL stub部分,况且这一部分google框架已经预留好了,我们所要做的工作就是填写相应的结构体及实现方法,这一部分的实现可以参考源码中的device/xxxx/libsensors中的文件,下面介绍重要的结构体;1. 一切从struct sensors_module_t HAL_MODULE_INFO_SYM开始:每一个硬件模块都必须有一个命名为HAL_MODULE_INFO_SYM的数据结构(第二部分已经介绍过为什么),这个数据结构的第一个成员必须是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. */struct sensors_module_t struct hw_module_t common; /* * Enumerate all available sensors. The list is returned in list. * return number of sensors in the list */ int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const* list);HAL_MODULE_INFO_SYM结构体中的get_sensors_list用于得到当前设备支持的sensor列表,hw_module_t common用于表述sensor列表的基本信息,其中重要的是该结构体中的struct hw_module_methods_t* methods,该结构体中定义了打开设备sensor的方法:/* * 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 */ struct hw_module_methods_t* methods; /* modules dso */ void* dso; /* padding to 128 bytes, reserved for future use */ uint32_t reserved32-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;这一部分的通常的实现形式如下:/* The SENSORS Module */ /sensor stub中支持的sensor列表static const struct sensor_t sSensorList = KR3DM 3-axis Accelerometer, STMicroelectronics, 1, SENSORS_ACCELERATION_HANDLE,SENSOR_TYPE_ACCELEROMETER, RANGE_A, RESOLUTION_A, 0.23f, 20000, , AK8973 3-axis Magnetic field sensor, Asahi Kasei Microdevices, 1, SENSORS_MAGNETIC_FIELD_HANDLE, SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 30000, ,。;/ open_sensors方法的声明,实现在后面static int open_sensors(const struct hw_module_t* module, const char* id, struct hw_device_t* device);static int sensors_get_sensors_list(struct sensors_module_t* module, struct sensor_t const* list) *list = sSensorList; return ARRAY_SIZE(sSensorList);static struct hw_module_methods_t sensors_module_methods = open: open_sensors;struct sensors_module_t HAL_MODULE_INFO_SYM = common: tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: SENSORS_HARDWARE_MODULE_ID, name: Samsung Sensor module, author: Samsung Electronic Company, methods: &sensors_module_methods, , get_sensors_list: sensors_get_sensors_list,;2. open_sensors与实际sensor的操作方法相关联:/* Open a new instance of a sensor device using name */static int open_sensors(const struct hw_module_t* module, const char* id, struct hw_device_t* device) int status = -EINVAL; sensors_poll_context_t *dev = new sensors_poll_context_t(); memset(&dev-device, 0, sizeof(sensors_poll_device_t); mon.tag = HARDWARE_DEVICE_TAG; mon.version = 0; mon.module = const_cast(module); mon.close = poll_close; dev-device.activate = poll_activate; dev-device.setDelay = poll_setDelay; dev-device.poll = poll_poll; *device = &mon; status = 0; return status;poll_close为关闭设备的实现;poll_activate为enable&disable设备的实现;poll_setDelay为设置delay time的实现;poll_poll为poll设备信息的实现;在sensor设备的添加及修改的时候,最主要的就是要根据linux kernel driver部分来实现这几个函数;sensors_poll_context_t为自定义的结构体,其第一个成员必须为struct sensors_poll_device_t类型:struct sensors_poll_context_t struct sensors_poll_device_t device; / must be first。;/*
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年程序员进阶算法与数据结构考试要点
- 人教版除法竖式教学课件
- 【教案版】小学五班级上册 武术
- 2025年专业备考指南初级工程师面试题预测与解析工程技术类
- 2025年特岗教师招聘考试历史专业知识与面试技巧详解
- 2025年初级软件测试工程师模拟题及面试技巧
- 2025年数据分析师实战技能模拟测试题库及答案详解
- 2025年财务会计招聘面试技巧及预测题详解
- 2025年电子商务运营专家老年人电商市场趋势分析预测题集
- 2025年特岗教师招聘考试备考策略与规划
- 医院培训课件:《黄帝内针临床运用》
- 峥嵘岁月 课件-2024-2025学年高中音乐人音版(2019) 必修 音乐鉴赏
- 《医院医疗技术临床应用管理制度》
- 建筑装饰工程涂料施工技术考核试卷
- 数字媒体艺术史全册完整教学课件
- 2024年人社法律法规知识竞赛考试题库及答案
- 知识题库-人社劳动知识竞赛测试题及答案(十五)
- 《民宿管家》课件-民宿管家之预订接待
- 部编小学语文单元作业设计四年级上册第三单元 3
- 《信号完整性测试》课件2
- 火电厂检修培训课件
评论
0/150
提交评论