input之上层

  底层的驱动我们已经分析过了,那这些上报的数据是如何被获得的呢,所以就跑到上层来看看相关的函数。从输入读取线程开始,当一个输入设备插入时,会在/dev/input目录下新增一个文件,然后就会导致inotify发生变化,进而导致阻塞在epoll_wait(mEpollFd)上的EventHub被唤醒,然后读取新增设备的详细信息,打开设备,最后通过epoll该设备文件来达到监听输入设备事件(包括key、touch等)的目的。整个过程由inputReaderRhread线程发起,然后调用EventHub::getEvents函数实现。


  图1读取线程流程图

loopOnce():

运行循环处理的单个迭代,一般读和处理一个来自EventHub的输入信息,这个方法用在输入读取线程(input reader thread)。

virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices):

通知输入读取协议(input reader policy)一些输入设备已经改变并且提供所有当前输入设备的信息。

virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize):

等待事件变得可用并且返回他们,返回后,EventHub获取唤醒锁直到下次调用getEvent

这样是确保设备在被处理的过程中不会睡眠,如果需要设备更长久的不睡眠,那就需要调用者去实现了,超时仅为参考,如果设备已经进入睡眠,它仅为超时服务而不会醒来。返回事件的编号,如果超时返回0。

AutoMutex _l(mLock):

自动互斥锁,在函数的开头声明,当函数返回后将释放这个锁。


图2刷新配置

getReaderConfiguration:

获取输入读取器(intput reader)的配置

setExcludedDevices:

设置不被打开的设备,可以用来忽略传感器的输入设备。

requestReopenDevices:

要求EventHub在下次调用getEvents的时候重新打开所有的输入设备。

mContext->getPolicy()->getKeyboardLayoutOverlay:

获得输入设备的键盘布局

mContext->getEventHub()->setKeyboardLayoutOverlay

设置键盘布局

mContext->getPolicy()->getDeviceAlias:

