AndroidR Input子系统(3)InputReader线程读取输入事件

上一篇文章分析了Input系统的启动之后会通过INotify与Epoll监听dev/input/目录下文件的创建和删除,并且启动两个线程InputReaderInputDispatcherInputReader启动之后调用其loopOnce()函数,InputDispatcher启动之后调用其dispatchOnce函数,它们都是死循环的调用,这篇文章就先来看看InputReaderloopOnce()函数:

loopOnce

//InputReader.cpp
void InputReader::loopOnce() {
    //(1)
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
    //(2)
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            //(3)
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {

                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }
        //(4)
        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}

这个函数比较复杂,我们分为四部分来依次分析,首先来看第一部分(1):

void InputReader::loopOnce() {
    //(1)
    int32_t oldGeneration;
    int32_t timeoutMillis;
    //dev/input目录下的设备节点是否发生变化,增加或删除
    bool inputDevicesChanged = false;
    //InputDeviceInfo描述了dev/input目录下的设备节点信息,inputDevices为
    //InputDeviceInfo集合
    std::vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
    ...
    //(2)
    ...
    //(3)
    ...
    //(4)
    ...  
  }

第一部分首先定义了一些变量,inputDevicesChanged用来描述dev/input目录下的设备节点是否发生变化(增加或删除),通过adb shell getevent查看dev/input目录下的设备节点:
在这里插入图片描述
比如我自己的手机有7个设备节点,每一个设备节点都对应了一张kl(key layout)表,如果外接一个键盘或游戏手柄就可能会增加设备节点,这时inputDevicesChanged就会发生变化,变量inputDevices代表一个InputDeviceInfo的集合,InputDeviceInfo描述了dev/input目录这些输入设备节点的特性和功能(例如设备ID,kl表名称),变量mGeneration会在dev/input设备节点增加或删除时发生变化,变量mConfigurationChangesToRefresh描述了一些input配置信息的变化,由函数requestRefreshConfiguration进行修改,

void InputReader::requestRefreshConfiguration(uint32_t changes) {
    AutoMutex _l(mLock);

    if (changes) {
        bool needWake = !mConfigurationChangesToRefresh;
        mConfigurationChangesToRefresh |= changes;

        if (needWake) {
            mEventHub->wake();
        }
    }
}

参数changes可以是以下枚举值

struct InputReaderConfiguration {
    // Describes changes that have occurred.
    enum {
        // The pointer speed changed.
        CHANGE_POINTER_SPEED = 1 << 0,

        // The pointer gesture control changed.
        CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1,

        // The display size or orientation changed.
        CHANGE_DISPLAY_INFO = 1 << 2,

        // The visible touches option changed.
        CHANGE_SHOW_TOUCHES = 1 << 3,

        // The keyboard layouts must be reloaded.
        CHANGE_KEYBOARD_LAYOUTS = 1 << 4,

        // The device name alias supplied by the may have changed for some devices.
        CHANGE_DEVICE_ALIAS = 1 << 5,

        // The location calibration matrix changed.
        CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,

        // The presence of an external stylus has changed.
        CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,

        // The pointer capture mode has changed.
        CHANGE_POINTER_CAPTURE = 1 << 8,

        // The set of disabled input devices (disabledDevices) has changed.
        CHANGE_ENABLED_STATE = 1 << 9,

        // All devices must be reopened.
        CHANGE_MUST_REOPEN = 1 << 31,
    };

什么情况下Input的配置信息会发生变化呢?比如我们在手机开发者选项中开关"显示按键反馈"就对应CHANGE_SHOW_TOUCHES的设置,其他的值我没测试过也不太清楚怎么操作,但从注释也能直观感受,比如CHANGE_POINTER_SPEED修改指针速度,CHANGE_DISPLAY_INFO 屏幕大小或方法变化,CHANGE_KEYBOARD_LAYOUTS键盘重布局等,待以后有空来测试一下这些值然后再修改文章…

当Input配置信息改变之后则调用refreshConfigurationLocked进行更新,refreshConfigurationLocked这部分细节不是我们分析重点,就不细看了。

接着来分析loopOnce第二部分:

void InputReader::loopOnce() {
    //(1)
    ...
    //(2)
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    ...
    //(3)
    ...
    //(4)
    ...  
  }

这部分就是InputReader的核心,从EventHub读取事件,参数mEventBuffer是一个存储RawEvent的数组,大小为EVENT_BUFFER_SIZE(256):

