2、EventHub

InputManager的初始化可知,EventHub是NativeInputManager的构造函数中创建的。

@framework/base/services/core/jni/com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) {
    ...
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

本节将详细介绍EventHub的具体实现。

先看看构造函数:

@frameworks/native/services/inputflinger/EventHub.cpp

 EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {

    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    mINotifyFd = inotify_init();
    int result = inotify_add_watch(mINotifyFd, "/dev/input", IN_DELETE | IN_CREATE);

    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);
}

除了监控Input设备节点的添加和删除,EventHub还会监控一个pipe读端文件,这提供了一个唤醒EventHub的epoll的方法。

因为InputReader在没有event事件的时候也需要被唤醒,来处理其他事务,这种情况后续会提到。

 

InputReader会在每次loop时,都会调用EventHub的getEvents来获取input事件:

@frameworks/native/services/inputflinger/InputReader.cpp

void InputReader::loopOnce() {
    ...
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);   // 在没有input事件时,会block在这里
    ...
    if (count) {
        processEventsLocked(mEventBuffer, count);
    }
    ...
    mQueuedListener->flush();

}

 

getEvents()实现主要分两部分:

1、打开和关闭设备

2、接收input事件

完整代码如下:

@frameworks/native/services/inputflinger/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    AutoMutex _l(mLock);
    struct input_event readBuffer[bufferSize];
    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // Reopen input devices if needed.
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;
            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

        // Report any devices that had last been added/removed.
        while (mClosingDevices) {
            Device* device = mClosingDevices;
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            // 设备的打开和关闭的事件
            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                }
                continue;
            }
            // 唤醒事件,需要跳出循环,让InputReader处理其他的事务(更新配置信息)
            if (eventItem.data.u32 == EPOLL_ID_WAKE) {
                if (eventItem.events & EPOLLIN) {
                    awoken = true;
                    char buffer[16];
                    ssize_t nRead;
                    do {
                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
                }
                continue;
            }

            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,  sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    ...
                } else if (readSize < 0) {
                    ...
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ...
                } else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL  + nsecs_t(iev.time.tv_usec) * 1000LL;
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            }
        }
        ...
        // 打开和关闭设备的事件
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }

        // Report added or removed devices immediately.
        if (deviceChanged) {
            continue;
        }

        // 如果读取到event或被InputReader有其他事务要处理,则跳出循环
        if (event != buffer || awoken) {
            break;
        }
        mPendingEventIndex = 0;
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
        ...
        mPendingEventCount = size_t(pollResult);
    }

    // All done, return the number of events we read.
    return event - buffer;
}

EventHub的构造函数中mNeedToScanDevices的初始值为true,所以第一次进入getEvents时,会扫描设备目录("/dev/input")。

@frameworks/native/services/inputflinger/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    AutoMutex _l(mLock);
    ...
    for (;;) {
        ...
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }
        ...
}

void EventHub::scanDevicesLocked() {
    status_t res = scanDirLocked("/dev/input");
    ...
}

status_t EventHub::scanDirLocked(const char *dirname)
{
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    //扫描/dev/input/目录下的设备节点
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&  (de->d_name[1] == '\0' ||  (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
}

status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];

    int fd = open(devicePath, O_RDWR | O_CLOEXEC);

    // 构建identifier
    InputDeviceIdentifier identifier;
    if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.name.setTo(buffer);
    }
    ...
    identifier.vendor = inputId.vendor;
    identifier.version = inputId.version;
    ...

    // 设置成NONBLOCK
    fcntl(fd, F_SETFL, O_NONBLOCK)) ;

   // 分配设备ID,并创建Device对象
    int32_t deviceId = mNextDeviceId++;
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
    ...

    // 将设备注册到epoll监控列表中
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = deviceId;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
    }
    ...
    addDeviceLocked(device);
    return 0;
}

void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device);
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

从上面的openDeviceLocked()函数中可以看到,

这里打开"/dev/input/"目录下的input设备后,将其注册到epoll的监控队列中。

这样一旦对应设备上有可读的input事件,则epool_wait()就会返回,并带会deviceid。

而每个设备都是用addDeviveLocked()将对应设备以deviceid为索引加入到mDevices中,

因此我们可以用epoll_wait()返回的deviceid,找到具体的device:

@frameworks/native/services/inputflinger/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    AutoMutex _l(mLock);
    struct input_event readBuffer[bufferSize];
    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        ...

        while (mPendingEventIndex < mPendingEventCount) {

            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            // eventItem.data.u32既是deviceid
            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                // 从device中得到fd后再去读设备,获取input事件
                int32_t readSize = read(device->fd, readBuffer,  sizeof(struct input_event) * capacity);


                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    ...
                } else if (readSize < 0) {
                    ...
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ...
                } else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL  + nsecs_t(iev.time.tv_usec) * 1000LL;
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            }
        }
        ...
        mPendingEventIndex = 0;
        // 等待input事件
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
        ...
        mPendingEventCount = size_t(pollResult);
    }
}

除了具体的input事件,设备的打开关闭等信息,也要包装成event,上报给InputReader:

@frameworks/native/services/inputflinger/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ...
    for (;;) {
        ...
        while (mClosingDevices) {
            Device* device = mClosingDevices;
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
           ...
        }

  }
}

EventHub是InputReader用于打开和关闭Input设备,监听和读取Input事件的对象。

 

下一节将介绍InputReader处理EventHub中的Event的流程。

 

posted on 2020-04-20 17:24  EMH1899  阅读(321)  评论(0)    收藏  举报

导航