zoukankan      html  css  js  c++  java
  • 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"
    ", 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
    ", 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读取事件概述

  • 相关阅读:
    npm version patch
    nginx 操作
    基于 Vue CLI 组件库封装,按需加载实现
    nginx 配置文件路径获取
    Laravel 生产资源路由并指定模型
    base.js,通用js方法,Js方法封装
    jquery.params.js,Jquery获取页面参数,js获取页面参数
    layui使用,LayUI select不显示,LayUI文件上传,Layui自定义校验规则
    Layer弹窗消息封装,Layer消息提示封装,Layer使用
    Html跨域js封装,前端页面跨域js,postMessage实现跨域
  • 原文地址:https://www.cnblogs.com/lkq1220/p/6743279.html
Copyright © 2011-2022 走看看