	//InputReader.h
    // The event queue.
    static const int EVENT_BUFFER_SIZE = 256;
    RawEvent mEventBuffer[EVENT_BUFFER_SIZE];

RawEvent 描述了一个输入事件的原始事件结构体,

/*
 * A raw event as retrieved from the EventHub.
 */
 //EventHub.h
struct RawEvent {
    nsecs_t when;    //事件发生的事件
    int32_t deviceId;   //事件发生的设备节点ID
    int32_t type;		//事件的类型
    int32_t code;		//扫描码scancode
    int32_t value;
};

EventHub->getEvents

继续来看EventHubgetEvents函数:

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);

        // 是否需要重新打开设备
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;
            //关闭所有设备
            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

        // 是否删除所有设备
        while (mClosingDevices) {
            Device* device = mClosingDevices;
           
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = (device->id == mBuiltInKeyboardId)
                    ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
                    : device->id;
            //添加设备删除事件
            event->type = DEVICE_REMOVED;
            event += 1;
            //删除
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            //设备数量达到256则break
            if (--capacity == 0) {
                break;
            }
        }
        //是否需要扫描并打开设备,初始化为true
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            //扫描并打开设备
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }
		//是否正在打开的设备不为空
        while (mOpeningDevices != nullptr) {
            Device* device = mOpeningDevices;
           //指向下一个打开的设备
            mOpeningDevices = device->next;
            //当前时间
            event->when = now;
            //设备节点ID
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            //设备添加事件
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }
		//是否设备扫描完成
        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            //当前时间
            event->when = now;
            //添加设备扫描完成事件
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        bool deviceChanged = false;
        //mPendingEventCount描述了从dev/input目录下各个设备节点发生的事件个数,
        //初始化为0,
        //mPendingEventIndex 描述了正在处理的事件下标,初始化为0
        //这个while循环作用就是依次处理dev/input目录下各个设备节点
        //发生的所有事件,首次到这里时因为没有任何事件,则为fasle
        while (mPendingEventIndex < mPendingEventCount) {
            //mPendingEventItems是一个epoll_event类型数组,size为16,
            //epoll_event是用来描述通过epoll_wait监听到的内核事件,
            //这里的事件也就是监听mINotifyFd和mWakeReadPipeFd获取到的
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            //是否是监听mINotifyFd获取到的事件
            if (eventItem.data.fd == mINotifyFd) {
                //是否可以读取事件
                if (eventItem.events & EPOLLIN) {
                    //设置mPendingINotify为true,后面处理
                    mPendingINotify = true;
                } else {
                   ...
                }
                continue;
            }
            //是否是监听mWakeReadPipeFd获取到的事件
            if (eventItem.data.fd == mWakeReadPipeFd) {
               //从mWakeReadPipeFd读取到的事件不是我们分析重点,省略
               .......
            }
            //根据fd类型获取对应设备,可以是输入设备或者视频设备(不太清楚视频设备相关)
            //Device是用来描述dev/input目录下设备节点信息的结构体
            Device* device = getDeviceByFdLocked(eventItem.data.fd);
            if (!device) {
               ...
                continue;
            }
            //是否是视频设备
            if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
               //不是重点,省略
                ....
                continue;
            }
            //可读取的input事件
            if (eventItem.events & EPOLLIN) {
                //通过read函数读取dev/input目录下各个设备节点发生的事件,device->fd
                //的值是在打开设备时赋值的,其实就是dev/input目录下的各个设备节点
                //将事件放入readBuffer数组
                //readSize / sizeof(struct input_event) = 事件个数,必须为整数倍,否则
                //读取异常。
                int32_t readSize =
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                //异常情况
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // Device was removed before INotify noticed.
                   ...
                    deviceChanged = true;
                    closeDeviceLocked(device);
                    //异常情况
                } else if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        
                    }
                    //异常情况
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                   ...
                } else {//处理事件
                    //mBuiltInKeyboardId是一个枚举值NO_BUILT_IN_KEYBOARD,具体含义不是
                    //太清楚,但从dump的input信息看,一般device->id不会等于mBuiltInKeyboardId
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
                    //读取到的事件个数
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    //for循环分别处理每一个事件,将input_event转换为RawEvent
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        //将每一个事件都封装为原始事件RawEvent
                        event->when = processEventTimestamp(iev);
                        //事件的设备节点ID
                        event->deviceId = deviceId;
                        //事件类型
                        event->type = iev.type;
                        //事件code
                        event->code = iev.code;
                        //事件value
                        event->value = iev.value;
                        //指向下一个事件
                        event += 1;
                        //容量-1
                        capacity -= 1;
                    }
                    //事件满了
                    if (capacity == 0) {
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
                //异常情况,发生不合法事件
            } else if (eventItem.events & EPOLLHUP) {
                deviceChanged = true;
                //关闭设备
                closeDeviceLocked(device);
            } else {
               //异常情况,发生不合法事件
                device->identifier.name.c_str());
            }
        }

        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        //mPendingINotify 为true代表在mINotifyFd上读取到了dev/input目录下设备节点的
        //删除或者创建,mPendingEventIndex >= mPendingEventCount代表当前这一轮input
        //事件已经处理完成
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            //通知更新dev/input目录下设备节点
            readNotifyLocked();
            deviceChanged = true;
        }

        // 报告dev/input目录下设备节点发生了增加或者删除
        if (deviceChanged) {
            continue;
        }

        // 读取到事件,结束最开始的for(;;)
        if (event != buffer || awoken) {
            break;
        }

        // Poll for events.
        // When a device driver has pending (unread) events, it acquires
        // a kernel wake lock.  Once the last pending event has been read, the device
        // driver will release the kernel wake lock, but the epoll will hold the wakelock,
        // since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
        // is called again for the same fd that produced the event.
        // Thus the system can only sleep if there are no events pending or
        // currently being processed.
        //
        // The timeout is advisory only.  If the device is asleep, it will not wake just to
        // service the timeout.
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll
        //通过epoll_wait等待mEpollFd上事件发生,没有则阻塞,mEpollFd添加了mINotifyFd和
        //mWakeReadPipeFd监听,实际上就是监听mINotifyFd和mWakeReadPipeFd上发生的事件,
        //事件发生之后放入mPendingEventItems数组,返回值pollResult为事件的数量
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        mLock.lock(); // reacquire lock after poll
        //如果pollResult 为0,说明超时了,因为不超时会一直阻塞在epoll_wait
        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }
        //pollResult < 0,发生异常
        if (pollResult < 0) {
            // An error occurred.
            mPendingEventCount = 0;

            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
               
                usleep(100000);
            }
        } else {
            //发生事件的数量
            mPendingEventCount = size_t(pollResult);
        }
    }

    //返回获取到的事件数量
    return event - buffer;
}

