受不了xxxx恶心人的行为,遂搬迁至博客园。 始发:2016-12-16 13:09:58 版本信息: Linux:3.10 Android:4.4
一、提纲挈领
EventHub是Android中Input事件的处理中心,完成kernel上报事件的读取、初步处理、传递。
读取:Input设备一旦产生动作,将通过事件(Event)的方式通知user空间;user空间通过读取/dev/input目录下各个文件,获取事件及事件所属的Input设备信息:
初步处理:kernel是以struct input_event的格式上报数据,这里只是根据读取的该结构体做一个简单的封装,成RawEvent形式的数据:
struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; }; struct RawEvent { nsecs_t when; int32_t deviceId; int32_t type; int32_t code; int32_t value; };
传递:RawEvent形式的数据传递给InputReader,由它进一步细分为Android可以识别的数据形式。
二、处理流程
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); AutoMutex _l(mLock); struct input_event readBuffer[bufferSize]; RawEvent* event = buffer; size_t capacity = bufferSize; bool awoken = false; ALOGI("getEvents, enter."); for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // 1、mNeedToReopenDevices = false if (mNeedToReopenDevices) { ALOGI("getEvents, mNeedToReopenDevices."); mNeedToReopenDevices = false; ALOGI("Reopening all input devices due to a configuration change."); closeAllDevicesLocked(); mNeedToScanDevices = true; break; // return to the caller before we actually rescan } // 2、mClosingDevices == null while (mClosingDevices) { Device* device = mClosingDevices; ALOGI("getEvents, Reporting device closed: id=%d, name=%s ", device->id, device->path.string()); 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; } } // 3、EventHub对象构建时设置true if (mNeedToScanDevices) { ALOGI("getEvents, mNeedToScanDevices."); mNeedToScanDevices = false; // 4、扫描"/dev/input"目录,若属于我们需要监测的Input设备,就把它加入监测List // 详见“Input设备open流程” scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } // 5、遍历mOpeningDevices列表,把设备的一些信息打包进RawEvent对象中 while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; ALOGW("getEvents, Reporting device opened: id=%d, name=%s ", 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; // 启动构建下一个RawEvent对象 mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } // 6、添加一个FINISHED_DEVICE_SCAN类型的RawEvent对象 if (mNeedToSendFinishedDeviceScan) { ALOGW("getEvents, 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; ALOGW("getEvents: before while, mPendingEventIndex=%d ", mPendingEventIndex); // 8、有事件,去处理 // mPendingEventCount:等待处理的事件的个数 // mPendingEventIndex:指示当前需要处理的事件 while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; ALOGW("getEvents: #1 mPendingEventIndex=%d ", mPendingEventIndex); // EPOLL_ID_INOTIFY:用于监控某个目录(子目录)下是否有新增或者删除文件,在这里用于监视/dev/input // 如果有新增设备,则会在该目录内创建新文件; // 如果删除设备,则该目录的相应文件会被删除。 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; } // EPOLL_ID_WAKE:EventHub维护一个pipe,当pipe的写入端按照适当格式写入事件后, // getEvents可以通过pipe的读取端获取这个虚拟事件 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; } // 9、当前事件属于的Input设备 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; } // 10、获取当前事件属于的Input设备 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)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " "capacity: %d errno: %d) ", device->fd, readSize, bufferSize, capacity, errno); 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 { // 11、正式开始处理device设备的Input事件 int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; // 12、Input事件,即input_event个数 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); // EV_MSC:其他事件,如果一个事件类型用其他EV_*无法描述时,定义为EV_MSC类型 // 对于kernel,它为所有Input事件打上的时间戳(timestamps)比较笼统(比如仅有一个秒数); // 而有的设备(比如uinput设备,详见博客末尾注释“Linux uinput设备”)可能定义一个更加详尽的时间信息, // 比如秒、毫秒、微妙 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; } ALOGI("applied override time %d.%06d", int(iev.time.tv_sec), int(iev.time.tv_usec)); } #ifdef HAVE_POSIX_CLOCKS // 使用之前read函数读出的时间值作为when成员的数值, // 而不是当前时间(通过systemTime(SYSTEM_TIME_MONOTONIC)函数获取的时间值) // 这样事件的时间信息会更加精确,因为这个时间(CLOCK_MONOTONIC)是事件产生时driver立即打上去的 event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL; ALOGI("event time %lld, now %lld", event->when, now); // 避免kernel因时钟错误而上报一个发生在future的事件 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 %lld, current time %lld, call time %lld. " "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 %lld, current time %lld, call time %lld.", event->when, time, now); } } #else // 如果不支持HAVE_POSIX_CLOCKS时钟,则用当前时间作为when成员的值 event->when = now; #endif event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1; capacity -= 1; ALOGW("getEvents, code=%d ", event->code); ALOGW("getEvents, value=%d ", event->value); } if (capacity == 0) { // The result buffer is full. Reset the pending event index // so we will try to read the device again on the next iteration. mPendingEventIndex -= 1; ALOGW("getEvents: #2 mPendingEventIndex=%d ", mPendingEventIndex); 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() will modify the list of devices so this must be done after // processing all other events to ensure that we read all remaining events // before closing the devices. ALOGW("mPendingEventIndex=%d ", mPendingEventIndex); ALOGW("mPendingEventCount=%d ", mPendingEventCount); if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { ALOGW("getEvents, readNotifyLocked."); mPendingINotify = false; readNotifyLocked(); deviceChanged = true; } // Report added or removed devices immediately. if (deviceChanged) { continue; } // Return now if we have collected any events or if we were explicitly awoken. if (event != buffer || awoken) { break; } // Poll for events. Mind the wake lock dance! // 使用EPoll机制,等待事件到来 // We hold a wake lock at all times except during epoll_wait(). This works due to some // subtle choreography. When a device driver has pending (unread) events, it acquires // a kernel wake lock. However, once the last pending event has been read, the device // driver will release the kernel wake lock. To prevent the system from going to sleep // when this happens, the EventHub holds onto its own user wake lock while the client // is processing events. Thus the system can only sleep if there are no events // pending or currently being processed. // // The timeout is advisory only. If the device is asleep, it will not wake just to // service the timeout. mPendingEventIndex = 0; // 13、mLock:在处理Input事件之前,加锁;处理完成后,解锁 mLock.unlock(); // release lock before poll, must be before release_wake_lock // 14、参见“休眠锁在EventHub中的生命周期” // 在epoll_wait()的时候释放休眠锁,这样系统才能休眠 release_wake_lock(WAKE_LOCK_ID); // 7、等待input事件,成功时epoll_wait() 返回就绪的监测List中的Input事件个数 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); // 15、在设备驱动中,如果driver有处于挂起(pending)状态的事件,它会持有kernel休眠锁阻止系统休眠; // 一旦事件得到处理,driver释放kernel休眠锁,系统可能进入休眠。但是!这个事件user空间还没有处理, // 所以我们获取一个休眠锁,阻止系统系统休眠好让我们处理事件 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock if (pollResult == 0) { // Timed out. mPendingEventCount = 0; break; } if (pollResult < 0) { // An error occurred. mPendingEventCount = 0; // Sleep after errors to avoid locking up the system. // Hopefully the error is transient. if (errno != EINTR) { ALOGW("poll failed (errno=%d) ", errno); usleep(100000); } } else { // Some events occurred. mPendingEventCount = size_t(pollResult); ALOGW("getEvents: mPendingEventCount=%d ", mPendingEventCount); } } ALOGI("getEvents, exit."); // All done, return the number of events we read. return event - buffer; }
形象莫过于log,开机EventHub扫描设备log:
// 开机EventHub扫描设备log I/EventHub( 523): getEvents, enter. I/EventHub( 523): getEvents, mNeedToScanDevices. I/EventHub( 523): Open device from method scanDirLocked I/EventHub( 523): Opening device: /dev/input/event0 D/EventHub( 523): No input device configuration file found for device 'misc'. W/EventHub( 523): Dropping device: id=1, path='/dev/input/event0', name='misc' I/EventHub( 523): Open device from method scanDirLocked I/EventHub( 523): Opening device: /dev/input/event1 D/EventHub( 523): No input device configuration file found for device 'ft5x06_ts'. --> 触摸屏设备 I/EventHub( 523): New device: id=2, fd=106, path='/dev/input/event1', name='ft5x06_ts', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true I/EventHub( 523): Open device from method scanDirLocked I/EventHub( 523): Opening device: /dev/input/event2 D/EventHub( 523): No input device configuration file found for device 'xxx-keypad'. --> 还记得《【Android休眠】之PowerKey唤醒源实现 》中驱动.name = "xxx-keypad" W/EventHub( 523): Unable to disable kernel key repeat for /dev/input/event2: Function not implemented I/EventHub( 523): New device: id=3, fd=107, path='/dev/input/event2', name='xxx-keypad', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/xxx-keypad.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=true, usingSuspendBlockIoctl=true, usingClockIoctl=true W/EventHub( 523): getEvents, Reporting device opened: id=-1, name=<virtual> W/EventHub( 523): getEvents, Reporting device opened: id=3, name=/dev/input/event2 W/EventHub( 523): getEvents, Reporting device opened: id=2, name=/dev/input/event1 W/EventHub( 523): getEvents, mNeedToSendFinishedDeviceScan. W/EventHub( 523): getEvents: before while, mPendingEventIndex=0 W/EventHub( 523): mPendingEventIndex=0 W/EventHub( 523): mPendingEventCount=0 I/EventHub( 523): getEvents, exit.
按下PowerKey点亮屏幕log:
// 按下PowerKey点亮屏幕log I/EventHub( 523): getEvents, enter. W/EventHub( 523): getEvents: before while, mPendingEventIndex=0 W/EventHub( 523): mPendingEventIndex=0 W/EventHub( 523): mPendingEventCount=0 W/EventHub( 523): getEvents: before while, mPendingEventIndex=0 W/EventHub( 523): mPendingEventIndex=0 W/EventHub( 523): mPendingEventCount=0 W/EventHub( 523): getEvents: mPendingEventCount=1 --> 有事件上来 W/EventHub( 523): getEvents: before while, mPendingEventIndex=0 W/EventHub( 523): getEvents: #1 mPendingEventIndex=1 W/EventHub( 523): /dev/input/event2 got: time=34.860046, type=1, code=116, value=1 W/EventHub( 523): event time 34860046000, now 34860404099 W/EventHub( 523): /dev/input/event2 got: time=34.860046, type=0, code=0, value=0 W/EventHub( 523): event time 34860046000, now 34860404099 W/EventHub( 523): mPendingEventIndex=1 W/EventHub( 523): mPendingEventCount=1 I/EventHub( 523): getEvents, exit.
三、Input设备open流程
Input设备节点位于"/dev/input"目录下:
Android设备在系统起来、创建EventHub对象的时候,会扫描该目录:
status_t EventHub::scanDirLocked(const char *dirname) { char devname[PATH_MAX]; char *filename; // 1、DIR是一个内部结构,类似于FILE,保存当前正在被读取的目录的有关信息 DIR *dir; // 2、struct dirent:描述目录文件(directory file),dirent既含有目录信息,还指有目录中的具体文件的信息 struct dirent *de; // 3、opendir()打开目录"/dev/input",获取指向该目录的DIR dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); // devname = "/dev/input" filename = devname + strlen(devname); *filename++ = '/'; // filename = '/' while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == ' ' || (de->d_name[1] == '.' && de->d_name[2] == ' '))) continue; // de->d_name:路径下的文件名,比如"/dev/input/event0",d_name = "event0" strcpy(filename, de->d_name); // 比如:filename = "/event0", so devname = "/dev/input/event0" ALOGI("Open device from method scanDirLocked"); // open打开"/dev/input/eventX"设备节点 openDeviceLocked(devname); } closedir(dir); return 0; }
open打开"/dev/input/eventX"设备节点,获取设备信息,加入到epoll的监测列表:
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGI("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC); InputDeviceIdentifier identifier; // 1、Get device name. if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s ", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = ' '; identifier.name.setTo(buffer); } // 2、Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { ALOGI("ignoring event id %s driver %s ", devicePath, item.string()); close(fd); return -1; } } // 3、Get device driver version. int driverVersion; ioctl(fd, EVIOCGVERSION, &driverVersion); // 4、Get device identifier. struct input_id inputId; ioctl(fd, EVIOCGID, &inputId); // 5、初始化identifier对象相应成员 identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // 6、Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s ", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = ' '; identifier.location.setTo(buffer); } // 7、Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s ", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = ' '; identifier.uniqueId.setTo(buffer); } // 8、初始化identifier对象相应成员 setDescriptor(identifier); // 9、设置对该设备的访问为非阻塞模式(non-blocking) if (fcntl(fd, F_SETFL, O_NONBLOCK)) { ALOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } int32_t deviceId = mNextDeviceId++; // 10、构建Device对象 Device* device = new Device(fd, deviceId, String8(devicePath), identifier); // 11、加载设备的配置信息 loadConfigurationLocked(device); // 12、获取设备可以上报的事件的类型 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // 13、判断设备的类别,是键盘、鼠标、触摸屏等等,设备类型定义在: // EventHub.h (frameworksaseservicesinput),若不属于定义中的任意一种, // 则不理会它 // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; } // See if this device is a joystick. A joystick is an input device consisting of a stick // that pivots on a base and reports its angle or direction to the device it is controlling. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Check whether this device supports the vibrator. if (test_bit(FF_RUMBLE, device->ffBitmask)) { device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } // Disable kernel key repeat since we handle it ourselves unsigned int repeatRate[] = {0,0}; if (ioctl(fd, EVIOCSREP, repeatRate)) { ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); } } // 14、设备类型定义在:EventHub.h (frameworksaseservicesinput), // 若不属于定义中的任意一种,则不理会它。 // 对于PowerKey,其类型为:INPUT_DEVICE_CLASS_KEYBOARD if (device->classes == 0) { ALOGW("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) { device->controllerNumber = getNextControllerNumberLocked(device); } // 15、添加到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)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } // Enable wake-lock behavior on kernels that support it. // TODO: Only need this for devices that can really wake the system. bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", deviceId, fd, devicePath, device->identifier.name.string(), device->classes, device->configurationFile.string(), device->keyMap.keyLayoutFile.string(), device->keyMap.keyCharacterMapFile.string(), toString(mBuiltInKeyboardId == deviceId), toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); // 若是我们在意的Input设备,则加入监测设备List addDeviceLocked(device); return 0; }
四、休眠锁在EventHub中的生命周期
注: Linux uinput设备
我们知道,对于Input设备,流程基本就是硬件-kernel-应用,uinput作为kernel的一个模块(纯软件),allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application。详细参考资料:uinput: 用户空间的输入子系统。