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

 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中同样,有本身门户了。node

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

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中的友好多了,分别处理:固定长度命令、单个可变 长度命令和多个可变长度命令。app

      对于为何个人TouchScreen在Android4.0不工做,答案显而易见,我用的Kernel版本不对,固然移植到Android4.0对应的 Kernel(Kernel3.0.8)时,TouchScreen驱动自己也须要修改,由于input_dev变化也比较大,好比增长了propbit 字段,以供处理上面的ioctl时使用。异步

 

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

       正是因为遇到上面的问题,才促使本身对Event Input进行深刻了解。由于走马观花不是小弟的性格。ide

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

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

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

       2)读取设备输入流程?this

       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读取的事件数据结构以下:

[cpp] view plaincopy

  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. };  

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

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定义以下:

[cpp] view plaincopy

  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. };  

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

[cpp] view plaincopy

  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. }  

4.2.1 查看设备上是否有事件


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

[cpp] view plaincopy

  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中,其相关代码以下:

[plain] view plaincopy

  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.                         }  


     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)处理设备增长、删除和修改事件

       按照程序执行流程,应该是先有设备,而后才会有设备事件,因此先分析设备增长。 其代码以下:

 

[plain] view plaincopy

  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>  

 

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成员,它用于表示设备类型,其定义以下:

[plain] view plaincopy

  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. }  

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

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

[plain] view plaincopy

  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. }  


     总之,它调用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。

          

4.3.1.1.2 事件驱动设备事件处理processEventsForDeviceLocked

   下面的分析处理以单点触摸为例,对于单点触摸Touch Down时,它将报告如下事件:

    代码:

    input_report_abs(myInputDev, ABS_X, event->x);
    input_report_abs(myInputDev, ABS_Y, event->y);

    产生的事件:*type, code, value
                          EV_ABS,ABS_X,event->x
                          EV_ABS,ABS_Y,event->y     

    代码: 

    input_report_key(myInputDev, BTN_TOUCH,  1);
    产生的事件:*type, code, value
                          EV_KEY, BTN_TOUCH, 1

     代码:

      input_sync(myInputDev);
        它调用input_event(dev, EV_SYN, SYN_REPORT, 0);
     产生的事件:*type, code, value
                           EV_SYN, SYN_REPORT, 0

      

     它负责处理来自于同一个设备且在mEventBuffer中连续的多个事件,其函数原型以下:

[plain] view plaincopy

  1. void InputReader::processEventsForDeviceLocked(int32_t deviceId,  

  2.         const RawEvent* rawEvents, size_t count) {  

  3.     ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  

  4.     if (deviceIndex < 0) {  

  5.         LOGW("Discarding event for unknown deviceId %d.", deviceId);  

  6.         return;  

  7.     }  

  8.   

  9.     InputDevice* device = mDevices.valueAt(deviceIndex);  

  10.     if (device->isIgnored()) {  

  11.         //LOGD("Discarding event for ignored deviceId %d.", deviceId);  

  12.         return;  

  13.     }  

  14.   

  15.     device->process(rawEvents, count);  

  16. }  

它其实很简单,根据输入的deviceId找到对应的InputDevice,而后调用InputDevice::process以对设备输入事件进行处理。InputDevice::process主要源码以下:

 

[plain] view plaincopy

  1. void InputDevice::process(const RawEvent* rawEvents, size_t count) {  

  2.     // Process all of the events in order for each mapper.  

  3.     // We cannot simply ask each mapper to process them in bulk because mappers may  

  4.     // have side-effects that must be interleaved.  For example, joystick movement events and  

  5.     // gamepad button presses are handled by different mappers but they should be dispatched  

  6.     // in the order received.  

  7.   

  8.     size_t numMappers = mMappers.size();  

  9.     for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++)   

  10.     {  

  11.         for (size_t i = 0; i < numMappers; i++) {  

  12.             InputMapper* mapper = mMappers[i];  

  13.             mapper->process(rawEvent);  

  14.         }  

  15.     }  

  16. }  

       从上面的代码中能够看出,在InputDevice::process中,对于传入的每个RawEvent,依次调用InputDevice中的每个 InputMapper来进行处理。前面提到过,InputDevice包含一组处理对应设备事件InputMapper,如今这些 InputMapper开始干活了。
      下面以处理一个单点触摸事件设备的事件为例,进行分析,其它的处理流程相似。对于mapper->process须要查看 InputReader::createDeviceLocked中建立的具体的InputMapper的process函数。下面就看看 SingleTouchInputMapper的process是如何处理的,其代码以下:

[plain] view plaincopy

  1. void SingleTouchInputMapper::process(const RawEvent* rawEvent) {  

  2.     TouchInputMapper::process(rawEvent);  

  3.   

  4.     mSingleTouchMotionAccumulator.process(rawEvent);  

  5. }  

