==========================================================
第三部分:input上報流程-EventHub
==========================================================
//構造函數
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false)//不重新打開設備, mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//創建epoll對象,mEpollFd為epoll對象的描述符
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
//創建inotify對象,mINotifyFd為inotify對象的描述符
mINotifyFd = inotify_init();
//DEVICE_PATH值為"/dev/input",監聽該目錄下的設備節點創建與刪除操作。通過read函數讀取事件。
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
eventItem.events = EPOLLIN; //監聽可讀事件
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//EPOLL_CTL_ADD表示增加事件
//epoll_ctl將事件監聽添加到epoll對象中去。
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
}
//核心函數(讀取/dev/input/event*的數據
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; //容量大小為256
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
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;
}
}
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
//從mPendingEventItems讀取事件項
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//獲取設備ID所對應的device
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (eventItem.events & EPOLLIN) {
//從設備不斷讀取事件,放入到readBuffer
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// 設備被移除,關閉設備
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++) {
//獲取readBuffer的數據
struct input_event& iev = readBuffer[i];
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;
}
}
//事件時間相關計算,時間的錯誤可能會導致ANR和一些bug。這裡採取一系列的防範
//將input_event信息, 封裝成RawEvent
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
//每到我們計算完一個事件,capacity就會減1,如果為0。則表示 結果緩衝區已經滿了,
//需要重置開始讀取時間的索引值,來讀取下一個事件迭代
mPendingEventIndex -= 1;
break;
}
}
//表明讀到事件了,跳出循環
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
//等待input事件的到來
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
if (pollResult == 0) {
mPendingEventCount = 0;
break;
}
//判斷是否有事件發生
if (pollResult < 0) {
mPendingEventCount = 0;
} else {
//產生的事件的數目
mPendingEventCount = size_t(pollResult);
}
}
//返回所讀取的事件個數
return event - buffer;
}
||
||
void EventHub::scanDevicesLocked() {
//此處DEVICE_PATH="/dev/input"
//【函數定義如下】
status_t res = scanDirLocked(DEVICE_PATH);
}
||
||
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);
InputDeviceIdentifier identifier;
//獲取設備名
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1){
} else {
buffer[sizeof(buffer) - 1] = '\\0';
identifier.name.setTo(buffer);
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
//獲取設備物理地址
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
} else {
buffer[sizeof(buffer) - 1] = '\\0';
identifier.location.setTo(buffer);
}
//獲取設備唯一ID
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
} else {
buffer[sizeof(buffer) - 1] = '\\0';
identifier.uniqueId.setTo(buffer);
}
//將identifier信息填充到fd
assignDescriptorLocked(identifier);
//設置fd為非阻塞方式
fcntl(fd, F_SETFL, O_NONBLOCK);
//獲取設備ID,分配設備對象內存
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;
if (mUsingEpollWakeup) {
eventItem.events |= EPOLLWAKEUP;
}
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
delete device; //添加失敗則刪除該設備
return -1;
}
addDeviceLocked(device);
}
閱讀更多 AIOT小學生 的文章