Input输入系统
注:此文章为学习《深入理解Android卷3 邓凡平注》书的自己学习总结
1介绍
在android系统中目录下/dev/input/下记录着输入设备的设备节点,用户空间可以通过ioctl的方式获取设备节点的输入设备类型、厂商、描述信息等。
android通过监听该目录的变化进行添加和删除设备节点,通过监听具体的设备节点的写入,来进行对输入事件的解析,再传送到具体的事件处理View等。
1.1getevent和sendevent工具
getevent可以获取目录/dev/input/下的设备节点的输入事件,当有输入事件写入时会将输入事件的信息打印出来。
使用格式:
adb shell getevent [-选项] [device_path]
**device_path:**指明具体的设备节点
例如:adb shell getevent -t /dev/input/event0
输入事件显示格式:
2857.164700 /dev/input/event1(输入的设备节点): 0001(事件类型) 0027(事件代码) 00000001(事件的值:1表示按下)
[ 2857.208691] /dev/input/event1: 0001 0027 00000000(事件的值:1表示抬起)
sendevent可以向设备节点写入输入事件,实现模拟用户输入功能。
使用格式:
adb shell sendevent <节点路径> <类型> <代码> <值>
例如:sendevent /dev/input/event1 0001 0027 00000001
1.2Android输入系统简介
Android系统接收到的原始事件为上述格式,但是这种事件并不会很好的被app使用并且识别,所以android系统会将原始事件解析成KeyEvent和MotionEvent类型。以便app通过具体的类可以访问输入事件的信息。
Android输入系统起始为设备节点的事件输入,终点是WMS中具体的窗口(传达到具体View)。
上述图示表明了输入时间在起始到终点所涉及到的类以及具体路径:
- Linux内核,接收输入设备的中断,并将原始事件的数据写入设备节点中。
- 设备节点:作为内核与IMS的桥梁,将原始事件的数据暴露给用户空间,以便IMS读取
- InputManagerService,Android系统服务,分为Native和Java层,java层负责与WMS通信,而Native层则是对原始事件进行解析并加以修饰,转化成可以被framework以及app接受的事件类(KeyEvent)。
- EventHub,监听设备节点以及/dev/input/目录的变化,进行对设备节点的删除和添加等处理,以及接收原始事件,将原始事件解析传送给InputReader。
- InputReader,运行在独立的线程中,负责管理输入设备的列表和配置,以及进行输入事件的加工处理。
- InputDispatcher,同样运行在独立的线程中,并且保留了WMS的窗口信息。通过对窗口判断,然后将事件分发到具体窗口。
- InputReaderPolicy,提供InputReader对输入事件加工处理的策略配置,例如键盘布局信息等
- InputDispatcherPolicy,为InputDispatcher的派发过程提供策略控制。
总结:
内核将原始事件写入设备节点,InputReader不断通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispatcher,InputDispatcher根据WMS提供的窗口信息将事件发送给合适的窗口,窗口的ViewRootImpl会遍历布局View树,将事件传递给具体实现的View。
1.3IMS的初始化过程
1、SystemServer.startOtherService():
private void startOtherServices() {
........
//调用构造函数
inputManager = new InputManagerService(context);
......
//将InputManagerService添加到servicemanager中
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
......
//将InputMonitor注册到IMS中,用于对事件筛选和派发的处理
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
......
//调用到Native层,启动InputReader和InputDispatcher的线程循环
inputManager.start();
......
}
主要对InputManagerService模块进行初始化加载。将InputManagerService注册到servicemanager中。
2、InputManagerService构造函数:
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
//调用Native层函数,初始化Native层的InputManager系统
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
调用nativeInit函数,通过JNI初始化Native层的Input系统模块。
3、com_android_server_input_InputManagerService.nativeInit():
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//创建NativeInputManager对象
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
4、NativeInputManager::NativeInputManager():
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
}
mInteractive = true;
//创建EventHub对象,加载EventHub运行环境
sp<EventHub> eventHub = new EventHub();
//创建InputManager对象,创建InputReader和InputDispatcher以及运行环境
mInputManager = new InputManager(eventHub, this, this);
}
在此处加载EventHub以及InputManger对象,在InputMnager中会初始化加载InputReader和InputDispatcher。
5、InputManager::InputManager():
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
//创建InputDispatcher和InputReader的线程环境
initialize();
}
在此处会初始化InputReader和InputDispatcher,并调用InputManager::initialize()初始化并启动InputReader和InputDispatcher的运行线程InputReaderThread和InputDispatcherThread。创建InputReader和InputDispatcher时携带的参数InputReaderPolicyInterface和InputDispatcherPolicyInterface均为NativeInputManager。
6、InputManager::initialize()
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputReaderThread和InputDispatcherThread继承Thread类,调用Thread类的run函数后直接运行threadLoop函数,返回为1时则会循环调用threadLoop函数。
InputReaderThread调用InputReader的loopOnce函数进入从EventHub获取事件的循环。
InputDispatcherThread调用InputDispatcher的dispatcheOnce函数进入分发事件的循环。
7、InputManagerService.start() => com_android_server_input_InputManagerService.nativeStart()=>InputManager.start()
此处为进行启动InputReaderThread和InputDispatcherThread线程,循环InputDispatcher的dispatchOnce函数以及InputReader的loopOnce函数。
IMS的结构体系:
IMS成员关系:
2原始事件的读取与加工
EventHub通过使用INotify和epoll进行监听原始输入事件,监听设备节点的增加与删除。
2.1INotify和epoll了解
1、INotify的介绍与使用
INotify是Linux内核所提供的一种文件变化通知机制,它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等。INotify机制有两个基本对象,分别为inotify对象和watch对象,都使用文件描述符表示
Inotify对象对应一个队列,应用程序可以向inotify对象添加多个监听,当被监听的事件发生时,可以通过read()函数从inotify对象中将时间信息读取出来。
Inotify对象创建方式:
int inotify = inotify_init();
Watch对象则用来描述文件系统的变化事件的监听。它是一个二元组,包括监听目标和事件掩码两种元素。监听目标是文件系统的一个路径,时间掩码则是表示需要监听的事件类型(如:IN_CREATE、IN_DELETE)。
将监听文件的创建和删除的watch对象添加到inotify对象中:
int wd = inotify_add_watch(inotifyFd, “/dev/input/”,IN_CREATE |IN_DELETE);
用于保存事件信息的结构体inotify_event:
struct inotify_event {
_s32 wd; /*事件对应的watch对象的描述符*/
_u32 mask; /*事件类型*/
_u32 cookie; /**/
_u32 len; /*name字段长度*/
char name[0]; /*用于存储此事件的文件路径*/
}
读取一个或多个监听事件:
size_t len = read(inotifyFd, events_buf, BUF_LEN);
events_buf为inotify_event的数组指针。
2、Epoll的介绍和使用
Epoll机制可以使用一次等待监听多个描述符的可读/可写状态。等待返回时携带了可读的描述符或自定义数据。
2.1、创建epoll对象:
int epfd = epoll_create(MAX_FDS);
2.2、填充epoll_event结构体:
struct epoll_event {
_uint32_t events; /*时间掩码,监听的事件类型EPOLLIN(可读)、EPOLLOUT(可写)、EPOLLERR(描述符发生错误)、EPOLLHUP(描述符被挂起)等*/
Epoll_data data; /*使用自定义的数据,当此事件发生后该数据原封不动的返回给使用者*/
}
typedef union epoll_data {
void *ptr;
int fd;
_uint32_t u32;
_uint64_t u64;
} epoll_data_t;
填充epoll_event方法:
struct epoll_event eventItem;
memset(&eventItem, 0 , sizeof(eventItem));
eventItem.events = EPOLLIN | EPOLLERR |EPOLLHUP;
eventItem.data.fd = listeningFd; /*listeningFd为需要监听的描述符*/
int result = epoll_ctl(epfd, EPOLL_CTL_ADD, listeningFd, &eventItem);
- epfd为epoll_create函数创建的epoll对象的描述符
- EPOLL_CTL_ADD/EPOLL_CTL_DEL/EPOLL_CTL_MOD为对应的操作,分别是增加/删除/修改注册事件。
- listeningFd是需要监听的描述符 eventItem表示被监听的描述符的详细信息,会返回给使用者。
2.3、等待事件发生
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
- Epfd是由epoll_create()创建的epoll对象描述符
- Events是一个epoll_event的数组,此函数返回时,事件的信息会被填充。
- Maxevents表示此次调用最多可以获取多少个事件 timeout表示等待超时的事件
2.2InputReader和EventHub的工作流程
2.2.1EventHub的构造函数:
EventHub::EventHub(void) :mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
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);
#ifdef TERTIARY_TOUCH
......//获取一下属性进行设置
#endif
//创建epoll对象
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
//创建inotify对象
mINotifyFd = inotify_init();
//创建watch对象进行对文件/dev/input/的创建和删除的监听
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
//进行对epoll_event的填充
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
//对inotify进行监听的特殊标志
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//对inotify的文件描述符进行监听
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
//创建管道
result = pipe(wakeFds);
//读和写管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
//对读管道进行文件描述符设置
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
//对写管道进行文件描述符设置
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
//对管道进行监听的特殊标志
eventItem.data.u32 = EPOLL_ID_WAKE;
//对读管道描述符进行监听
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
......
}
总结:
EventHub的构造函数主要是对监听设备节点以及原始输入事件监听做准备,使用INotify进行对/dev/input/文件夹下的修改进行监听。
2.2.2InputReader线程调用的循环函数loopOnce
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{
......
} // release lock
//调用EventHub获取设备节点的创建或删除,以及原始输入事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//进一步分发设备节点的创建或删除,以及原始输入事件
processEventsLocked(mEventBuffer, count);
}
}
//将事件派发到InputDispatcher
mQueuedListener->flush();
}
总结:
在InputReader的loopOnce函数中,主要负责对原始输入事件的获取,以及对原始输入事件的进一步处理并发送给InputDispatcher。loopOnce函数是InputReaderThread线程启动,并且被循环调用。所以可以一直获取调用EventHub.getEvent()函数。
2.2.3getEvents的工作方式
getEvents函数会循环进行对事件的提取,事件分为设备节点的增加与删除和原始输入事件。
//RawEvent是需要返回给InputReader的事件数组
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
closeAllDevicesLocked();
mNeedToScanDevices = true;
break;
}
//mClosingDevices是存储被删除设备节点,此部分循环是将设备节点的删除事件传送给InputReader
while (mClosingDevices) {
Device* device = mClosingDevices;
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;
}
}
//mNeedToScanDevices初始化为true,第一次进入getEvents函数时,会进行遍历目录/dev/input/目录下的设备节点,并将设备节点信息转化成Device对象并保存在mOpeningDevices指针链表中。
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
//调用此函数进行遍历/dev/input/目录下的设备节点,并将设备节点的描述符加入到epoll监听中,下面有对设备节点有原始输入事件产生的处理
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
//将存储在mOpeningDevices 中需要添加设备节点的事件保存在RawEvent数组指针中
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;
}
}
//添加设备节点的事件处理结束后,会添加一个RawEvent表示设备节点事件添加完成
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
bool deviceChanged = false;
//进入循环处理设备节点上报的原始事件
while (mPendingEventIndex < mPendingEventCount) {
//mPendingEventItems是epoll_wait等待描述符监听的事件产生后保存的epoll_event
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//判断此事件是否是监听INotify的事件
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
//是的话将此处标记为true,后面用于对设备节点的添加或删除优先处理
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
//此处是监听管道的描述符返回的事件
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;
}
//接下来是处理对设备节点的原始输入事件,在添加设备节点时,会将设备节点的监听添加到epoll机制中。
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;
}
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
//将读取的事件保存在readBuffer中
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
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++) {
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;
}
}
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;
}
ALOGV("applied override time %d.%06d",
int(iev.time.tv_sec), int(iev.time.tv_usec));
}
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL;
ALOGI("event time %" PRId64 ", now %" PRId64, event->when, now);
if (event->when >= now + 10 * 1000000000LL) {
// Double-check. Time may have moved on.
nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
if (event->when > time) {
event->when = time;
} else {
event->when, time, now);
}
}
//将此原始输入事件保存到RawEvent数组指针中
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
//capacity是此次InputReader能够接受的事件RawEvent数组指针的大小,当RawEvent数组指针存储满了,就会跳出循环将RawEvent数组指针返回给InputReader
if (capacity == 0) {
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",eventItem.events, device->identifier.name.string());
}
}
//处理INotify描述符的监听事件,设备节点增加或删除
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
if (deviceChanged) {
continue;
}
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
//此处是epoll机制等待被添加的描述符需要监听的事件返回
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS,timeoutMillis);
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) {
mPendingEventCount = 0;
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
mPendingEventCount = size_t(pollResult);
}
}
return event - buffer;
}
总结:getEvents主要是通过epoll机制监听被注册的描述符产生的事件,并将此事件分为设备节点的添加和删除、设备节点的原始输入事件输入。然后将监听的事件保存在InputReader传过来的RawEvent数组指针中。需要注意的是设备节点的增加和删除要优先于设备节点的原始输入事件的添加。
2.2.4EventHub处理设备节点的增加和删除
2.2.4.1处理INotify描述符被监听的事件
status_t EventHub::readNotifyLocked() {
int res;
char devname[PATH_MAX];
char *filename;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
//读出发生在INotify机制中的事件
res = read(mINotifyFd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
return 0;
ALOGW("could not get event, %s\n", strerror(errno));
return -1;
}
strcpy(devname, DEVICE_PATH);
filename = devname + strlen(devname);
*filename++ = '/';
while(res >= (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
if(event->len) {
strcpy(filename, event->name);
if(event->mask & IN_CREATE) {
//进行对新的设备节点进行处理
openDeviceLocked(devname);
} else {
ALOGI("Removing device '%s' due to inotify event\n", devname);
//进行对设备节点的删除事件的处理
closeDeviceByPathLocked(devname);
}
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
总结:此处通过read获取INotify机制产生的事件,也就是设备节点的增加和删除。并进行对事件进行处理。
2.2.4.2对设备节点输入的处理
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
InputDeviceIdentifier identifier;
...... //省略,下面主要是将设备节点信息进行获取保存在本地对象Device中
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);
......//省略
//将设备节点的描述符添加到epoll监听机制中,监听设备节点的事件输入
if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
configureFd(device);
//添加到mOpeningDevices和mDevices中,在getEvents中处理并返回给InputReader
addDeviceLocked(device);
return OK;
}
总结:此函数主要是对INotify机制的添加设备节点的事件进行处理,将设备节点描述符注册到epoll机制中用于监听设备节点的原始事件输入,并将新建的Device对象保存在mOpeningDevices数组指针中,用于在getEvents中返回给InputReader。
2.2.4.3删除设备节点操作
void EventHub::closeDeviceLocked(Device* device) {
ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
device->path.string(), device->identifier.name.string(), device->id,
device->fd, device->classes);
if (device->id == mBuiltInKeyboardId) {
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
//将此设备节点的描述符从epoll机制中删除
unregisterDeviceFromEpollLocked(device);
releaseControllerNumberLocked(device);
mDevices.removeItem(device->id);
device->close();
Device* pred = NULL;
bool found = false;
//对mOpeningDevices进行遍历,删除需要删除的设备节点事件
for (Device* entry = mOpeningDevices; entry != NULL; ) {
if (entry == device) {
found = true;
break;
}
pred = entry;
entry = entry->next;
}
if (found) {
ALOGI("Device %s was immediately closed after opening.", device->path.string());
if (pred) {
pred->next = device->next;
} else {
mOpeningDevices = device->next;
}
delete device;
} else {
//如果此设备节点已经添加,那么将此需要删除的设备节点保存在mClosingDevices中,在getEvents中将此事件返回InputReader
device->next = mClosingDevices;
mClosingDevices = device;
}
}
总结:主要是将本地保存的Device信息进行删除,并注销epoll对设备节点的描述符的监听,保存到mClosingDevices中,将此删除事件返回给InputReader。
2.2.5InputReader对获取的事件的处理
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
//对设备节点的原始输入事件的处理
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
//针对设别节点的添加和删除的处理
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
ALOGI("LIUXINYU count: %d; batcheSize: %d; ", (int)count, (int)batchSize);
}
}
未完,待续…