getEvents这个函数非常的复杂,建议先对INotify与Epoll机制有所了解再来看,可以参考AndroidR Input子系统(1)INotify与Epoll机制,大部分的注释都已经写清楚了,耐心看,一定能看明白的,整个方法逻辑很简单,主要可以分为两大部分,

  1. 首次进入此函数时mNeedToScanDevices为true,会调用scanDevicesLocked扫描并打开设备,这个函数非常重要且复杂,下一篇文章单独分析。
  2. 通过epoll_wait等待mEpollFd上的事件发生,mEpollFd添加了mINotifyFdmWakeReadPipeFd监听,epoll_wait实际上就是等待mINotifyFdmWakeReadPipeFd上发生事件,事件发生之后放入mPendingEventItems数组,然后由一个while循环来处理这些事件,对于mINotifyFd发生的事件(设备节点的增删)则调用readNotifyLocked函数更新设备,对于input事件,则将事件封装为RawEvent

到此,getEvents函数已经看完了,下一篇文章我们会单独分析其中的scanDevicesLockedreadNotifyLocked这两个函数。

接着我们再回到loopOnce函数

void InputReader::loopOnce() {
    //(1)
    ...
    //(2)
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    ...
    //(3)
    ...
    //(4)
    ...  
  }

mEventHub->getEvents执行完成之后,mEventBuffer中已经填充好了input事件,第三部分就开始处理这些事件了:

//InputReader.cpp
void InputReader::loopOnce() {
    	//(1)
    	...
    	//(2)
    	...
    	//(3)
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
        ...
        //(4)
        ...
}

processEventsLocked

