注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东月之神

在单纯的观念里面,生命就容易变得比较深刻!

 
 
 

日志

 
 
关于我

别驻足,梦想要不停追逐,别认输,熬过黑暗才有日出,要记住,成功就在下一步,路很苦,汗水是最美的书!

网易考拉推荐

(转)Android 4.0 事件输入(Event Input)系统 (上)  

2012-03-31 12:04:00|  分类: Android |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
1. TouchScreen功能在Android4.0下不工作

       原来在Android2.3.5下能正常工作的TouchScreen功能,移植到Android 4.0就不能正常工作了。凭直觉,Android4.0肯定有鬼。真是不看不知道,一看吓一跳。在Android 4.0中,Event Input地位提高了,你看看,在Adroid2.3.5中,它在frameworks/base/libs/ui之下,在Android4.0中,它在frameworks/base/services/input之下,看到没有,它有了自己的地位,就像在Kernel中一样,有自己门户了。

      再看看代码,变化也太大了,当然TouchScreen不能工作,首先自然会看接口部分代码。首先看它是如何打开设备的,查看函数EventHub::openDeviceLocked,看看其代码,大部分还是很熟悉的,但仔细一看多了一个下面的东东:

ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);

      由于升级到Android4.0时,Kernel还是2.6.35,并没有进行升级。既然需要EVIOCGPROP,就就看看evdev.c中的ioctl函数是否支持此功能。一看不支持,再看看Kernel3.0.8<这个Kernel版本与Android4.0是一伙的>,我的乖乖,它已经支持了此功能,详见evdev.c中函数evdev_do_ioctl,这个写得2.6.35中的友好多了,分别处理:固定长度命令、单个可变长度命令和多个可变长度命令。

      对于为什么我的TouchScreen在Android4.0不工作,答案显而易见,我用的Kernel版本不对,当然移植到Android4.0对应的Kernel(Kernel3.0.8)时,TouchScreen驱动本身也需要修改,因为input_dev变化也比较大,比如增加了propbit字段,以供处理上面的ioctl时使用。

 

2. Android 4.0如何管理各种驱动设备

       正是由于遇到上面的问题,才促使自己对Event Input进行深入了解。因为蜻蜓点水不是小弟的性格。

       这个年代干啥都有什么经理,小弟之类的。比如去饭店吃饭,吃到小强了,总是会大吼一声,经理,过来看看,然后谈打折或赔偿的问题。可见经理是不可缺少的,要不然我们找谁来维权啊!

       前面谈到的EventHub,这个一看就是一个做实事的,肯定不是领导,哪它的领导是谁呢? 哪我们就从以下几方面来分析此问题:

       1)每个功能模块是怎么产生的?

       2)读取设备输入流程?

       3)事件分发流程?

3. 各个功能模块是怎么产生的?

      先介绍一下每个模块的工作职责:EventHub, InputReader, InputManager...

3.1 模块功能

3.1.1 EventHub

        它是系统中所有事件的中央处理站。它管理所有系统中可以识别的输入设备的输入事件,此外,当设备增加或删除时,EventHub将产生相应的输入事件给系统。

        EventHub通过getEvents函数,给系统提供一个输入事件流。它也支持查询输入设备当前的状态(如哪些键当前被按下)。而且EventHub还跟踪每个输入调入的能力,比如输入设备的类别,输入设备支持哪些按键。 

3.1.2 InputReader

      InputReader从EventHub中读取原始事件数据(RawEvent),并由各个InputMapper处理之后输入对应的input listener.

      InputReader拥有一个InputMapper集合。它做的大部分工作在InputReader线程中完成,但是InputReader可以接受任意线程的查询。为了可管理性,InputReader使用一个简单的Mutex来保护它的状态。

     InputReader拥有一个EventHub对象,但这个对象不是它创建的,而是在创建InputReader时作为参数传入的。

3.1.3 InputDispatcher

     InputDispatcher负责把事件分发给输入目标,其中的一些功能(如识别输入目标)由独立的policy对象控制。

 

3.1.4 InputManager

     InputManager是系统事件处理的核心,它虽然不做具体的事,但管理工作还是要做的,比如接受我们客户的投诉和索赔要求,或者老板的出所筒。

     InputManager使用两个线程:

     1)InputReaderThread叫做"InputReader"线程,它负责读取并预处理RawEvent,applies policy并且把消息送入DispatcherThead管理的队列中。

     2)InputDispatcherThread叫做"InputDispatcher"线程,它在队列上等待新的输入事件,并且异步地把这些事件分发给应用程序。

     InputReaderThread类与InputDispatcherThread类不共享内部状态,所有的通信都是单向的,从InputReaderThread到InputDispatcherThread。两个类可以通过InputDispatchPolicy进行交互。

     InputManager类从不与Java交互,而InputDispatchPolicy负责执行所有与系统的外部交互,包括调用DVM业务。

3.2 创建流程

1)在android_server_InputManager_nativeInit中创建NativeInputManager对象,并保存到gNativeInputManager中;

2)在创建NativeInputManager对象时,它会创建EventHub对象<且创建是其成员mNeedToScanDevices的值为true>,然后把刚创建的EventHub对象作为参数创建InputManager对象;

3)在创建InputManager对象时,创建InputReader对象,然后把它作为参数创建InputReaderThread;创建InputDispatcher对象,然后把它作为参数创建InputDispatcherThread对象;(注:以上两个线程对象都有自己的threadLoop函数,它将在Thread::_threadLoop中被调用,这个Thread::_threadLoop是线程入口函数,线程在Thread::run中被真正地创建

4.1)创建InputReader对象

4.1.1)把EventHub、readerPolicy<实质为NativeInputManager对象>和创建的InputDispatcher对象作为参数创建InputReader对象:mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

4.1.2)在创建InputReader时, 保存EventHub对象到mEventHub中,并创建QueuedInputListener对象并保存在mQueuedListener中

4.2)创建InputDispatcher对象

4.2.1)把传入的参数dispatcherPolicy<实质为NativeInputManager对象>作为参数创建InputDispatcher对象:mDispatcher = new InputDispatcher(dispatcherPolicy);

4.2.1)在创建InputDispatcher时,创建了一个looper对象:mLooper = new Looper(false);

3.3 启动流程

1)在android_server_InputManager_nativeStart中调用InputManager::start,代码如下:

result = gNativeInputManager->getInputManager()->start();

2)在InputManager::start中,调用mDispatcherThread->run和mReaderThread->run,代码如下:

result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

3)在上面的Thread::run中,调用createThreadEtc函数,并以Thread::_threadLoop作为入口函数,以上面的mDispatcherThread或mReaderThread作为userdata创建线程

4)至此InputReader线程和InputDispatcher线程都已经工作,详细信息见Thread::_threadLoop,在此函数中它将调用mDispatcherThread或mReaderThread的threadLoop函数来做真正的事

5.1)mReaderThread->threadLoop

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

5.2)mDispatcherThread->threadLoop

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;

 

3.4 EventInput对象关系图 

 

4. 设备操作流程

从EventHub::getEvents读取的事件数据结构如下:

  1. struct RawEvent {  
  2.     nsecs_t when;        //事件发生的时间   
  3.     int32_t deviceId;    //产生此事件的设备,比如发送FINISHED_DEVICE_SCAN,不需要填此项   
  4.     int32_t type;        //事件类型(如:DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN)   
  5.     int32_t scanCode;  
  6.     int32_t keyCode;  
  7.     int32_t value;  
  8.     uint32_t flags;  
  9. };  
struct RawEvent { nsecs_t when; //事件发生的时间 int32_t deviceId; //产生此事件的设备,比如发送FINISHED_DEVICE_SCAN,不需要填此项 int32_t type; //事件类型(如:DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN) int32_t scanCode; int32_t keyCode; int32_t value; uint32_t flags; };

读取事件时的调用流程为:

Thread::_threadLoop->

     InputReaderThread::threadLoop->

          InputReader::loopOnce->

               EventHub::getEvents->

4.1 打开设备

      在EventHub::getEvents中,当mNeedToScanDevices为true时<当创建EventHub对象时,它就为true>,它将从/dev/input目录下查找所有设备,并进行打开,获取其相关属性,最后加入mDevices列表中。

EventHub::scanDevicesLocked->

     EventHub::scanDirLocked("/dev/input")->

         EventHub::openDeviceLocked

4.1.1 打开事件输入设备

     打开事件输入设备,在用户态调用open,则在kernel态中调用evdev_open函数,evdev_open处理流程如下:

     1)首先从参数inode中获取在evdev_table中的索引,从而获取对应的evdev对象

     2)创建evdev_client对象,创建此对象时同时为其buffer成员分配对应的内存

     3)把新创建evdev_client对象添加到client_list链表中

     4)把client保存在file的private_data中

     5)调用evdev_open_device->input_open_device->input_dev.open函数打开设备。

 

4.2 读取输入事件

      要说EventHub::getEvents如何获取输入事件,不得不先说说它的几个相关的成员变量:

     1)mPendingEventCount:调用epoll_wait时的返回值,当然如果没有事件,则其值为0;

     2)mPendingEventIndex:当前需要处理的事件索引

     3)mEpollFd:epoll实例,在EventHub::EventHub中初始化此例,所有输入事件通过epoll_wait来获取,每一个事件的数据结构为:struct epoll_event,为了搞明白如何读取输入事件的原理,不得不对epoll相关的东东搞个清清楚楚,明明白白,见epoll kernel实现原理注:epoll_event只表明某个设备上有事件,并不包含事件内容,具体事件内容需要通过read来读取

   struct epoll_event定义如下:

  1. typedef union epoll_data   
  2. {  
  3.     void *ptr;  
  4.     int fd;  
  5.     unsigned int u32;  
  6.     unsigned long long u64;  
  7. } epoll_data_t;  
  8.   
  9. struct epoll_event   
  10. {  
  11.     unsigned int events;  
  12.     epoll_data_t data;  
  13. };  
typedef union epoll_data { void *ptr; int fd; unsigned int u32; unsigned long long u64; } epoll_data_t; struct epoll_event { unsigned int events; epoll_data_t data; };

     每个设备被创建(在函数EventHub::openDeviceLocked中)时,都会向epoll注册,代码如下:

  1. // Register with epoll.   
  2. struct epoll_event eventItem;  
  3. memset(&eventItem, 0, sizeof(eventItem));  
  4. eventItem.events = EPOLLIN;  
  5. eventItem.data.u32 = deviceId;  
  6. if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {  
  7.     LOGE("Could not add device fd to epoll instance.  errno=%d", errno);  
  8.     delete device;  
  9.     return -1;  
  10. }  
// Register with 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)) { LOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; }

4.2.1 查看设备上是否有事件


        在调用epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis)之后,读到的epoll_event事件保存在mPendingEventItems,总共的事件数保存在mPendingEventCount,当然,在调用epoll_event之前,mPendingEventIndex被清0,直正的事件处理在下面的代码中。

  1.         // Grab the next input event.   
  2.         bool deviceChanged = false;  
  3.         while (mPendingEventIndex < mPendingEventCount) {  
  4.             const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];  
  5.             if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {  
  6.                 if (eventItem.events & EPOLLIN) {  
  7.                     mPendingINotify = true;  
  8.                 } else {  
  9.                     LOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);  
  10.                 }  
  11.                 continue;  
  12.             }  
  13.   
  14.             if (eventItem.data.u32 == EPOLL_ID_WAKE) {  
  15.                 if (eventItem.events & EPOLLIN) {  
  16.                     LOGV("awoken after wake()");  
  17.                     awoken = true;  
  18.                     char buffer[16];  
  19.                     ssize_t nRead;  
  20.                     do {  
  21.                         nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));  
  22.                     } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));  
  23.                 } else {  
  24.                     LOGW("Received unexpected epoll event 0x%08x for wake read pipe.",  
  25.                             eventItem.events);  
  26.                 }  
  27.                 continue;  
  28.             }  
  29.   
  30.             ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);  
  31.             if (deviceIndex < 0) {  
  32.                 LOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",  
  33.                         eventItem.events, eventItem.data.u32);  
  34.                 continue;  
  35.             }  
  36.   
  37.             Device* device = mDevices.valueAt(deviceIndex);  
  38.             if (eventItem.events & EPOLLIN) {  
  39.                 int32_t readSize = read(device->fd, readBuffer,  
  40.                         sizeof(struct input_event) * capacity);  
  41.                 if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {  
  42.                     // Device was removed before INotify noticed.   
  43.                     LOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d capacity: %d errno: %d)\n",  
  44.                          device->fd, readSize, bufferSize, capacity, errno);  
  45.                     deviceChanged = true;  
  46.                     closeDeviceLocked(device);  
  47.                 } else if (readSize < 0) {  
  48.                     if (errno != EAGAIN && errno != EINTR) {  
  49.                         LOGW("could not get event (errno=%d)", errno);  
  50.                     }  
  51.                 } else if ((readSize % sizeof(struct input_event)) != 0) {  
  52.                     LOGE("could not get event (wrong size: %d)", readSize);  
  53.                 } else {  
  54.                     int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;  
  55.   
  56.                     size_t count = size_t(readSize) / sizeof(struct input_event);  
  57.                     for (size_t i = 0; i < count; i++) {  
  58.                         const struct input_event& iev = readBuffer[i];  
  59.                         LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",  
  60.                                 device->path.string(),  
  61.                                 (int) iev.time.tv_sec, (int) iev.time.tv_usec,  
  62.                                 iev.type, iev.code, iev.value);  
  63.   
  64. #ifdef HAVE_POSIX_CLOCKS   
  65.                         // Use the time specified in the event instead of the current time   
  66.                         // so that downstream code can get more accurate estimates of   
  67.                         // event dispatch latency from the time the event is enqueued onto   
  68.                         // the evdev client buffer.   
  69.                         //   
  70.                         // The event's timestamp fortuitously uses the same monotonic clock   
  71.                         // time base as the rest of Android.  The kernel event device driver   
  72.                         // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().   
  73.                         // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere   
  74.                         // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a   
  75.                         // system call that also queries ktime_get_ts().   
  76.                         event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL  
  77.                                 + nsecs_t(iev.time.tv_usec) * 1000LL;  
  78.                         LOGV("event time %lld, now %lld", event->when, now);  
  79. #else   
  80.                         event->when = now;  
  81. #endif   
  82.                         event->deviceId = deviceId;  
  83.                         event->type = iev.type;  
  84.                         event->scanCode = iev.code;  
  85.                         event->value = iev.value;  
  86.                         event->keyCode = AKEYCODE_UNKNOWN;  
  87.                         event->flags = 0;  
  88.                         if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {  
  89.                             status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,  
  90.                                         &event->keyCode, &event->flags);  
  91.                             LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",  
  92.                                     iev.code, event->keyCode, event->flags, err);  
  93.                         }  
  94.                         event += 1;  
  95.                     }  
  96.                     capacity -= count;  
  97.                     if (capacity == 0) {  
  98.                         // The result buffer is full.  Reset the pending event index   
  99.                         // so we will try to read the device again on the next iteration.   
  100.                         mPendingEventIndex -= 1;  
  101.                         break;  
  102.                     }  
  103.                 }  
  104.             } else {  
  105.                 LOGW("Received unexpected epoll event 0x%08x for device %s.",  
  106.                         eventItem.events, device->identifier.name.string());  
  107.             }  
  108.         }  

 

4.2.2 读取设备上真正的事件

epoll_wait只是告诉我们Device已经有事件了,让我们去读,真正读取设备输入事件的代码如上,其流程如下:
1)根据eventItem.data.u32获取设备索引,从而获取对应的Device

2)从device->fd中读取input_event事件。read(device->fd, readBuffer, sizeof(struct input_event) * capacity);这些input_event是由各个注册的input_device报告给input子系统的。具体读入流程参见Input Core和evdev基本知识 - Kernel3.0.8

至此,事件已经读取到用户态,哪我们就看看EventHub怎么处理这些事件了。 

4.3 处理输入事件

      在4.2中,首先通过epoll_wait查看哪些设备有事件,然后通过read从有事件的设备中读取事件,现在事件已经读取到用户态,且数据结构为input_event,保存在EventHub::getEvents的readBuffer中。下面就看看这些事件下一步的东家是谁?

      1)首先把input_event的信息填入RawEvent中,其相关代码如下:

  1. #ifdef HAVE_POSIX_CLOCKS  
  2.                         // Use the time specified in the event instead of the current time  
  3.                         // so that downstream code can get more accurate estimates of  
  4.                         // event dispatch latency from the time the event is enqueued onto  
  5.                         // the evdev client buffer.  
  6.                         //  
  7.                         // The event's timestamp fortuitously uses the same monotonic clock  
  8.                         // time base as the rest of Android.  The kernel event device driver  
  9.                         // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().  
  10.                         // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere  
  11.                         // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a  
  12.                         // system call that also queries ktime_get_ts().  
  13.                         event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL  
  14.                                 + nsecs_t(iev.time.tv_usec) * 1000LL;  
  15.                         LOGV("event time %lld, now %lld", event->when, now);  
  16. #else  
  17.                         event->when = now;  
  18. #endif  
  19.                         event->deviceId = deviceId;  
  20.                         event->type = iev.type;  
  21.                         event->scanCode = iev.code;  
  22.                         event->value = iev.value;  
  23.                         event->keyCode = AKEYCODE_UNKNOWN;  
  24.                         event->flags = 0;  
  25.                         if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {  
  26.                             status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,  
  27.                                         &event->keyCode, &event->flags);  
  28.                             LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",  
  29.                                     iev.code, event->keyCode, event->flags, err);  
  30.                         }  
#ifdef HAVE_POSIX_CLOCKS // Use the time specified in the event instead of the current time // so that downstream code can get more accurate estimates of // event dispatch latency from the time the event is enqueued onto // the evdev client buffer. // // The event's timestamp fortuitously uses the same monotonic clock // time base as the rest of Android. The kernel event device driver // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a // system call that also queries ktime_get_ts(). event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL; LOGV("event time %lld, now %lld", event->when, now); #else event->when = now; #endif event->deviceId = deviceId; event->type = iev.type; event->scanCode = iev.code; event->value = iev.value; event->keyCode = AKEYCODE_UNKNOWN; event->flags = 0; if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) { status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, &event->keyCode, &event->flags); LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", iev.code, event->keyCode, event->flags, err); }


     2)如果是input_event的类型为EV_KEY,则需要调用device->keyMap.keyLayoutMap->mapKey函数把iput_event.code映射为RawEvent.keyCode。相关数据结构关系如下图所示:

       至此,EventHub::getEvents读取事件的任务已经完成,下面看看这些RawEvent的命运如何呢?

 4.3.1 InputReader::loopOnce如何处理RawEvent?

    为此,先温习一下读取事件时的调用流程为:

Thread::_threadLoop->

     InputReaderThread::threadLoop->

          InputReader::loopOnce->

               EventHub::getEvents->

     在InputReader::loopOnce中,当调用EventHub->getEvents获取到RawEvent之后,调用InputReader::processEventsLocked来处理这些事件,然后调用mQueuedListener->flush()把这些队列中的事件发送到Listener。

