Android层面上对sensor及event事件的处理
时间:2023-11-21 21:37:01
也许这个总结会有点凌乱,以后再讲sensor,一会又讲event是的。但把两者放在一起也是有原因的,sensor的处理是event正是因为在事件的基础上为sensor对event依赖,所以把两者放在一起。仔细想想,还是有原因的。
开始前先说明两点。
1、这里说的android层面上是linux内核之上的
2、sensor指的是gsensor,lightsensor等
下面正式开始,先简单说一下驱动中的处理。一般来说,驱动通常是通过的i2c来获取sensor当然,设备数据中有中断机制。然后通过input_event,input_sync等函数报告事件。报告的数据无疑写在设备节点(/dev/input/event*)。接下来是看android层次处理。
在android从层面上看,先看BoardConfig.mk
62 #BOARD_HAS_SENSOR := true
很明显,这是一个可配置的选项,意思也很清楚,配置,意味着sensor的相关的代码会被编译。接下来我们看看解析这个配置的地方:hardware其中一个Android.mk
ifeq ($(BOARD_HAS_SENSOR),true) 28 LOCAL_SRC_FILES := \ 29 sensors.cpp \ 30 SensorBase.cpp \ 31 LightSensor.cpp \ 32 AccelSensor.cpp \ 33 MagSensor.cpp \ 34 PressSensor.cpp \ 35 InputEventReader.cpp
我们可以看到31-34是:光感、加速度、磁性和压力。它也是可选的,可以根据您的实际使用情况使用sensor添加或删除。在这里,我们主要关注SensorBase.cpp,看下面的代码
145 int SensorBase::openInput(const char* inputName) { 146 int fd = -1; 147 int input_id = -1; 148 const char *dirname = "/dev/input"; 149 const char *inputsysfs = "/sys/class/input"; 150 char devname[PATH_MAX]; 151 char *filename; 152 DIR *dir; 153 struct dirent *de; 154 155 dir = opendir(dirname); 156 if(dir == NULL) 157 return -1; 158 strcpy(devname, dirname); 159 filename = devname strlen(devname); 160 *filename = '/'; 161 while((de = readdir(dir))) { 162 if(de->d_name[0] == '.' && 163 (de->d_name[1] == '\0' || 164 (de->d_name[1] == '.' && de->d_name[2] == '\0'))) 165 continue; 166 strcpy(filename, de->d_name); 167 fd = open(devname, O_RDONLY); 168 169 if (fd>=0) { 170 char name[80]; 171 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { 172 name[0] = '\0'; 173 } 174 175 if (!strcmp(name, inputName)) { 176 strcpy(input_name, filename); 177 break; 178 } else { 179 close(fd); 180 fd = -1; 181 } 182 } 183 } 184 closedir(dir); 185 ALOGE_IF(fd<0, "couldn't find '%s' input device", inputName); 186 return fd; 187 }
首先是定义event节点目录:
148 const char *dirname = "/dev/input";
然后打开这个目录,得到它event*,真正的报告数据是从event*在此之前,为了给程序足够的访问权限event*节点,在ueventd.$VENDOR.rc 设置节点分析权限:
25 /dev/input/event2 0666 root input 26 /dev/input/event0 0666 root input
这跟android下getevent这个命令的用法是一样的,我们通常在android串口命令行输入getevent 命令将在串口终端打印event如果用户触发报告数据,则在终端命令行中输出相应的报告数据。
root@rom_3420:/# getevent
couldnot get driver version for /dev/input/mice, Not a typewriter
adddevice 1: /dev/input/event1
name:"matrix-keypad"
adddevice 2: /dev/input/event0
name:"gpio-keys"
有兴趣的客户自己研究getevent代码,位于android源码目录下的:system/core/toolbox/getevent.c读取上报数据的位置在里面main在函数中,使用轮询机制读取数据的,如下:
631 while(1) { 632 pollres = poll(ufds, nfds, -1);
处理过程与上述处理过程相同。hardware读取过程相同,EventHub里面读取到event之后对这些数据进行分类,然后分发到各种线程的控制器中进行最终处理。key,有key处理控制器跟线程;touch,有touch控制器跟线程。
但说到这里,可能会有这样一个问题:问什么?android不把sensor还放置了数据eventHub内部处理,而不是sensor分开处理数据?其实如果有人知道原因,我也有这样的疑惑。但有一点可以确认,在framework里面会对sensor过滤数据是错误的sensor处理数据。如:
frameworks/base/services/input/EventHub.h 200 // Sets devices that are excluded from opening. 201 // This can be used to ignore input devices for sensors. 202 virtual void setExcludedDevices(const Vector& devices) = 0;
和:
frameworks/base/services/input/InputReader.cpp 496 void InputReader::refreshConfigurationLocked(uint32_t changes) { 497 mPolicy->getReaderConfiguratin(&mConfig);
498 mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
其实android的代码里面也表明了,但这样做的原因,如上所说的,不知道为什么这样做。
如果想了解更多的 frameworks/base/services/input里面怎样对数据进行读取和分类的,或者是想了解android对event数据的处理的过程,可以参考下面几个博客:
Android输入事件流程中的EventHub分析及源码演示
http://blog.csdn.net/a345017062/article/details/6417929
Android应用程序键盘(Keyboard)消息处理机制分析
http://www.blogjava.net/mixer-a/archive/2012/04/17/374987.html
http://blog.csdn.net/yangwen123/article/details/14160289
好,说到这里,既然我们知道了android处理event数据的过程,那么,当我们需要的时候,就可以自己定制自己的hardware,来获取,甚至是截取android event数据。说白了,也就是对 /dev/input/ 里面节点信息的截取。说到这里,还想提一提,因为android所有处理event数据都是以轮询的机制来处理的。它不像fifo(管道)的形式,数据一旦被读取了就不见了。如果多个地方等待读取某一event的数据,那么一旦数据过来了,所有在轮询的地方都能获取到数据。而如果我们在截取数据的时候,只想让截取数据的地方获取到数据呢?个人觉得是可以实现的。这方面客户研究一下getevent和setevent的用法。
对event数据的获取就讲到这里,接下来回到sensor的处理中。
在“.mk”我们会看到会拷贝sensor的xml文件:
frameworks/native/data/etc/android.hardware.sensor.light.xml:system/etc/permissions/android.hardware.sensor.light.xml \
frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:system/etc/permissions/android.hardware.sensor.accelerometer.xml \
其实在manager里面就是通过是否存在这样一个xml文件来判断是否有sensor的存在:
frameworks/base/core/java/android/content/pm/PackageManager.java
988 @SdkConstant(SdkConstantType.FEATURE)
989 public static final String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
1013 /**
1014 * Feature for {@link #getSystemAvailableFeatures} and
1015 * {@link #hasSystemFeature}: The device includes a light sensor.
1016 */
1017 @SdkConstant(SdkConstantType.FEATURE)
1018 public static final String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
在device/$VENDOR/$BOARD/required_hardware.xml里面对字符串的定义:
overlay/frameworks/base/core/res/res/values/config.xml里面对光感强度等级的描述:
87 - 20
88 - 30
89 - 40
90 - 50
91 - 60
92 - 70
93 - 80
94 - 130
95 - 180
96 - 255
97 - 255
98 - 255
99
Framework里面会对xml的参数进行解析,具体就不去分析了。这方面还挺有意思,有兴趣可以自行分析。
init.rc里面对相关属性的定义:节点路径和默认光照强度
88 # Set light sensor sysfs path and light sensor threshold lux value
89 setprop ro.hardware.lightsensor "/sys/class/i2c-dev/i2c-2/device/2-0044/"
90 setprop ro.lightsensor.threshold 20
在后在LightSensor.cpp里面会对这两个属性解析解析:
55 property_get("ro.hardware.lightsensor", buffer, "0");
56 strcpy(ls_sysfs_path, buffer);
57 ls_sysfs_path_len = strlen(ls_sysfs_path);
58 enable(0, 1);
59 }
60
光照强度
61 /* Default threshold lux is 10 if ro.lightsensor.threshold
62 isn't set */
63 property_get("ro.lightsensor.threshold", buffer, "10");
64 mThresholdLux = atoi(buffer);
Hardware里面定义好后,接下来是JNI里面导出接口函数:
frameworks\base\core\jni\android_hardware_SensorManager.cpp
在源码里,我们可以看到JNI接口的函数列表:
static JNINativeMethod gMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"sensors_module_init","()I", (void*)sensors_module_init },
{"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I",
(void*)sensors_module_get_next_sensor },
{"sensors_create_queue", "()I", (void*)sensors_create_queue },
{"sensors_destroy_queue", "(I)V", (void*)sensors_destroy_queue },
{"sensors_enable_sensor", "(ILjava/lang/String;II)Z",
(void*)sensors_enable_sensor },
{"sensors_data_poll", "(I[F[I[J)I", (void*)sensors_data_poll },
};
然后,接下来是在framework层面对sensor数据的处理,报错以下几点。这里不着重分析,一般到这里,所有数据都交由系统源码进行处理,这部分我们基本上不会进行修改。
SensorManager.java
实现传感器系统核心的管理类SensorManager
Sensor.java
单一传感器的描述性文件Sensor
SensorEvent.java
表示传感器系统的事件类SensorEvent
SensorEventListener.java
传感器事件的监听者SensorEventListener接口
SensorListener.java
传感器的监听者SensorListener接口
---------------------
版权声明:本文为CSDN博主「little_paul」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hbk320/article/details/47188519