核心函数processEventsLocked

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    //遍历RawEvent数组
    for (const RawEvent* rawEvent = rawEvents; count;) {
        //事件类型
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        //小于FIRST_SYNTHETIC_EVENT代表除DEVICE_ADDED,DEVICE_REMOVED,
        //FINISHED_DEVICE_SCAN的其他事件
        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) {
                    //如果事件类型是DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN,
                    //或者不是发生在同一设备节点的事件则break
                    break;
                }
                //同一设备节点的事件数量
                batchSize += 1;
            }
            //处理事件
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
                //如果事件类型为DEVICE_ADDED
                case EventHubInterface::DEVICE_ADDED:
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                 //如果事件类型为DEVICE_REMOVED
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                 //如果事件类型为FINISHED_DEVICE_SCAN
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

事件类型:

enum {
        // 设备添加
        DEVICE_ADDED = 0x10000000,
        // 设备移除
        DEVICE_REMOVED = 0x20000000,
        // 设备扫描
        FINISHED_DEVICE_SCAN = 0x30000000,

        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
    };

processEventsLocked函数比较简单,就是根据事件的类型调不同的函数,我们先来看addDeviceLocked函数:

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        //如果要添加的设备已经存在则return
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }
    //InputDeviceIdentifier用来标识设备
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    //通过设备ID和InputDeviceIdentifier创建InputDevice
    std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
    device->configure(when, &mConfig, 0);
    device->reset(when);
    ....
    //将InputDevice和设备ID一一对应到mDevices这个map中
    mDevices.emplace(eventHubId, device);
    ...
}

通过adb shell getevent可以查看InputDeviceIdentifier的名称,每个设备节点都会对应一个InputDeviceIdentifier
在这里插入图片描述

InputReader::createDeviceLocked

接着再来看看createDeviceLocked函数创建InputDevice:

std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        int32_t eventHubId, const InputDeviceIdentifier& identifier) {
        //通过find_if判断要创建的InputDevice是否已经存在
    auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
        return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
                devicePair.second->getDescriptor() == identifier.descriptor;
    });

    std::shared_ptr<InputDevice> device;
    //已经存在
    if (deviceIt != mDevices.end()) {
        device = deviceIt->second;
    } else {
        //不存在则需要创建
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        //构造InputDevice传入了4个参数,mContext指向InputReader
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    //将设备ID添加到InputDevice
    device->addEventHubDevice(eventHubId);
    return device;
}

InputDevice::addEventHubDevice

void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
   
    if (mDevices.find(eventHubId) != mDevices.end()) {
        //如果已经添加过了直接return
        return;
    }
    //创建InputDeviceContext,这个类主要提供一些访问EventHub的函数
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    uint32_t classes = contextPtr->getDeviceClasses();
    //mappers是一个InputMapper类型的集合,
    //InputMapper是原始事件加工的类,不同类型事件对应不同InputMapper,
    //这里的类型有键盘,鼠标,触摸屏等,都是InputMapper子类
    std::vector<std::unique_ptr<InputMapper>> mappers;

    //populateMappers默认值为true
    if (!populateMappers) {
        mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
        return;
    }

    // 开关类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
    }

    // 滑动类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
        mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
    }

    //震动类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
        mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
    }

    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes & INPUT_DEVICE_CLASS_DPAD) {
        keyboardSource |= AINPUT_SOURCE_DPAD;
    }
    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    }
    //键盘类型InputMapper
    if (keyboardSource != 0) { 
        mappers.push_back(
                std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
    }

    //鼠标类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
    }

    //触摸屏类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
    }

    // 操纵杆类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
        mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
    }

    // 外部触控笔类型InputMapper
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
    }

    // mDevices是一个map,提供了eventHubId,contextPtr,InputMapper集合的一一映射,
    //即一个eventHubId对应一个InputDeviceContext对应一个InputMapper集合
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}

createDeviceLockedaddEventHubDevice函数主要功能就是创建了InputDevice,每一个eventHubId对应一个InputDevice,并将InputReadermContext传给了InputDevice,然后创建InputDeviceContext,此类提供一系列访问EventHub的函数,接着根据eventHubId,获取设备类型,根据设备类型创建不同的InputMapper,用于处理该设备的原始事件,每个InputMapper构造函数中都接收一个contextPtr用于访问EventHub,最后再InputDevicemDevices成员变量中提供eventHubId,contextPtr,mappers的一一映射。

再回到前面的addDeviceLocked函数, InputDevice创建完成之后便以eventHubId为key,InputDevice为value存入InputReadermDevices中。

