1 2 3 4 5 6 | 受不了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形式的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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可以识别的数据形式。
二、处理流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | 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\n" , 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\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; // 启动构建下一个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\n" , mPendingEventIndex); // 8、有事件,去处理 // mPendingEventCount:等待处理的事件的个数 // mPendingEventIndex:指示当前需要处理的事件 while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; ALOGW( "getEvents: #1 mPendingEventIndex=%d\n" , 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)\n" , 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\n" , event->code); ALOGW( "getEvents, value=%d\n" , 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\n" , 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\n" , mPendingEventIndex); ALOGW( "mPendingEventCount=%d\n" , 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)\n" , errno ); usleep(100000); } } else { // Some events occurred. mPendingEventCount = size_t (pollResult); ALOGW( "getEvents: mPendingEventCount=%d\n" , mPendingEventCount); } } ALOGI( "getEvents, exit." ); // All done, return the number of events we read. return event - buffer; } |
形象莫过于log,开机EventHub扫描设备log:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // 开机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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 按下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对象的时候,会扫描该目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0' ))) 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的监测列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | 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\n", devicePath, strerror(errno)); } else { buffer[ sizeof (buffer) - 1] = '\0' ; 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\n" , 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\n", devicePath, strerror(errno)); } else { buffer[ sizeof (buffer) - 1] = '\0' ; 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\n", devicePath, strerror(errno)); } else { buffer[ sizeof (buffer) - 1] = '\0' ; 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 (frameworks\base\services\input),若不属于定义中的任意一种, // 则不理会它 // 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 (frameworks\base\services\input), // 若不属于定义中的任意一种,则不理会它。 // 对于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: 用户空间的输入子系统。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!