Android输入事件从读取到分发三:InputDispatcherThread线程分发事件的过程

本文详细分析了Android系统中输入事件从InputReaderThread读取到InputDispatcherThread分发的过程,包括事件的获取、传递和唤醒线程的机制。通过源码追踪,解释了InputDispatcher如何将事件封装并发送到目标窗口,为理解Android事件处理提供了深入理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析完事件的读取后,东忙西忙,不知不觉已过去了快五个月了…也不是说没有时间把这部分源码分析完,而是实在是分析不下去,因此转战到其他地方去了。然而这一块始终是心头那不舍的惦记,经过一段时间的沉淀,又参考了网上很多大神的文章,然后再来阅读源码,渐渐感觉到能看出点眉目了。因而事不宜迟,赶紧做个记录吧(注:分析使用的Android源码版本为6.0)。
前面两篇文章分析输入事件的读取,通过分析,发现时间的读取是在EventHub类中实现的,EventHub类的getEevent方法中使用epoll_wait来监听驱动程序上报的事件,而在InputReaderThread的threadLoop方法中调用InputReader的loopOnce方法来不断的调用EventHub的getEvent方法来一直监听事件的到来,getEvent是一个阻塞的方法,当没有事件的时候,epoll_wait方法就会是线程休眠,有事件了就会唤醒线程。

从事件读取线程到事件分发线程的转移过程

既然有个InputReaderThread线程,那么有个InputDispatcherThread就不奇怪了,一个用来读取,一个用来分发,分工合作,相互配合,这样才能高效的完成事件的读取与分发。
我们先梳理下思路:

这里写图片描述

从事件读取线程到事件分发线程的转移时序图:
这里写图片描述
从时序图中我们可以看到两个线程交互的过程。InputReaderThread会唤醒InputDispatcherThread来分发事件。
接下来,我们通过源码的追踪的方式,具体看看时序图中涉及的代码的具体实现。

跟着时序图,我们代码从InputReaderThread开始看起:

InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

InputReaderThread::~InputReaderThread() {
}

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

构造函数和析构函数都是空的,循环函数简单的就一句。mReader就是当前的InputReader对象,因此loopOnce如下:

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

        oldGeneration = mGeneration;
        timeoutMillis = -1;

       ...
    //获取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

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

        if (count) {
            //处理事件
            processEventsLocked(mEventBuffer, count);
        }
        ...
        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);
    }
    ...
    mQueuedListener->flush();
}

只列出了比较重要的一些代码。这个函数作如下事情:
1.使用mEventHub->getEvents获取输入事件
2.使用processEventsLocked处理事件
getEvents方法之前也已经有介绍过,它就是使用epoll来监听驱动程序上报的事件的。所以我们从processEventsLocked方法看起:

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;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
            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;
    }
}

这个方法会对事件类型进行判断。我们假定用户按了一下返回按键,所以输入的是一个按键事件。而这个函数判断的时间类型的定义如下:

    enum {
        // Sent when a device is added.
        DEVICE_ADDED = 0x10000000,
        // Sent when a device is removed.
        DEVICE_REMOVED = 0x20000000,
        // Sent when all added/removed devices from the most recent scan have been reported.
        // This event is always sent at least once.
        FINISHED_DEVICE_SCAN = 0x30000000,

        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
    };

可见我们的按键事件绝不是这几个,而应该是小于FIRST_SYNTHETIC_EVENT事件的,因此会执行第一个分支。进而调用 processEventsForDeviceLocked(deviceId, rawEvent, batchSize);方法进一步处理:

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }

    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}

调用device->process因一部处理,device是InputDevice的实例,因此看看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.
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
                rawEvent->when);
#endif

        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
                ALOGD("Recovered from input event buffer overrun.");
#endif
            } else {
#if DEBUG_RAW_EVENTS
                ALOGD("Dropped input event while waiting for next input sync.");
#endif
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            ALOGI("Detected input event buffer overrun for device %s.", getName().string());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

为了更好的理解这段代码,我们列出事件类型的定义:


/* Events */

#define EV_SYN          0x00
#define EV_KEY          0x01
#define EV_REL          0x02
#define EV_ABS          0x03
#define EV_MSC          0x04
#define EV_LED          0x11
#define EV_SND          0x12
#define EV_REP          0x14
#define EV_FF           0x15
#define EV_PWR          0x16
#define EV_FF_STATUS        0x17
#define EV_MAX          0x1f

因此我们的按键时间应该是0x01,所以这段代码执行的下面这个for循环:

            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }

for循环遍历mMappers数组,分别调用每一个mapper的process方法。这个数组包含了所有的输入事件的类型。我们按下的按键,因此会调用按键类型的Mapper来处理。如果想搞清楚这一块,可以看下mMappers数组的构造过程,在createDeviceLocked方法中实现,

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
            controllerNumber, identifier, classes);

    // External devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
        device
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值