Android input子系統-(3)

==========================================================

第三部分: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);

}


分享到:


相關文章: