___2017

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  328 随笔 :: 18 文章 :: 15 评论 :: 18万 阅读
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: 用户空间的输入子系统

posted on   yin'xiang  阅读(903)  评论(0编辑  收藏  举报
编辑推荐:
· 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框架的用法!
点击右上角即可分享
微信分享提示