4.3.1.1 InputReader::processEventsLocked

       在InputReader::processEventsLocked主要分两步处理:

       1)处理来自于事件驱动设备的事件(processEventsForDeviceLocked)

       2)处理设备增加、删除和修改事件

       按照程序执行流程,应该是先有设备,然后才会有设备事件,所以先分析设备增加。 其代码如下:

 

  1. <span style="font-size:10px;">void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count)   
  2. {  
  3.     for (const RawEvent* rawEvent = rawEvents; count;) {  
  4.         int32_t type = rawEvent->type;  
  5.         size_t batchSize = 1;  
  6.           
  7.        //处理来自于事件驱动设备的事件  
  8.         if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {  
  9.           
  10.             int32_t deviceId = rawEvent->deviceId;  
  11.             while (batchSize < count) {  
  12.                 if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT  
  13.                         || rawEvent[batchSize].deviceId != deviceId) {  
  14.                     break;  
  15.                 }  
  16.                 batchSize += 1;  
  17.             }  
  18.           //处理来自于同一个事件驱动设备的1个或多个事件  
  19.             processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  
  20.         }   
  21.         else   
  22.         {  
  23.             //处理增加或删除事件驱动设备的事件,在EventHub::getEvents中产生,  
  24.             //不是由事件驱动设备产生的。  
  25.             switch (rawEvent->type) {  
  26.             case EventHubInterface::DEVICE_ADDED:  
  27.                 addDeviceLocked(rawEvent->when, rawEvent->deviceId);  
  28.                 break;  
  29.             case EventHubInterface::DEVICE_REMOVED:  
  30.                 removeDeviceLocked(rawEvent->when, rawEvent->deviceId);  
  31.                 break;  
  32.             case EventHubInterface::FINISHED_DEVICE_SCAN:  
  33.                 handleConfigurationChangedLocked(rawEvent->when);  
  34.                 break;  
  35.             default:  
  36.                 LOG_ASSERT(false); // can't happen  
  37.                 break;  
  38.             }  
  39.         }  
  40.         count -= batchSize;  
  41.         rawEvent += batchSize;  
  42.     }  
  43. }</span>  
<span style="font-size:10px;">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; } //处理来自于同一个事件驱动设备的1个或多个事件 processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { //处理增加或删除事件驱动设备的事件,在EventHub::getEvents中产生, //不是由事件驱动设备产生的。 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: LOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } }</span>

 

4.3.1.1.1 设备增加事件处理 addDeviceLocked

      它处理其中的EventHubInterface::DEVICE_ADDED, EventHubInterface:: DEVICE_REMOVED和EventHubInterface::FINISHED_DEVICE_SCAN事件,即与Device相关的事件,这些事件是在EventHub::getEvents中产生的,并不是Kernel态的事件输入设备产生的。

     下面分析它如何处理EventHubInterface::DEVICE_ADDED事件。查看其它代码,它是调用InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId)来处理此事件。

      在InputReader::addDeviceLocked中的调用流程:

      1)先根据mContext, deviceId, name, classes创建一个InputDevice对象,它用于表示单个输入设备的状态。其中的classes为对应Device的classes成员,它用于表示设备类型,其定义如下:

  1. /*  
  2.  * Input device classes.  
  3.  */  
  4. enum {  
  5.     /* The input device is a keyboard or has buttons. */  
  6.     INPUT_DEVICE_CLASS_KEYBOARD      = 0x00000001,  
  7.   
  8.     /* The input device is an alpha-numeric keyboard (not just a dial pad). */  
  9.     INPUT_DEVICE_CLASS_ALPHAKEY      = 0x00000002,  
  10.   
  11.     /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */  
  12.     INPUT_DEVICE_CLASS_TOUCH         = 0x00000004,  
  13.   
  14.     /* The input device is a cursor device such as a trackball or mouse. */  
  15.     INPUT_DEVICE_CLASS_CURSOR        = 0x00000008,  
  16.   
  17.     /* The input device is a multi-touch touchscreen. */  
  18.     INPUT_DEVICE_CLASS_TOUCH_MT      = 0x00000010,  
  19.   
  20.     /* The input device is a directional pad (implies keyboard, has DPAD keys). */  
  21.     INPUT_DEVICE_CLASS_DPAD          = 0x00000020,  
  22.   
  23.     /* The input device is a gamepad (implies keyboard, has BUTTON keys). */  
  24.     INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040,  
  25.   
  26.     /* The input device has switches. */  
  27.     INPUT_DEVICE_CLASS_SWITCH        = 0x00000080,  
  28.   
  29.     /* The input device is a joystick (implies gamepad, has joystick absolute axes). */  
  30.     INPUT_DEVICE_CLASS_JOYSTICK      = 0x00000100,  
  31.   
  32.     /* The input device is external (not built-in). */  
  33.     INPUT_DEVICE_CLASS_EXTERNAL      = 0x80000000,  
  34. }  
