Android_input系统分析InputReader

之前分析说getEvent()返回原始结果到InputReader,今天针对InputReader对getevent返回的结果进行分析:

首先我们看看InputReader在哪里调用getEvent()方法.

void InputReader::loopOnce() {
    ...
    { // acquire lock
        AutoMutex _l(mLock);
             ...
            timeoutMillis = 0;
            // 如果配置信息修改过则更新配置信息
            refreshConfigurationLocked(changes);
   ...
    } // release lock
    ....
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
    ...
            processEventsLocked(mEventBuffer, count);
  
            getInputDevicesLocked(inputDevices);
    ....
    } // release lock

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

其中我们先要知道这个loopOnce()是在InputReaderThread执行的.InputReaderThread是在InputManager中起的.

在这个loopOnce方法中我们可以看到,需要做的事就是以下内容:

  • 查看InputReader配置是否改变
  • 从EventHub读取事件,其中EVENT_BUFFER_SIZE = 256
  • 调用processEventsLocked()方法简单处理事件
  • 调用getInputDeviceLocked()方法获取输入设备的信息
  • 通过mPolicy->notifyInputDeviceChanged()方法发送message,通知输入读取器策略某些输入设备已更改,并提供有关所有当前输入设备的信息。
  • 通过flush()方法将事件传到InputDispatcher

1.processEventsLocked

在processEventsLocked()方法中,先要判断事件类型,如果是发生设备设备的增删扫描,则调用相应的方法进行处理,这里先不对增删扫描进行分析,主要对已经注册好的事件触发进行处理。type<EventHubInterface::FIRST_SYNTHETIC_EVENT时就需要事件进行处理.调用processEventsForDeviceLocked()进行处理。

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    // 在for循环中处理
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        // 判断事件类型,方满足条件是才会处理,当type<EventHubInterface::FIRST_SYNTHETIC_EVENT
        // 就需要事件进行处理
        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: %zu Count: %zu", batchSize, count);
#endif
            //通过调用processEventsForDeviceLocked进行处理
            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()方法干了些什么

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

可以看出processEventsForDeviceLocked()中通过deviceId找到InputDevice 对应的设备事件类型,然后判断是不是要将此次事件忽略,如果不忽略,则会调用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.
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
                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);
            }
        }
        --count;
    }
}

以上代码主要是调用所有的Mapper,调用每个Mapper的process()方法进行处理,当然不是所有的Mapper都会对一个事件进行处理,只有与事件对应的Mapper才会进行处理。那么有多少个Mapper呢?

我们可以在InputReader.h头文件中可以看到有很对对应的Mapper:(下面只列出部分)

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

 这里我们就对Android设备使用比较多的touch类型的TouchInputMapper为例(我反悔。这个内容太多,我要找个简单的分析),就找个KeyBoardInputMapper为例,看看是怎么进行处理的:

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的proces()代码我们可以看出它的主要工作:

当RawEvent->type为EV_KEY时,说明是按键类Input事件,则调用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 (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                              &keyCode, &keyMetaState, &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }

    if (down) {
        ...
    } else {
       ...
    }

    if (updateMetaStateIfNeeded(keyCode, down)) {
     
        keyMetaState = mMetaState;
    }

    nsecs_t downTime = mDownTime;

    
    if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) {
        policyFlags |= POLICY_FLAG_WAKE;
    }

    if (mParameters.handlesKeyRepeat) {
        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
    }

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

在processKey()方法中:

  1. 调用EventHub的mapKey函数得到keyCode、keyMetaState、policyFlags
  2. 对按下、按起的记录和逻辑判断
  3. 将按键事件相关的信息封装到NotifyKeyArgs中(deviceId、when、policyFlags、down还是up、keyCode等等……)
  4. 最终调用getListener()->notifyKey,这里getListener得到的就是InputDispatcher

调用getListener()->notifyKey(&args)调用的是QueuedInputListener的notifyKey函数,它里边有许多notifyXXX函数,做的事情都是将NotifyXXXArgs放入它的mArgsQueue队列中存储,等待处理。

再回到processEventsLocked,当事件类型为增删和扫描后,需要分别处理

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

以addDeviceLocked()来看看会怎么处理


void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex >= 0) {
        ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
        return;
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
    // 通过deviceId, controllerNumber, identifier, classes来创建新的InputDevice对象
    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
    device->configure(when, &mConfig, 0);
    device->reset(when);

    if (device->isIgnored()) {
        ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
                identifier.name.string());
    } else {
        ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
                identifier.name.string(), device->getSources());
    }
    // 将新创建的InputDevice放到mDevices中
    mDevices.add(deviceId, device);
    bumpGenerationLocked();

    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        notifyExternalStylusPresenceChanged();
    }
}

addDeviceLocked主要的工作就是,创建新的InputDevice,然后再讲新创建的InputDevice对象放到mDevices中。

相同的,removeDeviceLocked则需要将mDevices对相应的InputDevice删除

void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
    InputDevice* device = NULL;
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
        return;
    }

    device = mDevices.valueAt(deviceIndex);
    mDevices.removeItemsAt(deviceIndex, 1);
    bumpGenerationLocked();

....
    device->reset(when);
    delete device;
}

handleConfigurationChangedLocked() 的工作就是重置全局元状态 ,修改配置列表,并通知mQueuedListener。

void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
    // Reset global meta state because it depends on the list of all configured devices.
    updateGlobalMetaStateLocked();

    // Enqueue configuration changed.
    NotifyConfigurationChangedArgs args(when);
    mQueuedListener->notifyConfigurationChanged(&args);
}

2.getInputDevicesLocked


void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
    outInputDevices.clear();

    size_t numDevices = mDevices.size();
    for (size_t i = 0; i < numDevices; i++) {
        InputDevice* device = mDevices.valueAt(i);
        if (!device->isIgnored()) {
            outInputDevices.push();
            device->getDeviceInfo(&outInputDevices.editTop());
        }
    }
}

它就是把mDevices中不需要被忽略的InputDevice取出来放入参数outInputDevices,也就是loopOnce中的inputDevices。

InputDevice添加完成后,调用InputManagerService的notifyInputDevicesChanged函数通知系统输入设备信息需要更新。

处理设备的增删,预处理、归类事件,将事件放入事件队列,通知系统更新设备信息后,当然就是要通知InputDispatcher取出事件队列中的事件进行处理了。

3. mQueuedListener->flush()

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

flush()将事件传到InputDispatcher.

在flush中,循环取出队列里的NotifyXXXArgs(有多种,例如NotifyKeyArgs、NotifyMotionArgs),调用它的notify函数通知mInnerListener,也就是InputReader创建时传入的listener,即InputDispatcher,最终会调用mInnerListener的notifyXXX函数。

发布了41 篇原创文章 · 获赞 35 · 访问量 4338

猜你喜欢

转载自blog.csdn.net/weixin_38140931/article/details/100859390