Android Framework重要服务之InputManagerService(二) inputReader

前言

本章将继续探究InputReader线程,该线程负责从eventhub获取事件,转换成EventEntry事件并将事件加入到InputDispatcher的mInboundQueue。

threadLoop

InputReaderThread线程启动后,将调用一个thredLoop方法,该方法不断从eventhub获取事件,并进行后续处理,相关代码位于frameworks/native/services/inputflinger/reader/InputReader.cpp:

// 启动InputReader,调用loopOnce
status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

void InputReader::loopOnce() {
    ...
    
    // 从eventhub获取事件(EVENT_BUFFER_SIZE = 256)
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
 
    {
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();
 
        if (count) {
            // 处理事件
            processEventsLocked(mEventBuffer, count);   
        }
        ...
        
        // 如果输入设备发生改变,则重新获取当前输入设备
        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock
 
    // 发送输入设备改变的通知
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
 
    // 发送事件到nputDispatcher
    mQueuedListener->flush();  
} 

在上述代码中,有三个关键节点需要重点关注,他们分别是:mEventHub->getEvents,processEventsLocked,mQueuedListener->flush,下面将重点介绍下这几个方法。

mEventHub->getEvents [获取事件]

getEvents方法主要负责获取kernel的event, 这里事件不仅包括input,还包括输入设备的add/remove等相关事件。
加入的输入设备在没有事件的时候,会block在EventHub中的epoll处,当有事件产生后,epoll_wait就会返回,然后针对变化的事件进行处理。相关代码位于frameworks/native/services/inputflinger/reader/EventHub.cpp:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ...
    
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        // 扫描设备
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();   
            mNeedToSendFinishedDeviceScan = true;
        }
 
        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            ALOGV("Reporting device opened: id=%d, name=%s\n",
                 device->id, device->path.string());
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            // 添加设备事件
            event->type = DEVICE_ADDED;  
            event += 1;
        }
            ...
            
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
            // 从设备读取事件,放入到readBuffer
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
 
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        // 读取事件
                        struct input_event& iev = readBuffer[i];  
                        // 将input_event信息封装成RawEvent
                        event->when = processEventTimestamp(iev);
                        event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
 
                }
            ...
        }
                mLock.unlock(); // release lock before poll, must be before release_wake_lock
        release_wake_lock(WAKE_LOCK_ID);
 
        //poll之前先释放锁 等待input事件的到来
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
        } else {
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
        }
    }
 
    // All done, return the number of events we read.
    return event - buffer;
} 

EventHub采用INotify + epoll机制实现监听目录/dev/input下的设备节点,经过EventHub将input_event结构体 + deviceId 转换成RawEvent结构体,RawEvent结构体的声明位于frameworks/native/services/inputflinger/reader/include/EventHub.h,其结构如下:

RawEvent mEventBuffer[EVENT_BUFFER_SIZE];

struct RawEvent {
    // Time when the event happened
    nsecs_t when;
    // Time when the event was read by EventHub. Only populated for input events.
    // For other events (device added/removed/etc), this value is undefined and should not be read.
    nsecs_t readTime;
    int32_t deviceId;
    int32_t type;
    int32_t code;
    int32_t value;
};
 
struct input_event {
 struct timeval time; //事件发生的时间点
 __u16 type;
 __u16 code;
 __s32 value;
    }; 

processEventsLocked [处理事件]

processEventsLocked方法负责设备的添加、移除与删除,以及事件的处理,相关代码位于frameworks/av/media/libstrming/input/key_injector.cpp

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;
            }
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
                // 添加设备
                case EventHubInterface::DEVICE_ADDED:
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                // 移除设备
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                // 设备扫描
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
} 

processEventsForDeviceLocked

processEventsForDeviceLocked方法用于处理输入设备事件,更具体的来说,是对输入事件的相关信息进行核验,该方法位于frameworks/native/services/inputflinger/reader/InputReader.cpp:

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    // 使用eventHubId查找是哪一个设备发送的事件
    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);
} 

InputDevice::process

InputDevice::process方法负责将输入事件进行映射处理,按设备顺序处理所有事件,这是因为每个设备处理之间可能有依赖关系。相关代码位于frameworks/native/services/inputflinger/reader/InputDevice.cpp:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    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;
    }
} 

KeyboardInputMapper::process

上面提到InputDevice::process方法会使用不同的处理方式处理输入事件,这些事件包括但不限于触控事件、键盘事件、传感器事件等等,总结下来共有以下几种处理方法

class SwitchInputMapper : public InputMapper {
class VibratorInputMapper : public InputMapper {
class KeyboardInputMapper : public InputMapper {
class CursorInputMapper : public InputMapper {
class RotaryEncoderInputMapper : public InputMapper {
class TouchInputMapper : public InputMapper {
class ExternalStylusInputMapper : public InputMapper {
class JoystickInputMapper : public InputMapper { 

在这其中,键盘事件处理最为简单,也最容易分析,触控事件最复杂,所以这里以键盘事件为例进行分析,相关代码位于frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp:

// 键盘事件处理
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->readTime, 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::processKey

KeyboardInputMapper::processKey方法用于处理按键相关事件,相关代码位于frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp:

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;
 
    // 将事件的扫描码(scanCode)转换成键盘码(Keycode)
    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                              &keyCode, &keyMetaState, &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }
 
    if (down) {
        ...
    
        mDownTime = when;
    } else {
        ...
        
    }
    // 创建NotifyKeyArgs对象, when记录eventTime, downTime记录按下时间
    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    
     // 发送key事件
    getListener()->notifyKey(&args); 
} 

EventHub::mapKey

EventHub::mapKey负责将事件的扫描码(scanCode)转换成键盘码(Keycode),相关代码位于frameworks/native/services/inputflinger/reader/EventHub.cpp:

status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
                          int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
    std::scoped_lock _l(mLock);
    Device* device = getDeviceLocked(deviceId);
    status_t status = NAME_NOT_FOUND;

    if (device != nullptr) {
        // Check the key character map first.
        const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
        if (kcm) {
            if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
                *outFlags = 0;
                status = NO_ERROR;
            }
        }

        // Check the key layout next.
        if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
            if (!device->keyMap.keyLayoutMap->mapKey(scanCode, usageCode, outKeycode, outFlags)) {
                status = NO_ERROR;
            }
        }

        if (status == NO_ERROR) {
            if (kcm) {
                kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
            } else {
                *outMetaState = metaState;
            }
        }
    }

    if (status != NO_ERROR) {
        *outKeycode = 0;
        *outFlags = 0;
        *outMetaState = metaState;
    }

    return status;
} 

总结

以上就是InputReader的全部流程,现给出InputReader事件的流程图供大家参考

尾声

一转眼时间真的过的飞快。我们各奔东西,也各自踏上了自己的旅途,但是即使多年不见,也因为这份情谊我们依旧如从前那般“亲密”。不忘初心方得始终。加油吧,程序员们,在我看来35岁,40岁从来不是危机,只要永远不要忘记自己为何踏上征程!

最后需要同款资料的,可以 私信我回复【学习】或者扫描下方二维码我愿意分享给你!

为了让更多在学习中或者最近要准备面试的朋友们看到这篇文章,希望你们能多多评论,点赞+转发!

**再次感谢所有给我提供过题目的朋友们,感谢一路有你!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值