Android系统input系统

Posted 写了程序换酒钱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统input系统相关的知识,希望对你有一定的参考价值。

我们平台的build system移植于android,在android组件中,我们使用了Binder驱动,来实现进程间的交互,对于input系统,因为我们将android的java application framework换成了Qt,为了实现更好的图形渲染,主要是我们需要实现主从设备的显示屏公用,这样我们需要将从设备的surface传输到主设备的来实现不同设备间的surface合成,来实现主从设备共同显示。我们使用了Wayland,其自带input系统。今天我深入android源码,看看android是怎么样来完成input设备的插拔和事件监听,和事件的分发。

源码位置

这个我们以4.4.4的源码为基础。
一个在先android源码阅读网站:androidxref

input相关源码
/frameworks/native/include/android/
/frameworks/native/include/input/
/frameworks/native/libs/input/
/frameworks/base/services/input/
/frameworks/base/services/java/com/android/server/input/
/frameworks/base/services/jni/

先看这个文件
/frameworks/native/include/android/input.h
这个文件定义了android系统input相关的枚举值和一些辅助函数。input事件主要分为两种一种是Key按下抬起事件,另一种是移动事件,比如触摸屏手势,TouchPad的Cursor移动。

整个流程

Input系统分为分为两个部分,一个是事件的读取,一个是分发,分别对应/frameworks/base/services/input/InputReader.cpp和/frameworks/base/services/input/InputDispatcher.cpp。他们分别运行在不同的线程。

input事件监听

linux系统input系统,当有输入设备插拔的时候,会在/dev/input目录下生成和删除相应的驱动文件。这里介绍一个重要的类EventHub,其封装了事件监听相关的操作。android使用epoll来实现I/O的事件的监听,以前我也在博文中介绍过epoll,用于高性能的服务器开发。

   mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);

   mINotifyFd = inotify_init();
   int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
            DEVICE_PATH, errno);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
  eventItem.data.u32 = EPOLL_ID_INOTIFY;
   result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

使用inotify来实现/dev/input目录的监听,将inotify的句柄加入到epoll的监听链表中实现当设备插拔时的事件监听。
InputReaderloopOnce中通过调用EventHubgetEvent函数来驱input事件监听。
设备插拔监听
在将inotify的id加入epoll时

    struct epoll_event eventItem;
  memset(&eventItem, 0, sizeof(eventItem));
  eventItem.events = EPOLLIN;
   eventItem.data.u32 = EPOLL_ID_INOTIFY;

EPOLL_ID_INOTIFY作为额外参数传入
这样

   const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
          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;
            

根据这个标识我们mPendingINotify置成true,这样在epell_wait 调用后来执行设备插拔操作

     if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) 
         mPendingINotify = false;
         readNotifyLocked();
            deviceChanged = true;
     

readNotifyLocked函数去读取/dev/input目录下的create和delete的事件。

1462 status_t EventHub::readNotifyLocked() 
1463    int res;
1464    char devname[PATH_MAX];
1465    char *filename;
1466    char event_buf[512];
1467    int event_size;
1468    int event_pos = 0;
1469    struct inotify_event *event;
1470
1471    ALOGV("EventHub::readNotify nfd: %d\\n", mINotifyFd);
1472    res = read(mINotifyFd, event_buf, sizeof(event_buf));
1473    if(res < (int)sizeof(*event)) 
1474        if(errno == EINTR)
1475            return 0;
1476        ALOGW("could not get event, %s\\n", strerror(errno));
1477        return -1;
1478    
1479    //printf("got %d bytes of event information\\n", res);
1480
1481    strcpy(devname, DEVICE_PATH);
1482    filename = devname + strlen(devname);
1483    *filename++ = '/';
1484
1485    while(res >= (int)sizeof(*event)) 
1486        event = (struct inotify_event *)(event_buf + event_pos);
1487        //printf("%d: %08x \\"%s\\"\\n", event->wd, event->mask, event->len ? event->name : "");
1488        if(event->len) 
1489            strcpy(filename, event->name);
1490            if(event->mask & IN_CREATE) 
1491                openDeviceLocked(devname);
1492             else 
1493                ALOGI("Removing device '%s' due to inotify event\\n", devname);
1494                closeDeviceByPathLocked(devname);
1495            
1496        
1497        event_size = sizeof(*event) + event->len;
1498        res -= event_size;
1499        event_pos += event_size;
1500    
1501    return 0;
1502

