您当前的位置: 首页 > 
  • 3浏览

    0关注

    417博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

06.输入系统:第10课第4节_输入系统_Reader线程_使用EventHub读取事件

江南才尽,年少无知! 发布时间:2019-03-05 23:42:33 ,浏览量:3

在前面的学习中,我们分析了android输入子系统的框架,知道他会存在Reader与Dispatcher两个线程,Reader是循环读取驱动事件,并且监测是否有输入设备拔插,我们可以想象一下Reader线程会做哪些事情,我们可以简单的认为他是获取事件,然后把这个事件发送给Dispatcher,其中还包括了一些简单的处理。简单的框图如下: 在这里插入图片描述 再次粘贴一下上小节的总框图 在这里插入图片描述 在右下角我们可以看到如下 在这里插入图片描述 可以知道最终调用了mReader->loopOnce,其处于inputReader.cpp文件,打开该文件,找到loopOnce函数,

void InputReader::loopOnce() {
	size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //获取事件
		if (count) {
         	processEventsLocked(mEventBuffer, count); //处理事件
    mQueuedListener->flush();//把这些事件刷送给Dispatcher线程
	    

接下来的几个小节将围绕

1.Reader线程_使用EventHub读取事件
2.Reader线程_处理事件
3.Reader线程_送Dispatcher线程发送事件

下面我们开始:mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);,该函数获取的事件存放在mEventBuffer中,其为一个RawEvent mEventBuffer[EVENT_BUFFER_SIZE]数组,并且RawEvent为:

struct RawEvent {
    nsecs_t when;
    int32_t deviceId;
    int32_t type;
    int32_t code;
    int32_t value;
};

其中的int32_t type可以取值如下: 在这里插入图片描述 在之前的小节中,做了一个模拟的输入设备,其上报的类型为input_event区中程序

struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

把上面的的内容整理成框图如下: 在这里插入图片描述 红线部分代表应用层,红线下方代表驱动层,在应用层,InputReader.cpp中通过mEventHub->getEvents获取的是struct RawEvent类型,驱动获取上报的为struct input_event,可以知道在mEventHub->getEvents中,会把驱动上报的input_event构造成RawEvent,那么mEventHub是怎么检测输入设备的拔插的呢?在前面介绍过inotify和epoll_P,通过对目录或者文件的监测,实现热插拔,这里也是利用了同样的原理: 1.使用inotify监测/dev/input目录。 2.使用epoll监测有无数据。 当有设备接入的时候,mEventHub->getEvents就会构造一个RawEvent其中type为DEVICE_ADDED 当有设备一出的时候,mEventHub->getEvents就会构造一个RawEvent其中type为DEVICE_REMOVE 如果真的又数据可读,进行了上报,那么他就会构造其具体的input_event事件,与驱动一一对应,在驱动层是没有办法实现热插拔的,所以把驱动层传来的input_event进行了少许修改,从而实现热插拔。

下面我们开始阅读以下源代码:在InputReader.cpp文件中,找到之前的mEventHub->getEvents,那么mEventHub是什么?查看其定义sp mEventHub,可知道他是EventHub类型。我们打开EventHub.cpp,查看其构造函数:

EventHub::EventHub(void) :
	mEpollFd = epoll_create(EPOLL_SIZE_HINT);//创建mEpollFd
	mINotifyFd = inotify_init();
	/*监测DEVICE_PATH = "/dev/input"目录*/ 
	inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

我们再查看mEventHub->getEvents,根据前面的分析,他应该去扫描"/dev/input"目录下的每一个节点。

EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
	for (;;) {
	    ALOG_ASSERT(bufferSize >= 1);
	    if (mNeedToScanDevices) {
	    	scanDevicesLocked(); //扫描目录
	    		scanDirLocked(DEVICE_PATH); //扫描目录
	    			while((de = readdir(dir))) { //读取目录
	    				openDeviceLocked(devname);//处理其中每一个设备节点
	    					open(devicePath, O_RDWR | O_CLOEXEC);//打开设备文件
	    					ioctrl()....//调用一系列的ioctrl(),稍后再进行分析
	    					ioctrl()....
	    					if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {//添加到epoll中进行监测,
	   	pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, 	timeoutMillis);//等待驱动程序响应,或者等待监测文件动作
   

我们回到void InputReader::loopOnce() 中,既然他调用epoll_ctl,对那些设备进行了监测,那么他肯定会调用epoll_wait,等待驱动程序响应。当响应之后,该循环完成一次,可以想象,当增加或者删除了一个节点,在这个循环中,肯定做了对应的处理:

EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
	for (;;) {
		while (mPendingEventIndex = mPendingEventCount) {
            mPendingINotify = false;
            readNotifyLocked();
            	read(mINotifyFd, event_buf, sizeof(event_buf));//读取这个目录
            	while(res >= (int)sizeof(*event)) {
            		 if(event->mask & IN_CREATE) {//判断是删除还是增加了设备,做出相应动作。				
            		 	openDeviceLocked(devname);//如果创建设备,打开该设备,加入epoll		
            		 else
            		 	closeDeviceByPathLocked(devname);//如果删除设备,则从epoll中移除该设备
            deviceChanged = true;
        }

我们再次重新回到void InputReader::loopOnce() 中,如果没有设备节点增加或者删除,那么就是有数据来了:

EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
	for (;;) {
		deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
			readSize = read(device->fd, readBuffer,sizeof(struct input_event) * capacity);
            event->deviceId = deviceId;
            event->type = iev.type;
            event->code = iev.code;
            event->value = iev.value;	

我们可以看到,把数据读取到了struct input_event中,则就是内核中原始的上报的数据。然后构造成一个RawEvent* event。 这样我们就分析完成了。其逻辑如下: 在这里插入图片描述

关注
打赏
1592542134
查看更多评论
立即登录/注册

微信扫码登录

0.0383s