Android系统--输入系统(八)Reader线程_使用EventHub读取事件

Android系统--输入系统(八)Reader线程_使用EventHub读取事件

1. Reader线程工作流程

  • 获得事件

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

  • 简单处理

processEventsLocked(mEventBuffer, count);

  • 将事件分发给Dispatch线程处理

mQueuedListener->flush();

2. Reader线程获得事件分析

2.1 事件结构体描述

struct RawEvent {

    nsecs_t when;

    int32_t deviceId;

    int32_t type;

    int32_t code;

    int32_t value;

};

2.2 事件类型

事件类型type:

  • DEVICE_ADDED(输入设备插入)

  • DEVICE_REMOVED(输入设备被拔出)

  • FINISHED_DEVICE_SCAN(与Device相关的事件)

  • EV_KEY

  • EV_ABS

  • EV_REL

2.3 驱动层上报输入事件


struct input_event{

    struct timeval time;

    __u16 type;

    __u16 code;

    __s32 value;

};

上报事件类型Type:

  • EV_KEY

  • EV_ABS

  • EV_REL

2.4 驱动层上报输入事件给上层概述

当输入设备有数据产生,驱动程序将该事件数据上报,上层的Reader线程将读取驱动程序,获得Input_event结构体,然后将Input_event结构体直接构造成RawEvent结构体进行处理。

3. 输入设备拔插检测实现

3.1 实现原理
  • 使用inotify机制来检测目录下的文件变化

  • 使用epoll机制来检测目录下的文件是否有数据

3.2 实现过程分析
  • 初始化得到文件句柄--fd1 = inotify_init(/dev/input/event0);

  • 检测对象--inotify_add_watch(fd1,目录/文件,创建/删除);

  • 将输入事件加入epoll池中,监听事件行为--add_to_epoll(mINotifyFd, mEpollFd);

由EventHub构造函数实现

EventHub.cpp


EventHub::EventHub(void) :

    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);

    mINotifyFd = inotify_init();

    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",

            DEVICE_PATH, errno);

    struct epoll_event eventItem;

    memset(&eventItem, 0, sizeof(eventItem));

    eventItem.events = EPOLLIN;

    eventItem.data.u32 = EPOLL_ID_INOTIFY;

    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    int wakeFds[2];

    result = pipe(wakeFds);

    mWakeReadPipeFd = wakeFds[0];

    mWakeWritePipeFd = wakeFds[1];

    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);

    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.u32 = EPOLL_ID_WAKE;

    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

}

  • 在ScanDeviceLocked()函数中,实现对设备函数的打开

    • fd2 = open("/dev/input/event1");

    • fd3 = open("/dev/input/event2");

  • 使用epoll_wait检测fd1,fd2,fd3

  • 读取文件句柄,构造RawEvent结构体;getEvent的循环

    • 如果是增加输入设备,还需要open,并将其加入epoll_wait

    • 如果是拔出输入设备,从epoll中删去


if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {

    if (eventItem.events & EPOLLIN) {

        mPendingINotify = true;

}

readNotifyLocked.c


status_t EventHub::readNotifyLocked() {

    res = read(mINotifyFd, event_buf, sizeof(event_buf));

    while(res >= (int)sizeof(*event)) {

        event = (struct inotify_event *)(event_buf + event_pos);

        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");

        if(event->len) {

            strcpy(filename, event->name);

            if(event->mask & IN_CREATE) {

                openDeviceLocked(devname);

            } else {

                ALOGI("Removing device '%s' due to inotify event\n", devname);

                closeDeviceByPathLocked(devname);

            }

        }

        event_size = sizeof(*event) + event->len;

        res -= event_size;

        event_pos += event_size;

    }

    return 0;

}

  • 如果是输入设备有数据,读取Input_event

size_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);

    if (deviceIndex < 0) {

        ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",

        eventItem.events, eventItem.data.u32);

        continue;

    }

    Device* device = mDevices.valueAt(deviceIndex);

    if (eventItem.events & EPOLLIN) {

        int32_t readSize = read(device->fd, readBuffer,

        sizeof(struct input_event) * capacity);

    }

  • 将input_event结构体构造为RawEvent结构体

    event->deviceId = deviceId;

    event->type = iev.type;

    event->code = iev.code;

    event->value = iev.value;

4. 使用EventHub读取事件概述

posted @ 2017-04-21 14:00  lkq1220  阅读(1055)  评论(0编辑  收藏  举报