这里读出每个事件然后与/dev/input拼接成devicename来,然后根据是插拔来调用打开还是关闭驱动文件。
opendeviceLocked函数根据传入的设备名,来开发设备,然后实例化一个Device对象,然后通过ioctl调用来获得设备的各种信息,然后给设备分配一个deviceId,其初始值为1,然后递加分配。

    int32_t deviceId = mNextDeviceId++;

然后是比较重要的一步,就是知道是什么输入设备,是KeyBoard,Cursor,单点屏幕,多点屏幕还是joystick。这个很重要,决定了对raw数据的解析和上层将数据作为Key还是Motion处理。这之后还有一些需要处理,比如为KeyBoard配置Key映射表,设备是否有特殊的部分,内核驱动是否KEY支持repeat。
重要的一步

1245    struct epoll_event eventItem;
1246    memset(&eventItem, 0, sizeof(eventItem));
1247    eventItem.events = EPOLLIN;
1248    eventItem.data.u32 = deviceId;
1249    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) 
1250        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
1251        delete device;
1252        return -1;
1253    

将设备加入到epoll中,这样就能监听设备操作了,eventItem.data.u32 = deviceId;可以知道那个设备的事件,根据deviceId可以知道那个设备,就知道怎么对数据进行处理了。
在’InputReadner’中在loopOnce调用了EventHub::getEvents后使用

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) 
311    for (const RawEvent* rawEvent = rawEvents; count;) 
312        int32_t type = rawEvent->type;
313        size_t batchSize = 1;
314        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) 
315            int32_t deviceId = rawEvent->deviceId;
316            while (batchSize < count) 
317                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
318                        || rawEvent[batchSize].deviceId != deviceId) 
319                    break;
320                
321                batchSize += 1;
322            
323#if DEBUG_RAW_EVENTS
324            ALOGD("BatchSize: %d Count: %d", batchSize, count);
325#endif
326            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
327         else 
328            switch (rawEvent->type) 
329            case EventHubInterface::DEVICE_ADDED:
330                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
331                break;
332            case EventHubInterface::DEVICE_REMOVED:
333                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
334                break;
335            case EventHubInterface::FINISHED_DEVICE_SCAN:
336                handleConfigurationChangedLocked(rawEvent->when);
337                break;
338            default:
339                ALOG_ASSERT(false); // can't happen
340                break;
341            
342        
343        count -= batchSize;
344        rawEvent += batchSize;
345    
346

来处理事件
先来看device add事件

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) 
349    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
350    if (deviceIndex >= 0) 
351        ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
352        return;
353    
354
355    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
356    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
357    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
358
359    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
360    device->configure(when, &mConfig, 0);
361    device->reset(when);
362
363    if (device->isIgnored()) 
364        ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
365                identifier.name.string());
366     else 
367        ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
368                identifier.name.string(), device->getSources());
369    
370
371    mDevices.add(deviceId, device);
372    bumpGenerationLocked();
373

这里从EventHub中获得这个设备的相关属性,然后创建一个对应的InputDevice对象。

399InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
400        const InputDeviceIdentifier& identifier, uint32_t classes) 
401    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
402            controllerNumber, identifier, classes);
403
404    // External devices.
405    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) 
406        device->setExternal(true);
407    
408
409    // Switch-like devices.
410    if (classes & INPUT_DEVICE_CLASS_SWITCH) 
411        device->addMapper(new SwitchInputMapper(device));
412    
413
414    // Vibrator-like devices.
415    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) 
416        device->addMapper(new VibratorInputMapper(device));
417    
418
419    // Keyboard-like devices.
420    uint32_t keyboardSource = 0;
421    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
422    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) 
423        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
424    
425    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) 
426        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
427    
428    if (classes & INPUT_DEVICE_CLASS_DPAD) 
429        keyboardSource |= AINPUT_SOURCE_DPAD;
430    
431    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) 
432        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
433    
434
435    if (keyboardSource != 0) 
436        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
437    
438
439    // Cursor-like devices.
440    if (classes & INPUT_DEVICE_CLASS_CURSOR) 
441        device->addMapper(new CursorInputMapper(device));
442    
443
444    // Touchscreens and touchpad devices.
445    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) 
446        device->addMapper(new MultiTouchInputMapper(device));
447     else if (classes & INPUT_DEVICE_CLASS_TOUCH) 
448        device->addMapper(new SingleTouchInputMapper(device));
449    
450
451    // Joystick-like devices.
452    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) 
453        device->addMapper(new JoystickInputMapper(device));
454    
455
456    return device;
457

