底层的驱动我们已经分析过了,那这些上报的数据是如何被获得的呢,所以就跑到上层来看看相关的函数。从输入读取线程开始,当一个输入设备插入时,会在/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;
}
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;
}