到此addDeviceLocked这个函数就已经分析完了,我们已经大致清楚了当RawEvent的事件类型为DEVICE_ADDED时系统所作的事情,主要就两个,1.创建InputDevice,2.创建对应设备类型的InputMapper用于处理事件。

对于事件类型DEVICE_REMOVEDFINISHED_DEVICE_SCAN我们就不去分析了,本篇重点还是Input事件的处理,接着来看看对于除DEVICE_ADDED,DEVICE_REMOVED,FINISHED_DEVICE_SCAN的其他事件处理processEventsForDeviceLocked:

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return;
    }

    std::shared_ptr<InputDevice>& device = deviceIt->second;
    if (device->isIgnored()) {
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}

这个函数就很简单了,根据eventHubId,找到对应的InputDevice,然后调用其process函数处理对应设备节点发生的输入事件。

InputDevice::process

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // Process all of the events in order for each mapper.
    // We cannot simply ask each mapper to process them in bulk because mappers may
    // have side-effects that must be interleaved.  For example, joystick movement events and
    // gamepad button presses are handled by different mappers but they should be dispatched
    // in the order received.
    //遍历原始事件
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            } else {
                 ...
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
                mapper.process(rawEvent);
            });
        }
        --count;
    }
}

这个函数会遍历所有原始事件,依次进行处理,首先会对事件进行过滤,根据RawEvent的type和code决定如何处理,这个type和code是什么?
我们可以通过命令adb shell getevent -l进行查看,比如我点了一下power键亮屏就会有如下输出:
在这里插入图片描述
EV_KEY这一列就是type,KEY_POWER这一列就是code,DOWN这一列就是value,具体的含义可以查阅Linux 驱动输入子系统相关资料,我们继续看else分支的处理:

// run a function against every mapper on a specific subdevice
    inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
                                             std::function<void(InputMapper&)> f) {
        auto deviceIt = mDevices.find(eventHubDevice);
        if (deviceIt != mDevices.end()) {
            auto& devicePair = deviceIt->second;
            auto& mappers = devicePair.second;
            for (auto& mapperPtr : mappers) {
                f(*mapperPtr);
            }
        }
    }

这个函数我们首先看mDevices这个变量,

/*
    using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
    using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
    std::unordered_map<int32_t, DevicePair> mDevices;
*/
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
   ......
   
  // insert the context into the devices set
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}

我们在前面分析addEventHubDevice函数时已经知道了,mDevices是一个map,提供了eventHubId,contextPtr,InputMapper集合的一一映射(其中contextPtr,InputMapper被封装成了DevicePair,用作mDevices的value),忘了的可以回过头去看看,所以for_each_mapper_in_subdevice函数里的逻辑就是根据eventHubId,找到DevicePair,再从DevicePair中获取InputMapper集合,最后遍历mappers,并调用InputMapperprocess函数处理具体事件,InputMapper的种类有很多,键盘类型,鼠标类型,触摸类型等等,一个设备节点可能产生不同类型的事件,就需要不同的InputMapper处理,到此我们已经知道了原始事件最终其实是交给不同的InputMapper来处理的,所以InputMapper就是原始事件的加工厂。

我们接着以KeyboardInputMapper为例继续分析事件的处理:

KeyboardInputMapper::process

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
        case EV_KEY: {
            //扫描码
            int32_t scanCode = rawEvent->code;
            int32_t usageCode = mCurrentHidUsage;
            mCurrentHidUsage = 0;

            if (isKeyboardOrGamepadKey(scanCode)) {
                processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
            }
            break;
        }
        //其他事件
        case EV_MSC: {
            if (rawEvent->code == MSC_SCAN) {
                mCurrentHidUsage = rawEvent->value;
            }
            break;
        }
        //同步事件
        case EV_SYN: {
            if (rawEvent->code == SYN_REPORT) {
                mCurrentHidUsage = 0;
            }
        }
    }
}

这里把KeyboardInputMapper处理的事件分成了三类,EV_KEY按键事件,EV_MSC其他事件,EV_SYN同步事件,我们重点关注按键事件:

KeyboardInputMapper::processKey

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

    if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
                                  &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }
    //按下事件
    if (down) {
        ...
        // Add key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            //重复事件
            keyCode = mKeyDowns[keyDownIndex].keyCode;
        } else {
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
                getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
                //需要丢弃
                return;
            }
            if (policyFlags & POLICY_FLAG_GESTURE) {
                getDeviceContext().cancelTouch(when);
            }
            //构造KeyDown
            KeyDown keyDown;
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
            //放入mKeyDowns
            mKeyDowns.push_back(keyDown);
        }

        mDownTime = when;
    } else {//抬起事件
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // 一个按键事件抬起之后将该事件以及之前的所以事件从mKeyDowns移除
            keyCode = mKeyDowns[keyDownIndex].keyCode;
            mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
        } else {
            //该事件只有抬起没有按下,异常情况
            return;
        }
    }
    ......

    nsecs_t downTime = mDownTime;

    ...

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

这个函数有个非常重要的操作就是getDeviceContext().mapKey,它会将按键扫描码scanCode转换为keyCode,scanCode是驱动提供的,上层java使用的就是转换之后的keyCode,扫描码定义在kl(key layout)文件中,例如:在这里插入图片描述
这是我们公司的测试手机中的一张kl文件,定义了很多按键扫描码,如POWER对应扫描码116,我们可以通过命令adb shell getevent查看,当我点击POWER键时有如下输出:74是十六进制,对应十进制刚好等于116,并且注意其事件发生的设备节点为/dev/input/event1,而/dev/input/event1下的kl表名称就是" mtk-kpd.kl",所以POWER扫描码定义在" mtk-kpd.kl"中。
在这里插入图片描述
scanCode到keyCode的映射限于篇幅,本篇不会分析,后面分析".kl"文件的解析时来看。

接着看processKey函数,变量down描述按键按下还是抬起,大于0代表按下,等于0代表抬起,然后对按下和抬起分别做处理,mKeyDowns是一个存储KeyDown结构体集合,KeyDown结构体用来封装一个按键的scanCodekeyCode

	struct KeyDown {
        int32_t keyCode;
        int32_t scanCode;
    };

findKeyDown函数作用是从mKeyDowns集合中查找KeyDown结构体,processKey函数对按下和抬起事件处理很简单,即按下时添加到mKeyDowns,抬起时从mKeyDowns移除,函数最后根据RawEvent解析出的按键信息构造了一个NotifyKeyArgs,并调用QueuedInputListenernotifyKeyNotifyKeyArgs发送出去,

QueuedInputListener::notifyKey

//InputListener.cpp
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    traceEvent(__func__, args->id);
    mArgsQueue.push_back(new NotifyKeyArgs(*args));
}

这个函数做的事情就跟简单了,仅仅就是将NotifyKeyArgs放入mArgsQueue集合,

std::vector<NotifyArgs*> mArgsQueue;

到此RawEvent的加工就已经完成,说起来也很简单就是转换成了NotifyKeyArgs,接着我们需要再回到InputReader::loopOnce函数的第四部分:

//InputReader.cpp
void InputReader::loopOnce() {
    	//(1)
    	...
    	//(2)
    	...
    	//(3)
        ...

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}

QueuedListener::flush

//InputListener.cpp
void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}

这里会遍历mArgsQueue,并调用NotifyArgsnotify函数,NotifyArgs是一个父类,不同事件类型对应不同的子类,有如下几种类型:
NotifyConfigurationChangedArgs
NotifyKeyArgs
NotifyMotionArgs
NotifySwitchArgs
NotifyDeviceResetArgs

因为我们分析的是按键事件,对应的是NotifyKeyArgs,即NotifyKeyArgs::notify

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyKey(this);//this代表NotifyKeyArgs
}

这里继续调用InputListenerInterfacenotifyKey函数,InputListenerInterface是一个父类,我们需要找其子类的具体实现,子类其实就是InputDispatcher

class InputDispatcher : public android::InputDispatcherInterface{
	...
}

到此,输入事件就顺理成章的从InputReader发送到了InputDispatcher,本篇文章也接近了尾声,不得不说InputReader线程对事件的处理确实非常复杂,InputReader对input事件处理过程大致可以分为三大步:

  1. EventHub通过INotify与Epoll监听/dev/input下的事件,在读取到事件之后放入mEventBuffer,此步骤将input_event转换为了RawEvent
  2. 拿到原始事件RawEvent之后调用processEventsLocked对事件进行加工,不同事件类型有不同的加工厂(InputMapper),此步骤将RawEvent转换为了NotifyKeyArgs
  3. 通过QueuedListenerflush函数将事件发送到InputDispatcher线程。
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值