1)TouchInputMapper::process

       因而可知,它将首先调用TouchInputMaaper::process处理此事件,其处理代码以下:

[plain] view plaincopy

  1. void TouchInputMapper::process(const RawEvent* rawEvent) {  

  2.     mCursorButtonAccumulator.process(rawEvent);  

  3.     mCursorScrollAccumulator.process(rawEvent);  

  4.     mTouchButtonAccumulator.process(rawEvent);  

  5.   

  6.     if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {  

  7.         sync(rawEvent->when);  

  8.     }  

  9. }  


1.1) mCursorButtonAccumulator.process(rawEvent)

     记录mouse或touch pad按键状态,记录rawEvent->type为EV_KEY,且rawEvent->scanCode为BTN_LEFT、BTN_RIGHT、BTN_MIDDLE、BTN_BACK、BTN_SIDE、BTN_FORWARD、BTN_EXTRA、BTN_TASK的事件。

1.2) mCursorScrollAccumulator.process(rawEvent)

     记录cursor scrolling motions,记录rawEvent->type为EV_REL,且rawEvent->scanCode为REL_WHEEL、REL_HWHEEL的事件。

1.3) mTouchButtonAccumulator.process(rawEvent)

     记录touch, stylus and tool buttons状态,记录rawEvent->type为EV_KEY,且rawEvent->scanCode为BTN_TOUCH、 BTN_STYLUS、BTN_STYLUS二、BTN_TOOL_FINGER、BTN_TOOL_PEN、BTN_TOOL_RUBBER、 BTN_TOOL_BRUSH、BTN_TOOL_PENCIL、BTN_TOOL_AIRBRUSH、BTN_TOOL_MOUSE、 BTN_TOOL_LENS、BTN_TOOL_DOUBLETAP、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP的事件。

     看到了吧,咱们的BTN_TOUCH在这儿被处理了,且其value被保存在mBtnTouch成员变量中。

1.4) sync(rawEvent->when)

      处理EV_SYN:SYN_REPORT,咱们的EV_SYN就在这儿被处理了,固然它是Touch Down时,所发事件的最后一个事件。这儿才是处理的重点。

      TouchInputMapper::sync将调用SingleTouchInputMapper::syncTouch函数。

      a)SingleTouchInputMapper::syncTouch

      把mCurrentRawPointerData中的ABS_X和ABS_Y的值保存在TouchInputMapper::mCurrentRawPointerData->pointers中。

          单点触摸的syncTouch一次处理一个RawEvent,在pointers中只有一个值;而多点触摸的syncTouch一次处理多个RawEvent,在pointers中有多个值,最多16个。

      b)TouchInputMapper::cookPointerData

      根据TouchInputMapper::mCurrentRawPointerData->pointers中的数据,经过计算,最后生成 TouchInputMapper::mCurrentCookedPointerData.pointerCoords,mCurrentCookedPointerData.pointerProperties 和mCurrentCookedPointerData.idToIndex的数据。把Raw进行cook,以后生成了cooked数据。

      c)TouchInputMapper::dispatchHoverExit

 

      d)TouchInputMapper::dispatchTouches

      d.a)它调用dispatchMotion

      d.b)在dispatchMotion中,根据cooked数据建立NotifyMotionArg对象,它描述了一个移动事件

      d.c)调用TouchInputMapper::getListener()->notifyMotion(&args)

              TouchInputMapper::getListener()调用mContext->getListener(),此mContext为InputReader::mContext,因此其getListener()返回的则为InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion

       补充1) InputReader::mContext在构造时用本身的指针初始化了mContext,从而mContext::mReader则为此InputReader实例。
       补充2) 在InputReader::createDeviceLocked中建立InputDevice时,把本身的mContext做为参数传入,从而把它保 存在InputDevice::mContext中;在建立InputMapper时,以InputDevice做为参数,且InputMapper把它 保存在mDevice中,而后从把InputDevice中的mContext也保存在InputMapper的mContext中。

      d.d)把传递过来的NotifyMotionArg参数复制一份,而后加入QueuedInputListener::mArgsQueue例表中。

 

      e)TouchInputMapper::dispatchHoverEnterAndMove

          

         

 

2)mSingleTouchMotionAccumulator.process 


     记录ABS相关的值,记录rawEvent->type为EV_ABS,且rawEvent->scanCode为ABS_X、ABS_Y、ABS_PRESSURE、ABS_TOOL_WIDTH、ABS_DISTANCE、ABS_TILT_X、ABS_TILT_Y的事件。咱们发的ABS_X和ABS_Y在这儿被处理了。

 

     事件处理相关数据结构以下图所示:     

 

 

4.3.1.2 InputReader::mQueuedListener->flush()

      先温习一下,至此的消息结构变化流程:

     

      processEventsLocked已经把来自于事件设备的事件煮熟以后放入到各类NotifyArgs(如NotifyMotionArgs)之 中,而后把这些各类NotifyArgs加入InputReader::mQueuedListener::mArgsQueue链表中。本Flush函 数就是要把mArgsQueue中的全部NotifyArgs进行处理。为描述方便,先看看其代码:

 