/* * Input device classes. */ enum { /* The input device is a keyboard or has buttons. */ INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, /* The input device is an alpha-numeric keyboard (not just a dial pad). */ INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ INPUT_DEVICE_CLASS_TOUCH = 0x00000004, /* The input device is a cursor device such as a trackball or mouse. */ INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, /* The input device is a directional pad (implies keyboard, has DPAD keys). */ INPUT_DEVICE_CLASS_DPAD = 0x00000020, /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, /* The input device has switches. */ INPUT_DEVICE_CLASS_SWITCH = 0x00000080, /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, /* The input device is external (not built-in). */ INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, }

      创建InputDevice对象之后, 对于多点触摸设备(class为INPUT_DEVICE_CLASS_TOUCH_MT),创建MultiTouchInputMapper对象并增加到InputDevice的mMappers向量列表中。

      对于单点触摸设备(class为INPUT_DEVICE_CLASS_TOUCH),创建SingleTouchInputMapper对象并增加到InputDevice的mMappers向量列表中。相关代码如下:

  1. InputDevice* InputReader::createDeviceLocked(int32_t deviceId,  
  2.         const String8& name, uint32_t classes) {  
  3.     InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);  
  4.   
  5.     ....  
  6.   
  7.     if (keyboardSource != 0) {  
  8.         device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));  
  9.     }  
  10.   
  11.     // Cursor-like devices.  
  12.     if (classes & INPUT_DEVICE_CLASS_CURSOR) {  
  13.         device->addMapper(new CursorInputMapper(device));  
  14.     }  
  15.   
  16.     // Touchscreens and touchpad devices.  
  17.     if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {  
  18.         device->addMapper(new MultiTouchInputMapper(device));  
  19.     } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {  
  20.         device->addMapper(new SingleTouchInputMapper(device));  
  21.     }  
  22.   
  23.     // Joystick-like devices.  
  24.     if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {  
  25.         device->addMapper(new JoystickInputMapper(device));  
  26.     }  
  27.   
  28.     return device;  
  29. }  
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, const String8& name, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, name, classes); .... if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { device->addMapper(new JoystickInputMapper(device)); } return device; }


     总之,它调用createDeviceLocked创建一个InputDevice设备,并根据class类别创建对应的事件转换器(InputMapper),然后把这些新那建的InputMapper增加到InputDevice::mMappers中。InputMapper关系如下图所示:


        

   2)调用InputDevice::configure配置此InputDevice

   3)调用InputDevice::reset重置此InputDevice

   4)把新建的InputDevice增加到InputReader::mDevices中。

   InputReader::processEventsLocked设备增加、删除处理总结:

     它负责处理Device 增加、删除事件。增加事件的流程为:为一个新增的Device创建一个InputDevice,并增加到InputReader::mDevices中;根据新增加设备的class类别,创建对应的消息转换器(InputMapper),然后此消息转换器加入InputDevice::mMappers中。消息转换器负责把读取的RawEvent转换成特定的事件,以供应用程序使用。

     EventHub与InputReader各自管理功能:

     1)EventHub管理一堆Device,每一个Device与Kernel中一个事件输入设备对应

     2)InputReader管理一堆InputDevice,每一个InputDevice与EventHub中的Device对应

     3)InputDevice管理一些与之相关的InputMapper,每一个InputMapper与一个特定的应用事件相对应,如:SingleTouchInputMapper。

          

     

     

  评论这张
 
阅读(1653)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017