这边就知道我们在EventHub里面添加设备的时候为什么需要得知设备的相关属性。这边为每个设备产生不同的设备的数据处理类。
下面是对设备输入数据的处理

459void InputReader::processEventsForDeviceLocked(int32_t deviceId,
460        const RawEvent* rawEvents, size_t count) 
461    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
462    if (deviceIndex < 0) 
463        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
464        return;
465    
466
467    InputDevice* device = mDevices.valueAt(deviceIndex);
468    if (device->isIgnored()) 
469        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
470        return;
471    
472
473    device->process(rawEvents, count);
474

这边会根据deviceId来获得InputDevice对象,使用process来处理这些事件。

952void InputDevice::process(const RawEvent* rawEvents, size_t count) 
953    // Process all of the events in order for each mapper.
954    // We cannot simply ask each mapper to process them in bulk because mappers may
955    // have side-effects that must be interleaved.  For example, joystick movement events and
956    // gamepad button presses are handled by different mappers but they should be dispatched
957    // in the order received.
958    size_t numMappers = mMappers.size();
959    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) 
960#if DEBUG_RAW_EVENTS
961        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
962                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
963                rawEvent->when);
964#endif
965
966        if (mDropUntilNextSync) 
967            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) 
968                mDropUntilNextSync = false;
969#if DEBUG_RAW_EVENTS
970                ALOGD("Recovered from input event buffer overrun.");
971#endif
972             else 
973#if DEBUG_RAW_EVENTS
974                ALOGD("Dropped input event while waiting for next input sync.");
975#endif
976            
977         else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) 
978            ALOGI("Detected input event buffer overrun for device %s.", getName().string());
979            mDropUntilNextSync = true;
980            reset(rawEvent->when);
981         else 
982            for (size_t i = 0; i < numMappers; i++) 
983                InputMapper* mapper = mMappers[i];
984                mapper->process(rawEvent);
985            
986        
987    
988

然后使用设备对应的InputMapper们来处理事件。
这里我们以KEY事件为例子查看KeyboardInputMapper
最终会调到

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) 

这个方法,其在内部会将其打包成一个NotifyKeyArgs对象,通过注册下来的监听类来通知KEY到来。

    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
          down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
           AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
   getListener()->notifyKey(&args);

而这个监听类就是我们下面说的分发类InputDispatcher,其实现了
InputListenerInterface类的相关接口,比如notifyKey
InputDispatchernotifyKey中,我们根据参数产生一个
KeyEntry然后进队。

2410        int32_t repeatCount = 0;
2411        KeyEntry* newEntry = new KeyEntry(args->eventTime,
2412                args->deviceId, args->source, policyFlags,
2413                args->action, flags, args->keyCode, args->scanCode,
2414                metaState, repeatCount, args->downTime);
2415
2416        needWake = enqueueInboundEventLocked(newEntry);

这些输入事件其会放入一个名为mInboundQueueQueue<EventEntry>对象中。

InputDispathcer在独立的线程运行。

4465bool InputDispatcherThread::threadLoop() 
4466    mDispatcher->dispatchOnce();
4467    return true;
4468

其会不停的调用dispatchOnce,就像InputReader不停调用loopOnce一样。
(1)dispatchOnce
(2)dispatchOnceInnerLocked,出队一个mPendingEvent = mInboundQueue.dequeueAtHead()
(3)dispatchKeyLocked
(4)dispatchEventLocked
(5)prepareDispatchCycleLocked
(6)enqueueDispatchEntriesLocked
(7)startDispatchCycleLocked,这样完成了一个事件的派发。

InputManager实现对reade和dispatcher的线程的管理。

下面一篇将讲java层和c++层的关于事件分发,以及事件怎么发送到application和Window。

以上是关于Android系统input系统的主要内容,如果未能解决你的问题,请参考以下文章

Android系统input系统

Android R input 之 InputManagerService 的建立

Android R input 之 InputManagerService 的建立

Android系统源码阅读(13):Input消息的分发过程

Android中Input型输入设备驱动原理分析

Linux/Android——输入子系统input_event传递