[plain] view plaincopy

  1. void QueuedInputListener::flush() {  

  2.     size_t count = mArgsQueue.size();  

  3.     for (size_t i = 0; i < count; i++) {  

  4.         NotifyArgs* args = mArgsQueue[i];  

  5.         args->notify(mInnerListener);  

  6.         delete args;  

  7.     }  

  8.     mArgsQueue.clear();  

  9. }  


       看到了吧,确实很简单,调用链表中每一个NotifyArgs的notify函数,且有一个有意思的参数 mInnerListener,这个参数在前面多 次提到过,它是在建立mQueuedListener时提供的,它其实就是InputManager中的mDispatcher,前面一直在 InputReader中打转转,如今终于看到InputDispatcher登场了,说明事件很快就能够谢幕了。

       再向下看一下吧,这么多类NotifyArgs,为描述方便,下面以NotifyMotionArgs为例,其代码为: 

  

[cpp] view plaincopy

  1. void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {  

  2.     listener->notifyMotion(this);  

  3. }  

      下面就看看InputDispatcher(mDispatcher)的notifyMotion函数作了些什么。这个InputDispatcher::notifyMotion(const NotifyMotionArgs* args)可就不简单了。

       在InputDispatcher::notifyMotion中,
       1)根据NotifyMotionArgs提供的信息,构造一个MotionEvent,再调用 mPolicy->filterInputEvent看是否须要丢弃此事件,若是须要丢弃则立刻返加。其中mPolicy为 NativeInputManager实例,在构造InputDispatcher时提供的参数。

       2)对于AMOTION_EVENT_ACTION_UP或AMOTION_EVENT_ACTION_DOWN事件,则直接根据NotifyMotionArgs提供的信息,构造一个MotionEntry。

       3)调用InputDispatcher::enqueueInboundEventLocked把新构造的MotionEntry添加到InputDispatcher::mInboundQueue中,并返回是否须要唤醒mLooper<向pipe中写入数据>的标识。

      以上操做都是在InputReader线程中完成的,如今应该InputDispatcher线程开始工做了。

4. 4 分发输入事件

InputDispatcherThread主循环以下:

Thread::_threadLoop->

   InputDispatcherThread::threadLoop->

      mDispatcher->dispatchOnce(InputDispatcher::dispatchOnce)->

          dispatchOnceInnerLocked then

          mLooper->pollOnce

下面先看看简单的mLooper->pollOnce

 4.4.1 mLooper->pollOnce 

      其功能为等待超时或被pipe唤醒(InputReader线程调用InputDispatcher::notifyMotion时, InputDispatcher::notifyMotion根据状况调用mLooper->wake)。

      其调用流程以下:

      mLooper->pollOnce(int timeoutMillis)->

         Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData)->

4.4.2 dispatchOnceInnerLocked         

      1)从mInboundQueue从中依次取出EventEntry<MotionEntry的基类>

      2)调用InputDispatcher::dispatchMotionLocked处理此MotionEntry

      3)调用InputDispatcher::dispatchEventToCurrentInputTargetsLocked

            对于InputDispatcher::mCurrentInputTargets中的每个InputTarget,并获取对应的 Connection,调用InputDispatcher::prepareDispatchCycleLocked,

其相关代码以下:

 

[cpp] view plaincopy

  1.   <span style="font-size:10px;">  for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {  

  2.         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);  

  3.   

  4.         ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);  

  5.         if (connectionIndex >= 0) {  

  6.             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);  

  7.             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,  

  8.                     resumeWithAppendedMotionSample);  

  9.         } else {  

  10. #if DEBUG_FOCUS  

  11.             LOGD("Dropping event delivery to target with channel '%s' because it "  

  12.                     "is no longer registered with the input dispatcher.",  

  13.                     inputTarget.inputChannel->getName().string());  

  14. #endif  

  15.         }  

  16.     }</span>  

      4)InputDispatcher::prepareDispatchCycleLocked

           4.1)调用enqueueDispatchEntryLocked建立DispatchEntry对象,并把它增长到Connection::outboundQueue队列中。

           4.2)调用activateConnectionLocked把当前Connection增长到InputDispatcher::mActiveConnections链表中

           4.3)调用InputDispatcher::startDispatchCycleLocked,接着它调用Connection::inputPublisher.publishMotionEvent来发布事件到ashmem buffer中,调用Connection::inputPublisher.sendDispatchSignal发送一个dispatch信号到InputConsumer通知它有一个新的消息到了,快来消费吧!  关于消费者如何注册和如何消息的流程在下一个专题中再写。本文到此结束!!!  

相关文章
相关标签/搜索