获取用户提供的输入设备的别名,如果没有的话就是空。


  下面主要看一下getEvents这个函数:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {

  .........

AutoMutex _l(mLock);

//添加锁,当函数返回时释放锁。

  ..........

    for (;;) {

        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  //获取当前时间

      

        if (mNeedToReopenDevices) {   // 重新打开设备

            mNeedToReopenDevices = false;

 

            ALOGI("Reopening all input devices due to a configuration change.");

 

            closeAllDevicesLocked();

            mNeedToScanDevices = true;

            break; 

        }

 

        // 报告上次添加或移除的设备

        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;

            }

        }

    //查询设备,后面分析scanDevicesLocked()

        if (mNeedToScanDevices) {

            mNeedToScanDevices = false;

            scanDevicesLocked();

            mNeedToSendFinishedDeviceScan = true;

        }

    //打开设备

        while (mOpeningDevices != NULL) {

            Device* device = mOpeningDevices;

            ALOGV("Reporting device opened: id=%d, name=%s\n",

                 device->id, device->path.string());

            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) {

            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];  //读取事件

            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {   //是否有设备新增删除事件

                if (eventItem.events & EPOLLIN) {

                    mPendingINotify = true;

                } else {

                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);

                }

                continue;

            }

 

            if (eventItem.data.u32 == EPOLL_ID_WAKE) {   //处理唤醒事件

                if (eventItem.events & EPOLLIN) {

                    ALOGV("awoken after wake()");

                    awoken = true;

                    char buffer[16];

                    ssize_t nRead;

                    do {

                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));   //读取事件信息

                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));

                } else {

                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",

                            eventItem.events);

                }

                continue;

            }

 

            ssize_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);   //读取设备输入事件的信息

                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {

                    // 在inotify提示前移除设备,关闭设备。

                   

                    deviceChanged = true;

                    closeDeviceLocked(device);  //关闭设备

                } else if (readSize < 0) {

                    if (errno != EAGAIN && errno != EINTR) {

                        ALOGW("could not get event (errno=%d)", errno);

                    }

                } else if ((readSize % sizeof(struct input_event)) != 0) {

                    ALOGE("could not get event (wrong size: %d)", readSize);

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

                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",

                                device->path.string(),

                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,

                                iev.type, iev.code, iev.value);

 

      //一些输入设备有更强的时间观,当一个输入设备产生后就会在evdev里面加一个时间戳,这是安卓扩展的输入协议的一个定制,主要是用于基础设备驱动

                        if (iev.type == EV_MSC) {

                            if (iev.code == MSC_ANDROID_TIME_SEC) {

                                device->timestampOverrideSec = iev.value;

                                continue;

                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {

                                device->timestampOverrideUsec = iev.value;

                                continue;

                            }

                        }

                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {

                            iev.time.tv_sec = device->timestampOverrideSec;

                            iev.time.tv_usec = device->timestampOverrideUsec;

                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {

                                device->timestampOverrideSec = 0;

                                device->timestampOverrideUsec = 0;

                            }

                            ALOGV("applied override time %d.%06d",

                                    int(iev.time.tv_sec), int(iev.time.tv_usec));

                        }

 

                         //使用指定的而不是当前时间的事件,使得下游代码可以得到更准确的事件排队进入evdev客户端的调度等待时间

                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL

                                + nsecs_t(iev.time.tv_usec) * 1000LL;

                        ALOGV("event time %" PRId64 ", now %" PRId64, event->when, now);

 

                        if (event->when >= now + 10 * 1000000000LL) {

                            // Double-check.  Time may have moved on.

                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);

                            if (event->when > time) {

                                ALOGW("An input event from %s has a timestamp that appears to "

                                        "have been generated using the wrong clock source "

                                        "(expected CLOCK_MONOTONIC): "

                                        "event time %" PRId64 ", current time %" PRId64

                                        ", call time %" PRId64 ".  "

                                        "Using current time instead.",

                                        device->path.string(), event->when, time, now);

                                event->when = time;

                            } else {

                                ALOGV("Event time is ok but failed the fast path and required "

                                        "an extra call to systemTime: "

                                        "event time %" PRId64 ", current time %" PRId64

                                        ", call time %" PRId64 ".",

                                        event->when, time, now);

                            }

                        }

                        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;

                    }

                }

            } else if (eventItem.events & EPOLLHUP) {

                ALOGI("Removing device %s due to epoll hang-up event.",

                        device->identifier.name.string());

                deviceChanged = true;

                closeDeviceLocked(device);

            } else {

                ALOGW("Received unexpected epoll event 0x%08x for device %s.",

                        eventItem.events, device->identifier.name.string());

            }

        }


  //真正处理设备新增删除事件,readNotify()将修改设备列表,所以处理完所有事件后一定要执行下面操作,以确保在关闭设备之前读取所有剩余的设备。

        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {

            mPendingINotify = false;

            readNotifyLocked();

            deviceChanged = true;

        }

 

        // 立即上报增加或者删除的事件

        if (deviceChanged) {

            continue;

        }

 

        // Return now if we have collected any events or if we were explicitly awoken.

  //如果收到任何事件或者被唤醒,立刻返回

        if (event != buffer || awoken) {

            break;

        }

 

        mPendingEventIndex = 0;

 

        mLock.unlock();   // 在轮询前释放锁,必须在release_wake_lock前面

        release_wake_lock(WAKE_LOCK_ID);

 

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);  //等待事件

 

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

        mLock.lock(); //在轮询后加锁,必须在 acquire_wake_lock后面

 

        if (pollResult == 0) {

            // 轮询超时

            mPendingEventCount = 0;

            break;

        }

 

        if (pollResult < 0) {

            // 发生错误

            mPendingEventCount = 0;

 

            // 遇到报错后进入睡眠

            if (errno != EINTR) {

                ALOGW("poll failed (errno=%d)\n", errno);

                usleep(100000);

            }

        } else {

            // 有事件发生

            mPendingEventCount = size_t(pollResult);

        }

    }

 

    // 到此结束,返回我们读取的事件编号

    return event - buffer;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值