Android模拟器学framework和driver之传感器篇
来源:互联网 发布:stc89c51数据手册 编辑:程序博客网 时间:2024/06/06 13:24
Android模拟器学framework和driver之传感器篇
Android传感器的介绍这里我就不多说了,给出一个链接,想了解的朋友可以先去了解下:
http://www.ibm.com/developerworks/cn/opensource/os-android-sensor/
我这里我会带着大家一起分析android的传感器部分,之前拜读过罗老师对Android HAL分析的博客,个人感觉写的非常不错,在这里首先要感谢下老师的无私奉献:
http://blog.csdn.net/luoshengyang/article/details/6567257
下面介绍下我们分析android sensor的步骤:
1.首先是搭建linux下的开发环境,因为我是使用模拟器来做分析,所以要用到goldfish的linux kernel源码,以及android源码,在这里我使用的是android2.3.3 gingerbread;
2.在goldfish kernel中添加一个sensor的驱动,会使用到input subsystem以及一些linux driver的知识,在这边我是参考的freescale BSP中的加速度传感器的代码。
3.测试自己的driver,在android 源码中添加自己的一个小工具来做测试。
4.android sensor HAL 中添加自己的传感器。
5.编写一个android app测试传感器抓到的数据
6.分析sensorService
7.android framework中sensor的分析
我会跟着这个流程来分析,其实我也蛮喜欢反过来做分析的,不过个人觉得还是先从底层出发容易理清思路,当大家分析完后可以自己反过来分析一下。
尽请期待。。。
Android模拟器学framework和driver之传感器篇1(linux sensor driver)
对于android模拟器开发环境的搭建这里我就不多说了,网上google下一大堆,还有就是android 模拟器的kernel使用的是goldfish的kernel,可以使用git得到源码,然后就可以编译了,大家还是可以参考罗老师的博客。。。
在这里我准备编写一个温度传感器的虚拟driver,之前写过g-sensor和light sensor,所以不想写了,换个新鲜的,其实驱动架构都是一样的,OK 分化不多说,下面就介绍一下这个驱动。
在这里,我比较偷懒的使用了linux的一个iio子系统,这是一个不成熟的子系统,所以被放到源码陌路下面的/drvers/staging中,对于这个子系统,我也只是粗略的看过它的驱动模型,好吧 ^0^,不过个人觉得这个子系统还是蛮简单使用的,而却里面的api不是很多,相信大家随便分析下就能搞懂了。
OK,首先是头文件
/common/drivers/staging/iio/temperature/android-temperature.h
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <linux/input-polldev.h>
- #include "../iio.h"
- #define POLL_INTERVAL 2000 //set poll time
- struct temperature_drvdata {
- struct iio_dev *indio_dev;
- struct input_polled_dev *poll_input;
- //....reserved
- };
相信大家看到了这个头文件就差不多知道驱动是怎么写的了吧,我选用的是platform device driver,driver layer向user space传送数据时通过input sybsystem传送的,这也是android sensor驱动比较主流的做法,还有一些做法是直接往自己创建的sysfs中写数据,这也是一中比较简单的做法,事件的触控方式我选用的是poll方式,因为这里我写的驱动是一个虚拟的设备,一般出发方式会选用中断触发,而我这个驱动选择每隔一段时间往user space上报数据,时间间隔就是这里的POLL_INTERVAL这个宏设定的。
说了这么多都没有看到驱动的代码真不好意思,下面来分析下驱动的代码。
/common/drivers/staging/iio/temperature/android-temperature.c
首先是init和exit函数:
- <span style="color:#cc33cc;"><strong>static int __init temperature_init(void)
- {
- printk(KERN_INFO "temperature init...\n");
- return platform_driver_register(&temperature_device_driver);
- }
- static void __exit temperature_exit(void)
- {
- platform_driver_unregister(&temperature_device_driver);
- }
- module_init(temperature_init);
- module_exit(temperature_exit);</strong></span>
- 这也没啥好说的,大家愿意的话可以再后面在添上这个driver module的作者和出处,传扬千里,哈哈,我就不了,本人比较谦虚。
这边最主要的应该就是temperature_device_driver这个变量这是一个platform_driver结构体,在驱动注册的时候必须把这个结构体传进去,我们的platform设备模型就是通过这个结构体找到相应的device,然后把driver和device绑定在一起,这边涉及到linux 设备驱动模型,这边我也不做详细的分析了,想要了解的话可以自己学习,个人觉得如果是做linux驱动的话了解linux 设备驱动模型是很重要的,这可以让我们站在一个比较高的层次上去写代码。
OK,不扯了看下这个结构体:
- <span style="background-color: rgb(255, 255, 255);"><span style="color:#cc33cc;">static struct platform_driver temperature_device_driver = {
- .probe = temperature_probe,
- // .remove = __devexit_p(temperature_remove),
- .driver = {
- .name = "android-temperature",
- .owner= THIS_MODULE,
- },
- };</span></span>
这边就是定义了probe和remove,真实的设备的话还有会suspend,resume,early_suspend,late_resume等回调函数,在适当的时间会回调到这些函数(犀利的读者可能看到了这边remove我没有去实现,哈哈,我比较懒,不过大家要有一个良好的习惯,不要学我)。但是在这边注册了platform的驱动,是去找哪的platform设备呢?当然是我们自己要去实现啦,通常device端我们都会在板级的文件中去定义,我们这里是:
/common/arch/arm/mach-goldfish/board-goldfish.c
- <strong><span style="color:#cc33cc;">struct platform_device android_temperature_device = {
- .name="android-temperature",
- .id=-1,
- };
- </span></strong>
- static void __init goldfish_init(void)
- {
- platform_device_register(&goldfish_pdev_bus_device);
- <span style="color:#cc33cc;"><strong> platform_device_register(&android_temperature_device);</strong></span>
- }
大家注意。这边的name和driver中platform_driver中name用该一样,不然他们怎么可以绑定在一起呢,不然他们怎么会找到对方呢,有缘千里来相会嘛,对不?
OK,当我们的driver找到了device的时候会执行probe回调函数,也就是这里的temperature_probe函数,好,我们来看一下这个probe函数:
- <strong><span style="color:#cc33cc;">static int temperature_probe(struct platform_device *pdev)
- {
- struct temperature_drvdata *ddata;
- struct input_dev *idev;
- int err=0;
- printk(KERN_INFO "%s\n",__FUNCTION__);
- ddata=kzalloc(sizeof(struct temperature_drvdata),GFP_KERNEL);
- if(!ddata) {
- printk(KERN_INFO "failed to allocate memory...\n");
- err=-ENOMEM;
- goto exit;
- }
- //----for iio device
- ddata->indio_dev=iio_allocate_device();
- if(!ddata->indio_dev){
- printk(KERN_INFO "error to allocate iio device memory....\n");
- goto exit_iio_alloc;
- }
- ddata->indio_dev->attrs = &temperature_attr_group;
- ddata->indio_dev->dev.parent = &pdev->dev;
- ddata->indio_dev->dev_data = (void *)(ddata);
- ddata->indio_dev->driver_module = THIS_MODULE;
- ddata->indio_dev->modes = INDIO_DIRECT_MODE;
- err = iio_device_register(ddata->indio_dev);
- if(err){
- printk(KERN_INFO "iio device register failed....\n");
- goto exit_iio_reg;
- }
- //-----for input device
- ddata->poll_input=input_allocate_polled_device();
- if(!(ddata->poll_input)){
- err=-ENOMEM;
- printk(KERN_INFO "input poll allocate failed...\n");
- goto exit_iio_reg;
- }
- ddata->poll_input->poll=temperature_dev_poll;
- ddata->poll_input->poll_interval = POLL_INTERVAL;
- idev=ddata->poll_input->input;
- idev->name = "Android Temperature Sensor";
- idev->phys = "temperature-sensor/input0";
- idev->dev.parent=&pdev->dev;
- idev->id.bustype=BUS_HOST;
- idev->id.vendor=0x1234;
- idev->id.product=0x0123;
- idev->id.version=0x0012;
- __set_bit(EV_ABS,idev->evbit);
- __set_bit(ABS_PRESSURE,idev->absbit);
- __set_bit(EV_SYN,idev->evbit);
- input_set_abs_params(idev,ABS_PRESSURE,0,65535,0,0);
- err=input_register_polled_device(ddata->poll_input);
- if(err){
- printk(KERN_INFO "input register poll device failed....\n");
- goto err_reg_poll;
- }
- platform_set_drvdata(pdev,ddata);
- return 0;
- err_reg_poll:
- input_free_polled_device(ddata->poll_input);
- exit_iio_reg:
- iio_free_device(ddata->indio_dev);
- exit_iio_alloc:
- kfree(ddata);
- exit:
- return err;
- }</span></strong>
这边做的都是一些初始化的事情,我们这边首先给我们的机构体分配内存,然后给iio device分配空间,然后注册iio device,然后注册input_polled_device这里可以参考input)poll的源码,主要就是内嵌了一个工作队列来poll数据,这里不多说读者可以自行去分析。
这里最重要的有2点我提一下,首先就是我们poll数据的回调函数被挂在ddata->poll_input->poll=temperature_dev_poll;参考源码这个回调函数是什么时候被执行的呢,其实input_polled_dev还有几个回调函数,其中有一个open和close函数,当user space去open input下面的这个event的时候poll回调函数就会一直执行,时间间隔为我们定义的interval这个参数。还有一点就是iio 设备驱动上面挂的文件系统就是ddata->indio_dev->attrs = &temperature_attr_group;用法很简单吧,这边我只是注册了一个name的文件节点,user space可以去读写这个节点,一般我们写驱动的时候可以用这个文件节点来开关我们的设备。
OK,接下来就是一些事件的处理,看如下代码:
- <span style="color:#cc33cc;"><strong>#include "android-temperature.h"
- static ssize_t temperature_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%s\n", "android-temperature sensor");
- }
- static IIO_DEVICE_ATTR(name, S_IRUGO, temperature_show_name, NULL,0);
- static struct attribute *temperature_attributes[] = {
- &iio_dev_attr_name.dev_attr.attr,
- NULL
- };
- static const struct attribute_group temperature_attr_group = {
- .attrs = temperature_attributes,
- };
- static int tempValue;
- static void temperature_dev_poll(struct input_polled_dev *dev)
- {
- printk(KERN_INFO "Current Temperature: %d\n",tempValue);
- if((tempValue++)==100)
- tempValue=0;
- input_event(dev->input,EV_ABS,ABS_PRESSURE,tempValue);
- input_sync(dev->input);
- }</strong></span>
这里我们上报的数据就是这个tempValue,会每隔一段时间自增1,直到100再回到0,。
OK,驱动介绍完,接下来就可以把驱动编译进goldfish里面,然后运行模拟器,使用adb进入:
- <strong><span style="color:#cc33cc;">root@jay:/home/jay/android/common# adb shell
- # cd sys/bus/iio/devices/
- # ls
- device0
- device1
- device2
- # cd device2
- # ls
- uevent
- subsystem
- power
- name
- # cat name
- android-temperature sensor
- # </span></strong>
大家可以看到我这边cat出name就是自己写进去的那个名字,初步测试驱动ok接下来下一篇中给大家介绍下编译生成一个tool来测试驱动功能。
Android模拟器学framework和driver之传感器篇2(生成测试tool)
之前我们已经写好了自己的driver,现在我们要在android下测试我们的tool。
这里我使用extern下面去编译生成一个tool,在adb shell中可以执行的,来抓取我们的温度值。
这一步相对简单,可以看做是linux的应用程序,附代码:
/external/temperature/temperature.c
- <strong><span style="color:#cc33cc;">#include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <linux/input.h>
- /*
- struct input_event
- {
- struct timeval time;
- __u16 type;
- __u16 code;
- __s32 value;
- };*/
- int main(void)
- {
- struct input_event ev_temp;
- int fd = open("/dev/input/event2", O_RDWR);
- while(1)
- {
- int count = read(fd, &ev_temp, sizeof(struct input_event));
- if(EV_ABS == ev_temp.type && ABS_PRESSURE == ev_temp.code)
- {
- printf("time : %ld, %d", ev_temp.time.tv_sec, ev_temp.time.tv_usec);
- printf(" Current Temperature: %d \n", ev_temp.value);
- }
- }
- return 0;
- }</span></strong>
- 这边我就不多说了,大家都能看懂,接下来是android的makefile,
- /external/temperature/Android.mk
- <pre name="code" class="cpp"><strong><span style="color:#cc33cc;">LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := temperature
- LOCAL_SRC_FILES := $(call all-subdir-c-files)
- include $(BUILD_EXECUTABLE)</span></strong>
然后编译一下之后会在out/.../generic/system/bin下生成这个tool,
- 进入adb shell执行就可以了如下:
- <pre name="code" class="cpp"><span style="color:#cc33cc;"><strong>root@jay:/home/jay# adb shell
- #
- #
- #
- #
- # temperature
- time : 81, 292520 Current Temperature: 1
- time : 84, 40953 Current Temperature: 2
- time : 86, 61726 Current Temperature: 3
- time : 88, 42323 Current Temperature: 4
- time : 90, 61805 Current Temperature: 5
- ^C
- # </strong></span>
这样就完成了,接下来是我们temperature 的HAL,敬请期待。。。
Android模拟器学framework和driver之传感器篇3(Android HAL)
前面,带着大家一起写了一个temperature sensor的驱动,已经一个测试tool来测试这个驱动,基本功能已经ok,若还有问题的可以参考前面2篇文章,在这里我们要在HAL层中添加我们的设备,来跟framework中的代码连接起来。
在开始摆代码之前我觉得有必要啰嗦几句,HAL层我个人觉得是个比较重要的东西,虽然这边现在还不是很成熟,还不是很规范,但是google还是做了很大力气针对HAL的。
首先来介绍一下android HAL 层,
Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。下图为整个android 架构:
这个是google定义的android整个系统的架构,大家可以看到HAL层起了一个承上启下的作用,HAL层主要是针对一些传感器和一些个硬件而存在的,其实也可以绕过HAL层直接使用JNI来实现从驱动到framework这个过程,但是我们这里主要是讲android中的sensor,针对标准的android而言,sensor都是在HAL中添加的,个人理解还是呼应硬件厂商的建议吧,毕竟这部分代码还可以不开源的。
好了,开源不开源什么的,我是不去关心,对我影响不大,我们还是接着看HAL。
Android硬件抽象层,从下到上涉及到了Android系统的硬件驱动层、硬件抽象层、运行时库和应用程序框架层等等,下图描述了硬件抽象层在Android系统中的位置,以及它和其它层的关系:
现在的 libhardware 作法,使用了stub的概念。stub 虽然仍是以 *.so 檔的形式存在,但 HAL 已经将 *.so 档隐藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则是向 HAL 取得特定模块(stub)的 operations,再 callback 这些操作函数。HAL的实现主要在hardware.c和hardware.h文件中。实质也是通过加载 *.so 库。从而呼叫 *.so 里的符号(symbol)实现。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
到此,都是些理论的东西,实在是不想讲这些条条杠杠的,从小语文就不好的我,最讨厌的就是这些理论的东西了,实践才是真理呢。。。
好了接下来轮到我们的sensor的HAL层了,这里先列出来主要用到的代码:
。。。。。。
讲漏了,这边sensor的HAL层代码我参考的是freescale的BSP,因为个人感觉比较容易懂,哈哈。
先给下载链接,不然大家看不到完整的代码。
http://download.csdn.net/detail/zhangjie201412/4039312
代码目录如下:
sensor/├── AccelSensor.cpp├── AccelSensor.h├── Android.mk├── InputEventReader.cpp├── InputEventReader.h├── LightSensor.cpp├── LightSensor.h├── SensorBase.cpp├── SensorBase.h├── sensors.cpp├── sensors.h├── TemperatureSensor.cpp└── TemperatureSensor.h
这里我们要修改以及添加的是三个文件:
sensor.cpp TemperatureSensor.cpp TemperatureSensor.h
好了,接下来就带大家分析下android sensor的HAL层!!!
先看一下/hardware/libhareware/hardware.c和/hardware/libhardware/include/hardware/hardware.h
这2个文件是android hal层最重要的两个文件,其中定义了hal层主要要实现的3个结构体,
- struct hw_module_t;
- struct hw_module_methods_t;
- struct hw_device_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 */
- 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;
- 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 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;
其实标准的android hal就是实现这3个结构体,然后设置一些回调函数,最后把数据poll到framework中。
好,接下来看下sensor中是怎么封装的:
在/hardware/libhardware/include/hardware/sensors.h 中定义了几个结构体,其中都包含了上面的3个结构体,所以我们sensor module只需要去实现sensor.h中的这几个就OK了。
下面提一下如何添加我们的temperature sensor,首先是hardware/libhardware/modules/sensor/sensors.cpp 中sensor list中添加我们的sensor的信息,
- /* The SENSORS Module */
- static const struct sensor_t sSensorList[] = {
- { "Analog Devices ADXL345/6 3-axis Accelerometer",
- "ADI",
- 1, SENSORS_ACCELERATION_HANDLE,
- SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.145f, 200, { } }, //20000
- { "Android Light sensor",
- "Android",
- 1, SENSORS_LIGHT_HANDLE,
- SENSOR_TYPE_LIGHT, 16000.0f, 1.0f, 0.35f, 0, { } },
- //++++++add by Jay for temperature sensor
- { "Android Temperature Sensor",
- "Android",
- 1, SENSORS_TEMPERATURE_HANDLE,
- SENSOR_TYPE_TEMPERATURE, 100.0f, 1.0f, 1.0f,0, { }},
- //-----------
- };
这里面的Android Temperature Sensor就是我们自己添加的sensor,然后我们去实现我们的temperature sensor的功能,也就是填充一些结构体和实现一些回调函数,这里我挑重要的讲。
- int TemperatureSensor::readEvents(sensors_event_t* data, int count)
- {
- if(count<1)
- return -EINVAL;
- if(mHasPendingEvent){
- mHasPendingEvent = false;
- mPendingEvent.timestamp = getTimestamp();
- *data = mPendingEvent;
- return mEnabled ? 1:0;
- }
- ssize_t n = mInputReader.fill(data_fd);
- if(n<0)
- return n;
- int numEventReceived = 0;
- input_event const* event;
- DEBUG("count: %d\n",count);
- while(count && mInputReader.readEvent(&event)){
- int fd=open("/dev/input/event1", O_RDONLY);
- if(fd<0){
- DEBUG("readEvents: open event2 failed...\n");
- return fd;
- }
- int ret=read(fd,&event,sizeof(event));
- if(ret<sizeof(event)){
- DEBUG("readEvent read failed....\n");
- return ret;
- }
- close(fd);
- int type=event->type;
- if(type == EV_ABS){
- DEBUG("Current Temp: %d\n",event->value);
- mPendingEvent.temperature = (float)(event->value);
- }else if(type==EV_SYN){
- mPendingEvent.timestamp = timevalToNano(event->time);
- if(/*mEnabled &&*/ (mPendingEvent.temperature != mPreviousTemperature)){
- *data++ = mPendingEvent;
- count--;
- numEventReceived++;
- mPreviousTemperature = mPendingEvent.temperature;
- DEBUG("Current Temp: %d\n",(int)mPendingEvent.temperature);
- }
- }else
- DEBUG("temperature : unknow event...\n");
- mInputReader.next();
- }
- return numEventReceived;
- }
大家看了Temperature.cpp就应该知道我这里实现HAL层poll数据最主要的就是上面这个函数,这边其实就是linux的应用层的写法,open input 节点,然后read data,在poll给framework层。
这里我要提醒大家,如果对自己不够有信心的话第一次写hal层代码的时候最好多加点debug message,因为在hal层的调试比较麻烦,出现的错误会直接导致系统不断重启,不会告诉你错哪,所以,最好自己加debug message来调试。
代码方面大家可以看下Temperature.h和sensor.cpp这两个文件里面要实现的一些类和结构体,按照规范写好回调函数就ok了,大家自行分析绰绰有余。
还有就是这里的makefile,会把module编译成sensor.goldfish.so,给framework调用,ok来讲一下framework是如何调用HAL层里面的API的,
大家可以看下android源码下面的frameworks/base/services/sensorservice/SensorDevice.cpp
- SensorDevice::SensorDevice()
- : mSensorDevice(0),
- mSensorModule(0)
- {
- status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&mSensorModule);
- LOGE_IF(err, "couldn't load %s module (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
- if (mSensorModule) {
- err = sensors_open(&mSensorModule->common, &mSensorDevice);
- LOGE_IF(err, "couldn't open device for module %s (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
- if (mSensorDevice) {
- sensor_t const* list;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i<size_t(count) ; i++) {
- mActivationCount.add(list[i].handle, model);
- mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
- }
- }
- }
- }
这里调用了
- status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&mSensorModule);
这个函数在哪呢?在这:
hardware/libhardware/hardware.c里的
- int hw_get_module(const char *id, const struct hw_module_t **module)
- {
- int status;
- int i;
- const struct hw_module_t *hmi = NULL;
- char prop[PATH_MAX];
- char path[PATH_MAX];
- /*
- * Here we rely on the fact that calling dlopen multiple times on
- * the same .so will simply increment a refcount (and not load
- * a new copy of the library).
- * We also assume that dlopen() is thread-safe.
- */
- /* 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",
- 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",
- HAL_LIBRARY_PATH1, id);
- if (access(path, R_OK) == 0) break;
- }
- }
- status = -ENOENT;
- if (i < HAL_VARIANT_KEYS_COUNT+1) {
- /* load the module, if this fails, we're doomed, and we should not try
- * to load a different variant. */
- status = load(id, path, module);
- }
- return status;
- }
这里首先把要get的module的名字传进去,然后找到sensor.goldfish.so,但是怎么去加载这个binary呢?
看下这里的load函数:
- /**
- * Load the file defined by the variant and if successful
- * return the dlopen handle and the hmi.
- * @return 0 = success, !0 = failure.
- */
- static int load(const char *id,
- const char *path,
- const struct hw_module_t **pHmi)
- {
- int status;
- void *handle;
- struct hw_module_t *hmi;
- /*
- * load the symbols resolving undefined symbols before
- * dlopen returns. Since RTLD_GLOBAL is not or'd in with
- * RTLD_NOW the external symbols will not be global
- */
- handle = dlopen(path, RTLD_NOW);
- if (handle == NULL) {
- char const *err_str = dlerror();
- LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
- status = -EINVAL;
- goto done;
- }
- /* Get the address of the struct hal_module_info. */
- const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
- hmi = (struct hw_module_t *)dlsym(handle, sym);
- if (hmi == NULL) {
- LOGE("load: couldn't find symbol %s", sym);
- status = -EINVAL;
- goto done;
- }
- /* Check that the id matches */
- if (strcmp(id, hmi->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;
- }
- handle = dlopen(path, RTLD_NOW);这个函数是用来打开找到的sensor.goldfish.so这个动态库的,然后找到这个库里的一些回调函数,怎么找呢?
- 看下这句话:
- <pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); "><pre name="code" class="cpp"> /* Get the address of the struct hal_module_info. */
- const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
- HAL_MODULE_INFO_SYM_AS_STR;是一个宏,被定义在hardware.h中:
- <pre name="code" class="cpp">#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
好了,就是找HMI这个字串,我们可以用readelf命令查看下sensor.glodfish.so里面的symbol:
- <pre name="code" class="cpp">root@jay:/home/jay/android/android2.3.3# readelf -s out/target/product/generic/system/lib/hw/sensors.goldfish.so
- Symbol table '.dynsym' contains 118 entries:
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
- 2: 00001a29 44 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 3: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_f2iz
- 4: 00001a5d 364 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 5: 00000000 0 FUNC GLOBAL DEFAULT UND poll
- 6: 00000000 0 FUNC GLOBAL DEFAULT UND __errno
- 7: 00000000 0 FUNC GLOBAL DEFAULT UND strerror
- 8: 00000000 0 FUNC GLOBAL DEFAULT UND __android_log_print
- 9: 00000000 0 FUNC GLOBAL DEFAULT UND read
- 10: 00001bd1 120 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 11: 00000000 0 FUNC GLOBAL DEFAULT UND write
- 12: 00001c51 42 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 13: 00000000 0 FUNC GLOBAL DEFAULT UND close
- 14: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv
- 15: 00001c95 42 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 16: 00001cc1 216 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 17: 00000000 0 FUNC GLOBAL DEFAULT UND _Znwj
- 18: 00002455 124 FUNC GLOBAL DEFAULT 7 _ZN11LightSensorC1Ev
- 19: 00002af1 288 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensorC1Ev
- 20: 00002fd5 108 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensorC1E
- 21: 00000000 0 FUNC GLOBAL DEFAULT UND pipe
- 22: 00000000 0 FUNC GLOBAL DEFAULT UND fcntl
- 23: 00000000 0 FUNC GLOBAL DEFAULT UND memset
- 24: 00001ded 216 FUNC GLOBAL DEFAULT 7 _ZN22sensors_poll_context
- 25: 0000432c 132 OBJECT GLOBAL DEFAULT 16 HMI
- 26: 00001ec5 24 FUNC GLOBAL DEFAULT 7 _ZNK10SensorBase5getFdEv
- 27: 00001edd 4 FUNC GLOBAL DEFAULT 7 _ZN10SensorBase8setDelayE
- 28: 00001ee1 4 FUNC GLOBAL DEFAULT 7 _ZNK10SensorBase16hasPend
- 29: 00001ee5 32 FUNC GLOBAL DEFAULT 7 _ZN10SensorBase12close_de
- 30: 00001f05 60 FUNC GLOBAL DEFAULT 7 _ZN10SensorBaseD1Ev
- 31: 000040e8 36 OBJECT GLOBAL DEFAULT 13 _ZTV10SensorBase
- 32: 00001f41 60 FUNC GLOBAL DEFAULT 7 _ZN10SensorBaseD2Ev
- 33: 00001f7d 312 FUNC GLOBAL DEFAULT 7 _ZN10SensorBase9openInput
- 34: 00000000 0 FUNC GLOBAL DEFAULT UND opendir
- 35: 00000000 0 FUNC GLOBAL DEFAULT UND strcpy
- 36: 00000000 0 FUNC GLOBAL DEFAULT UND strlen
- 37: 00000000 0 FUNC GLOBAL DEFAULT UND open
- 38: 00000000 0 FUNC GLOBAL DEFAULT UND ioctl
- 39: 00000000 0 FUNC GLOBAL DEFAULT UND strcmp
- 40: 00000000 0 FUNC GLOBAL DEFAULT UND readdir
- 41: 00000000 0 FUNC GLOBAL DEFAULT UND closedir
- 42: 00000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail
- 43: 00000000 0 OBJECT GLOBAL DEFAULT UND __stack_chk_guard
- 44: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr1
- 45: 000020b5 68 FUNC GLOBAL DEFAULT 7 _ZN10SensorBaseC1EPKcS1_
- 46: 000020f9 68 FUNC GLOBAL DEFAULT 7 _ZN10SensorBaseC2EPKcS1_
- 47: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_lmul
- 48: 00002141 56 FUNC GLOBAL DEFAULT 7 _ZN10SensorBase12getTimes
- 49: 00000000 0 FUNC GLOBAL DEFAULT UND clock_gettime
- 50: 00002179 80 FUNC GLOBAL DEFAULT 7 _ZN10SensorBase11open_dev
- 51: 000021c9 18 FUNC GLOBAL DEFAULT 7 _ZN10SensorBaseD0Ev
- 52: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_pure_virtual
- 53: 000021dd 4 FUNC GLOBAL DEFAULT 7 _ZN11LightSensor8setDelay
- 54: 000021e1 24 FUNC GLOBAL DEFAULT 7 _ZN11LightSensor6enableEi
- 55: 000021f9 12 FUNC GLOBAL DEFAULT 7 _ZNK11LightSensor16hasPen
- 56: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_i2f
- 57: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_fcmpeq
- 58: 00002209 432 FUNC GLOBAL DEFAULT 7 _ZN11LightSensor10readEve
- 59: 00000000 0 FUNC GLOBAL DEFAULT UND memcpy
- 60: 000030dd 96 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 61: 000030c5 24 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 62: 000030ad 22 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 63: 000023b9 68 FUNC GLOBAL DEFAULT 7 _ZN11LightSensorD1Ev
- 64: 0000313d 18 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 65: 00004110 36 OBJECT GLOBAL DEFAULT 13 _ZTV11LightSensor
- 66: 000023fd 18 FUNC GLOBAL DEFAULT 7 _ZN11LightSensorD0Ev
- 67: 00002411 68 FUNC GLOBAL DEFAULT 7 _ZN11LightSensorD2Ev
- 68: 00003165 30 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 69: 000024d1 124 FUNC GLOBAL DEFAULT 7 _ZN11LightSensorC2Ev
- 70: 0000254d 48 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensor6enableEi
- 71: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_fmul
- 72: 0000257d 120 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensor12process
- 73: 000025f9 308 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensor10readEve
- 74: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_ldivmod
- 75: 00002731 216 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensor8setDelay
- 76: 00000000 0 FUNC GLOBAL DEFAULT UND fopen
- 77: 00000000 0 FUNC GLOBAL DEFAULT UND snprintf
- 78: 00000000 0 FUNC GLOBAL DEFAULT UND fwrite
- 79: 00000000 0 FUNC GLOBAL DEFAULT UND fclose
- 80: 00002809 628 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensor11getPoll
- 81: 00000000 0 FUNC GLOBAL DEFAULT UND strncmp
- 82: 00000000 0 FUNC GLOBAL DEFAULT UND strcat
- 83: 00000000 0 FUNC GLOBAL DEFAULT UND fread
- 84: 00000000 0 FUNC GLOBAL DEFAULT UND strtol
- 85: 00002a7d 48 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensorD1Ev
- 86: 00004138 36 OBJECT GLOBAL DEFAULT 13 _ZTV11AccelSensor
- 87: 00002aad 18 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensorD0Ev
- 88: 00002ac1 48 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensorD2Ev
- 89: 00002c11 288 FUNC GLOBAL DEFAULT 7 _ZN11AccelSensorC2Ev
- 90: 00002d31 4 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensor8se
- 91: 00002d35 24 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensor6en
- 92: 00002d4d 12 FUNC GLOBAL DEFAULT 7 _ZNK17TemperatureSensor16
- 93: 00002d59 488 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensor10r
- 94: 00002f41 64 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensorD1E
- 95: 00004160 36 OBJECT GLOBAL DEFAULT 13 _ZTV17TemperatureSensor
- 96: 00002f81 18 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensorD0E
- 97: 00002f95 64 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensorD2E
- 98: 00003041 108 FUNC GLOBAL DEFAULT 7 _ZN17TemperatureSensorC2E
- 99: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdaPv
- 100: 00003151 18 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 101: 00000000 0 FUNC GLOBAL DEFAULT UND _Znaj
- 102: 00003185 30 FUNC GLOBAL DEFAULT 7 _ZN24InputEventCircularRe
- 103: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize
- 104: 000043c0 0 NOTYPE GLOBAL DEFAULT 17 __dso_handle
- 105: 00004000 0 NOTYPE GLOBAL DEFAULT 11 __INIT_ARRAY__
- 106: 00004008 0 NOTYPE GLOBAL DEFAULT 12 __FINI_ARRAY__
- 107: 000035dc 0 NOTYPE GLOBAL DEFAULT ABS __exidx_start
- 108: 0000371c 0 NOTYPE GLOBAL DEFAULT ABS __exidx_end
- 109: 0000432c 0 NOTYPE GLOBAL DEFAULT 16 __data_start
- 110: 000043b4 0 NOTYPE GLOBAL DEFAULT ABS _edata
- 111: 000043b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
- 112: 000043b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start__
- 113: 000043d0 0 NOTYPE GLOBAL DEFAULT ABS _bss_end__
- 114: 000043d0 0 NOTYPE GLOBAL DEFAULT ABS __bss_end__
- 115: 000043d0 0 NOTYPE GLOBAL DEFAULT ABS __end__
- 116: 000043d0 0 NOTYPE GLOBAL DEFAULT ABS _end
- 117: 00080000 0 NOTYPE GLOBAL DEFAULT ABS _stack
大家可以看到这里的第25行,OK 找到了,这里找到了这个动态库的地址,然后就可以一次找到这个动态库中的函数,最终可以被调用。结束语:
- 这里我只是大致分析了一下这个流程,对于代码是如何编写的,大家可以参考我提供的下载,其实android hal层就是填充一些“规则”。
- 下面一节我们来编写一个测试apk来抓我们的温度,之后再来分析framework层,因为到这里我们sensor的移植就结束了,framework层中android已经帮我们把api都写好了,也就是说sensor是android的标准api,我们不需要自己去搭建。
Android模拟器学framework和driver之传感器篇4(Android APP)
上面已经介绍了,android temperature sensor的移植过程,代码页已经贴给大家了,现在我们写一个APK来进行测试,代码很简单,界面也很简单很丑陋,哈哈,大家不要介意,这个aok只是用作测试,这里我就不多做介绍了,直接贴代码。
java代码:
- package com.android.jay.sensor1;
- import android.app.Activity;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.widget.TextView;
- public class MySensor1Activity extends Activity implements SensorEventListener {
- /** Called when the activity is first created. */
- private TextView tView;
- SensorManager sensorManager = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tView=(TextView)findViewById(R.id.tv);
- sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
- sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE),sensorManager.SENSOR_DELAY_GAME);
- }
- public void onSensorChanged(SensorEvent event) {
- if(event.sensor.getType()==Sensor.TYPE_TEMPERATURE)
- tView.setText("value: "+Float.toString(event.values[0]));
- }
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // TODO Auto-generated method stub
- }
- }
最后用adb install xxx.apk安装程序,然后再模拟器上运行,结果如下:
OK,看到value在不断的变化了吧,完工,下面一节我们会介绍framework层如何处理的。。。
Android模拟器学framework和driver之传感器篇5(Android framework)
之前的几篇文章重点介绍了android中传感器模块的标准移植方法,这篇文章我主要跟大家介绍下android framework中对传感器的处理以及管理,涉及到的代码有:
/frameworks/base/services/sensorservice/SensorService.cpp
/frameworks/base/services/sensorservice/SensorDevice.cpp
/frameworks/base/services/sensorservice/SensorInterface.cpp
/frameworks/base/core/jni/android/hardware/jni/android_hardware_SensorManager.cpp
/frameworks/base/core/java/android/hardware/SensorManager.java
首先在这里我先声明下,网上关于这部分的资料很多,不过都大同小异,而且大部分是android2.2的分析,但是到了2.3之后sensor这边改了很多代码,一开始我也看的很迷糊的。这里我只是阐述了我的理解,可能是有问题的,希望有识之士可以指出,这边我也只能粗略的介绍了,能力有限。
在上一篇文章中介绍了在SensorDevice.cpp中使用hw_get_module来获得HAL层编译出来的sensor.goldfish.so:
- SensorDevice::SensorDevice()
- : mSensorDevice(0),
- mSensorModule(0)
- {
- status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&mSensorModule);
- LOGE_IF(err, "couldn't load %s module (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
- if (mSensorModule) {
- err = sensors_open(&mSensorModule->common, &mSensorDevice);
- LOGE_IF(err, "couldn't open device for module %s (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
- if (mSensorDevice) {
- sensor_t const* list;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i<size_t(count) ; i++) {
- mActivationCount.add(list[i].handle, model);
- mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
- }
- }
- }
- }
这就是framework调用到HAL的最最重要的一个接口,接下来的工作可以说就是根据得到的这个地址来找到相应的HAL中定义的hw_device_t结构体中的回调函数作为framework中的api,然后进行“封装”,因为hal中只是poll数据,framework需要对数据处理,以及封装API给android app开发者使用。
- /** 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));
- dev->device.common.tag = HARDWARE_DEVICE_TAG;
- dev->device.common.version = 0;
- dev->device.common.module = const_cast<hw_module_t*>(module);
- dev->device.common.close = poll__close;
- dev->device.activate = poll__activate;
- dev->device.setDelay = poll__setDelay;
- dev->device.poll = poll__poll;
- *device = &dev->device.common;
- status = 0;
- return status;
- }
最主要的还是open,close,activate,setDelay,poll等回调函数。
得到module之后再open,然后就是得到activate,poll等函数进行封装到SensorDevice这个类当中去。最后,service这层是通过SensorInterface.cpp把接口都封装到HardwareSensor这个类中,传送到/frameworks/base/core/jni/android_hardware_SensorManager.cpp中被使用。
大家可以看到其实/frameworks/base/core/jni/android_hardware_SensorManager.cpp就是/frameworks/base/core/java/android/hardware/SensorManager.java的原生代码,其中封装了一些native function给java文件调用,其中对于我们来说最重要的也就是poll函数。
下面是core中的jni函数:
- static jint
- sensors_data_poll(JNIEnv *env, jclass clazz, jint nativeQueue,
- jfloatArray values, jintArray status, jlongArray timestamp)
- {
- sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
- if (queue == 0) {return -1;}
- status_t res;
- ASensorEvent event;
- res = queue->read(&event, 1);
- if (res == -EAGAIN) {
- res = queue->waitForEvent();
- if (res != NO_ERROR)
- return -1;
- res = queue->read(&event, 1);
- }
- if (res < 0)
- return -1;
- jint accuracy = event.vector.status;
- env->SetFloatArrayRegion(values, 0, 3, event.vector.v);
- env->SetIntArrayRegion(status, 0, 1, &accuracy);
- env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);
- return event.sensor;
- }
java层就是调用了这边的这个函数来得到底层的数据,其中比较重要的其实就是
- env->SetFloatArrayRegion(values, 0, 3, event.vector.v);
- env->SetIntArrayRegion(status, 0, 1, &accuracy);
- env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);
设置了value,status,timestamp这三个变量,java和应用层也就是用到了这3个参数来写android app的。
- while (true) {
- // wait for an event
- //+++add log by Jay
- Log.d(TAG, "sensor data poll......");
- final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
- Log.d(TAG, "sensor data poll......value:"+values[0]+values[1]+values[2]);
- int accuracy = status[0];
- synchronized (sListeners) {
- if (sensor == -1 || sListeners.isEmpty()) {
- // we lost the connection to the event stream. this happens
- // when the last listener is removed or if there is an error
- t;span> </span>。。。
接下去我就不分析了,下面就是一些封装,封装,再封装,然后设置sensor的监听器,一般我们修改和跟踪代码就是通过以上介绍的函数中加。
ok,这边android sensor 的framework就粗略的介绍到这边。
下面介绍另外一种方法从driver打通到android framework层,其中会涉及到android server jni和driver中的uevent设置以及监听。
敬请期待。。。
Android模拟器学framework和driver之传感器篇6(Android 通过JNI连接驱动层和framework)
之前,我们已经实现了android HAL层,在android模拟器上移植了一个虚拟的temperature sensor,我之前在模拟器上也移植了backlight,RTC等驱动,都能在应用层得到需要的数据,其实自己想学点东西,给自己布置点任务还是不错的,通过模拟器也可以来学习linux 中的device driver,这部分在今后的博客中我会涉及到,这篇blog我主要是想在之前所做的东西的基础上来实现android 的另外一种架构层的实现。
driver--->framework JNI(server)---->framework JAVA(server)
我们的任务分为如下几个步骤:
=====================================================================
|| 1.在temperature sensor驱动中添加sysfs中添加一个只读的文件让JNI 读数据。
|| 2.在temperature sensor驱动中添加uevent通知user space数据发生了改变需要读取。
|| 3.在android framework中添加jni server读取底层数据,封装操作函数。
|| 4.在android framework中添加uevent observer来监听uevent事件的变化。
|| 5.(可选)在java server中添加系统ACTION,然后编写android apk来接收ACTION。
======================================================================
下面会根据这个步骤来展开我们的学习!!!!!!!
之前的代码可以参照之前的文章。
1.在temperature sensor驱动中添加sysfs中添加一个只读的文件让JNI 读数据。
首先来看的还是驱动,我们在之前的驱动中加入如下代码:
首先是添加value文件节点,可以参照name是如何做的
- static int tempValue;
- static ssize_t temperature_show_value(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%d\n", tempValue);
- }
- static IIO_DEVICE_ATTR(name, S_IRUGO, temperature_show_name, NULL,0);
- static IIO_DEVICE_ATTR(value, S_IRUGO, temperature_show_value, NULL,0);
- static struct attribute *temperature_attributes[] = {
- &iio_dev_attr_name.dev_attr.attr,
- &iio_dev_attr_value.dev_attr.attr,
- NULL
- };
这样的话会生成/sys/bus/iio/devices/device0/value 可以read 这个节点来得到温度值。
2.在temperature sensor驱动中添加uevent通知user space数据发生了改变需要读取。
接下来是uevent的添加,这边先把代码贴上,我们在分析uvent的代码。
- <pre name="code" class="cpp">static void temperature_dev_poll(struct input_polled_dev *dev)
- {
- //++++add uevent in driver
- char *buf;
- char *envp[3];
- sysfs_notify(&dev->input->dev.kobj,NULL, "value");
- buf = kmalloc(32,GFP_ATOMIC);
- if(!buf){
- printk(KERN_ERR "%s kmalloc failed\n", __func__);
- return;
- }
- envp[0] = "NAME=temperature";
- snprintf(buf , 32 , "TEMPERATURE=%d",tempValue);
- envp[1] = buf;
- envp[2] =NULL;
- kobject_uevent_env(&dev->input->dev.kobj,KOBJ_CHANGE,envp);
- kfree(buf);
- //----------
- printk(KERN_INFO "Current Temperature: %d\n",tempValue);
- if((tempValue++)==100)
- tempValue=0;
- input_event(dev->input,EV_ABS,ABS_PRESSURE,tempValue);
- input_sync(dev->input);
- }
其实大家可以看到这边最主要的就是kobject_uevent_env函数,这个函数会通知user space 环境变量发生了变化,然后user space可以通过监听uevent来知道这个时候需要读数据,好,来分析下这个函数:
- /**
- * kobject_uevent_env - send an uevent with environmental data
- *
- * @action: action that is happening
- * @kobj: struct kobject that the action is happening to
- * @envp_ext: pointer to environmental data
- *
- * Returns 0 if kobject_uevent() is completed with success or the
- * corresponding error when it fails.
- */
- int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
- char *envp_ext[])
- {
- struct kobj_uevent_env *env;
- const char *action_string = kobject_actions[action];
- const char *devpath = NULL;
- const char *subsystem;
- struct kobject *top_kobj;
- struct kset *kset;
- struct kset_uevent_ops *uevent_ops;
- u64 seq;
- int i = 0;
- int retval = 0;
- pr_debug("kobject: '%s' (%p): %s\n",
- kobject_name(kobj), kobj, __func__);
- /* search the kset we belong to */
- top_kobj = kobj;
- /*找到其所属的kset容器,如果没找到就从其父kobj找,一直继续下去,直到父kobj不存在*/
- while (!top_kobj->kset && top_kobj->parent)
- top_kobj = top_kobj->parent;
- if (!top_kobj->kset) {
- pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
- "without kset!\n", kobject_name(kobj), kobj,
- __func__);
- return -EINVAL;
- }
- kset = top_kobj->kset;
- uevent_ops = kset->uevent_ops;
- /*回调uevent_ops->filter()函数,我们这边是dev_uevent_filter()函数,主要是检查是否是uevent_suppress*/
- /* skip the event, if the filter returns zero. */
- if (uevent_ops && uevent_ops->filter)
- if (!uevent_ops->filter(kset, kobj)) { //如果不成功,就是uevent_suppress,则直接返回
- pr_debug("kobject: '%s' (%p): %s: filter function "
- "caused the event to drop!\n",
- kobject_name(kobj), kobj, __func__);
- return 0;
- }
- /*回调uevent_ops->name(),来获取bus或者class的名字,这边是iio bus,所以bus的名字是“iio”*/
- /* originating subsystem */
- if (uevent_ops && uevent_ops->name)
- subsystem = uevent_ops->name(kset, kobj);
- else
- subsystem = kobject_name(&kset->kobj);
- if (!subsystem) {
- pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
- "event to drop!\n", kobject_name(kobj), kobj,
- __func__);
- return 0;
- }
- /*获得用于存放环境变量的buffer*/
- /* environment buffer */
- env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
- if (!env)
- return -ENOMEM;
- /*获取该kobj在sysfs的路径,通过遍历其父kobj来获得,这边是/sys/devices/platform/android-temperature*/
- /* complete object path */
- devpath = kobject_get_path(kobj, GFP_KERNEL);
- if (!devpath) {
- retval = -ENOENT;
- goto exit;
- }
- /*添加ACTION环境变量,这边是“change” 命令,这里提供了add,remove,change,move,online,offline六种命令*/
- /* default keys */
- retval = add_uevent_var(env, "ACTION=%s", action_string);
- if (retval)
- goto exit;
- /*添加DEVPATH环境变量,这边是/sys/devices/platform/android-temperature 之后会用到*/
- retval = add_uevent_var(env, "DEVPATH=%s", devpath);
- if (retval)
- goto exit;
- /*添加subsystem环境变量,这里是input*/
- retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
- if (retval)
- goto exit;
- /* keys passed in from the caller */
- if (envp_ext) {
- for (i = 0; envp_ext[i]; i++) {
- retval = add_uevent_var(env, "%s", envp_ext[i]);
- if (retval)
- goto exit;
- }
- }
- //回调uevent_ops->event(),输出一些环境变量
- /* let the kset specific function add its stuff */
- if (uevent_ops && uevent_ops->uevent) {
- retval = uevent_ops->uevent(kset, kobj, env);
- if (retval) {
- pr_debug("kobject: '%s' (%p): %s: uevent() returned "
- "%d\n", kobject_name(kobj), kobj,
- __func__, retval);
- goto exit;
- }
- }
- /*
- * Mark "add" and "remove" events in the object to ensure proper
- * events to userspace during automatic cleanup. If the object did
- * send an "add" event, "remove" will automatically generated by
- * the core, if not already done by the caller.
- */
- if (action == KOBJ_ADD)
- kobj->state_add_uevent_sent = 1;
- else if (action == KOBJ_REMOVE)
- kobj->state_remove_uevent_sent = 1;
- /* we will send an event, so request a new sequence number */
- /*增加event序列号的值,并输出到环境变量的buffer。该序列号可以从sys/kernel/uevent_seqnum属性文件读取*/
- spin_lock(&sequence_lock);
- seq = ++uevent_seqnum;
- spin_unlock(&sequence_lock);
- retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
- if (retval)
- goto exit;
- /*如果配置了网络,那么就会通过netlink socket向用户控件发送环境变量,而用户控件则通过netlink socket接收,然后采取一系列的动作。这种机制目前在udev中,也就是pc机系统中,我们这边不是PC机所以不在分析*/
- #if defined(CONFIG_NET)
- /* send netlink message */
- if (uevent_sock) {
- struct sk_buff *skb;
- size_t len;
- /* allocate message with the maximum possible size */
- len = strlen(action_string) + strlen(devpath) + 2;
- skb = alloc_skb(len + env->buflen, GFP_KERNEL);
- if (skb) {
- char *scratch;
- /* add header */
- scratch = skb_put(skb, len);
- sprintf(scratch, "%s@%s", action_string, devpath);
- /* copy keys to our continuous event payload buffer */
- for (i = 0; i < env->envp_idx; i++) {
- len = strlen(env->envp[i]) + 1;
- scratch = skb_put(skb, len);
- strcpy(scratch, env->envp[i]);
- }
- NETLINK_CB(skb).dst_group = 1;
- retval = netlink_broadcast(uevent_sock, skb, 0, 1,
- GFP_KERNEL);
- } else
- retval = -ENOMEM;
- }
- #endif
- /*对于嵌入式系统来说,busybox采用的是mdev,在系统启动脚本rcS中会使用echo /sbin/mdev > /proc/sys/kernelhotplug命令。。。。*/
- /* call uevent_helper, usually only enabled during early boot */
- if (uevent_helper[0]) {
- char *argv [3];
- argv [0] = uevent_helper;
- argv [1] = (char *)subsystem;
- argv [2] = NULL;
- retval = add_uevent_var(env, "HOME=/");
- if (retval)
- goto exit;
- retval = add_uevent_var(env,
- "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
- if (retval)
- goto exit;
- //呼叫应用程序来处理,UMH_WAIT_EXEC表明等待应用程序处理完
- retval = call_usermodehelper(argv[0], argv,
- env->envp, UMH_WAIT_EXEC);
- }
- exit:
- kfree(devpath);
- kfree(env);
- return retval;
- }
- EXPORT_SYMBOL_GPL(kobject_uevent_env);
这边我们要关注的就是ACTION还有就是环境变量参数,注意,我们这边使用的kobject是input->dev.kobj,所以这边的DEVPATH和SUBSYSTEM都是跟input subsystem有关的。
这里把uevent传到user space了,下面来看user space是怎么做的,涉及的代码有:
hardware/libhardware_legacy/uevent frameworks/base/core/jni/android_os_UEventObserver.cpp frameworks/base/core/java/android/os/UEventObserver.java frameworks/base/services/java/com/android/server/SystemServer.java
这边我提最重要的,就是hardware/libhardware_legacy/uevent/uevent.c 发送一个socket广播把这个uevent事件发送出去
- s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if(s < 0)
- return 0;
- setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
- if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(s);
- return 0;
- }
然后就是在framework中通过jni进行封装,使得java中也能通过sokect来监听uevent。
3.在android framework中添加jni server读取底层数据,封装操作函数。
下面我们来实现在jni中读取文件系统中的节点来获得温度的值。
下面是2个文件的下载地址,一个是jni一个是java(com_android_server_TemperatureObserver.cpp,TemperatureObserver.java)
http://download.csdn.net/detail/zhangjie201412/4049098
其实在这边用到的东西也不是很多,最多就是jni中的一些规则:
在jni中获得java中的域,在jni中注册method函数,在jni中注册等方法,这边很简单,就是open节点,然后读数据,获得java中的变量的fieldID 然后把数据传给java中的变量,最后封装native函数,然后再java中调用。
1.获得java中的域:
- jclass clazz = env->FindClass("com/android/server/TemperatureObserver");
- if(clazz == NULL)
- {
- LOGE("Can't find com/android/server/TemperatureObserver");
- return -1;
- }
- mTemperatureValueID =
- env->GetFieldID(clazz , "mTemperatureValue" , "I");
2.open节点读数据,再把数据传到java的变量中:
- jclass clazz = env->FindClass("com/android/server/TemperatureObserver");
- if(clazz == NULL)
- {
- LOGE("Can't find com/android/server/TemperatureObserver");
- return -1;
- }
- mTemperatureValueID =
- env->GetFieldID(clazz , "mTemperatureValue" , "I");
4.在android framework中添加uevent observer来监听uevent事件的变化。
3.在java中注册uevent监听
- public TemperatureObserver(Context context) {
- mContext = context;
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TemperatureObserver");
- mWakeLock.setReferenceCounted(false);
- //++++add log
- Slog.v(TAG,"------Struct function....");
- / startObserving("EVENT=temperature");
- startObserving(TEMPERATURE_UEVENT_MATCH);
- / init(); // set initial status
- }
4.在java中实现onUEvent,并且调用java原生接口
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- if (LOG) Slog.v(TAG, "Temperature UEVENT: " + event.toString());
- try {
- update(event.get("NAME"), Integer.parseInt(event.get("TEMPERATURE")));
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Could not parse switch state from event " + event);
- }
- }
- private native void native_temperature_update();
- private synchronized final void update(String newName, int newValue){
- if(LOG)
- Slog.v(TAG,"NAME: "+newName+" VALUE: "+newValue);
- native_temperature_update();
- Slog.v(TAG,"-----value-----"+mTemperatureValue);
- }
至此,我们的分析就结束了,关于jni的用法我就不多说了,提供一些链接,大家可以拿作参考:
http://blog.csdn.net/thl789/article/details/7212822
http://blog.csdn.net/furongkang/article/details/6857610
这一部分到此结束,希望写的这些对大家有点帮助。
- Android模拟器学framework和driver之传感器篇
- Android模拟器学framework和driver之传感器篇1(linux sensor driver)
- Android模拟器学framework和driver之传感器篇1(linux sensor driver)
- Android模拟器学framework和driver之传感器篇5(Android framework)
- Android模拟器学framework和driver之传感器篇5(Android framework)
- Android模拟器学framework和driver之传感器篇3(Android HAL)
- Android模拟器学framework和driver之传感器篇4(Android APP)
- Android模拟器学framework和driver之传感器篇3(Android HAL)
- Android模拟器学framework和driver之传感器篇4(Android APP)
- Android模拟器学framework和driver之传感器篇(Android HAL)
- Android模拟器学framework和driver之传感器篇3(Android HAL)
- Android模拟器学framework和driver之传感器篇0(导读)
- Android模拟器学framework和driver之传感器篇2(生成测试tool)
- Android模拟器学framework和driver之传感器篇2(生成测试tool)
- Android模拟器学framework和driver之传感器篇0(导读)
- Android模拟器学framework和driver之传感器篇6(Android 通过JNI连接驱动层和framework)
- Android模拟器学framework和driver之传感器篇6(Android 通过JNI连接驱动层和framework)
- Android模拟器学framework和driver之传感器篇6(Android 通过JNI连接驱动层和framework)
- windows下cvs服务器安装配置
- ejb3+jboss+ant
- OpenGL中的Alpha测试,深度测试,模板测试,裁减测试
- 使用代理下载android系统源码和SDK
- zoj 3204
- Android模拟器学framework和driver之传感器篇
- 小工具:assembly中嵌入图片抓取器(C#)
- JQuery加载并解析XML
- 锐捷密码忘了!->锐捷密码查看器
- AS3 RadioButton ---- 单选框控件
- EJB3 Persistence 对象
- 在存储过程中执行存储过程
- System Center 2012 Configuration Manager
- 通过持续集成尽早发现缺陷(全面指导您创建最合适的 CI 环境)