Android4.4——InputManagerService之InputReader线程

之前在《Android4.4——InputManagerService启动》博客中通过InputManagerService.start函数->nativeStart->inputmanager.start->InputXXXThread.run函数,最终启动了InputReader线程和InputDispatcher线程这两个工作线程。这篇博客主要来分析一下InputReader相关的代码。

InputReader线程启动后,线程会一直在InputReaderThread.threadLoop函数中不断循环。

Step 1、InputReaderThread.threadLoop
该函数的代码位于frameworks\base\services\input\InputReader.cpp文件中。

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

其中mReader为InputReaderThread类中的一个接口。

/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
    InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

private:
    sp<InputReaderInterface> mReader;

    virtual bool threadLoop();
};    

InputReader类实现了InputReaderInterface接口,所以mReader->loopOnce()调用的是InputReader.loopOnce函数。

Step 2、InputReader.loopOnce
该函数的代码同样位于frameworks\base\services\input\InputReader.cpp文件中。

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    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

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//从EventHub获取输入事件

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

        if (count) {
            processEventsLocked(mEventBuffer, count);//Input事件处理函数
        }

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

        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();//将Input事件发送给Listener。
}

对于InputReader而言,Listener实际为InputDispatcher。

Step 3、EventHub.getEvents
该函数代码位于frameworks\base\services\input\EventHub.cpp文件中。这块代码涉及到了驱动部分,暂时不分析了,只需要知道EventHub.getEvents从底层上获取到Input事件即可。

Step 4、InputReader.ProcessEventsLocked
该函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {//rawEvents为从EventHub获取的事件;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 {//EventsHub.getEvents函数所产生的事件
            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;
    }
}

从EventsHub中获取到Input事件及其事件数后,由InputReader.ProcessEventsLocked函数进行处理。根据获取的事件类型,可以大致分为两类,一类有设备驱动程序上报的事件,一类为EventsHub.getEvents函数产生的事件。EventsHub.getEvents产生的事件主要包括增加设备、移除设备和扫描设备三个事件。负责处理 Device 增加、删除事件。增加事件的流程为:为一个新增的 Device 创建一个InputDevice,并增加到 InputReader::mDevices 中;并根据新增加设备的 class 类别,创建对应的消息转换器(InputMapper),然后此消息转换器加入InputDevice::mMappers 中。消息转换器负责把读取的 RawEvent 转换成特定的事件,以供应用程序使用。
EventHub 与 InputReader 各自管理功能:
1)EventHub 管理一堆 Device,每一个 Device 与内核驱动中一个事件输入设备对应
2)InputReader 管理一堆 InputDevice,每一个 InputDevice 与 EventHub 中的 Device 对应
3)InputDevice 管理一些与之相关的 InputMapper,每一个 InputMapper 与一个特定的应用事件相对应,如:SingleTouchInputMapper。

但是在这里,只主要针对地分析设备驱动程序上报的事件的处理过程。

Step 5、InputReader. processEventsForDeviceLocked
该函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//根据rawEvents.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);
}

根据deviceID获取对应的InputDevice,然后调用InputDevice::process函数对设备输入事件进行处理。

Step 6、InputDevice::process
本函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。

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();//获取InputMapper中各设备对应的Mapper对象总数
    for (const RawEvent* rawEvent = rawEvents; count--; 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().string());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (size_t i = 0; i < numMappers; i++) {//遍历InputDevice中的每一个InputMapper,并调用相应mapper的process函数处理事件
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

上面说到本函数会遍历InputDevice的所有InputMapper并调用相应mapper的process函数。注意到,InputMapper::process函数是一个纯虚函数(参考frameworks\base\services\input\ InputReader.h中InputMapper类的声明处)。

class InputMapper {
public:
    InputMapper(InputDevice* device);
    virtual ~InputMapper();

    ……
    virtual void process(const RawEvent* rawEvent) = 0;
    ……

protected:
    InputDevice* mDevice;<pre name="code" class="java">    InputReaderContext* mContext;
    ……
};

因此,要实现其process函数,需要其它类继承并重写process函数。 下面以触摸触摸屏为例,来简单分析一下这段逻辑。
当我们在上面按下时驱动程序会上报触点的坐标,在InputDevice::process函数中会调用mapper->process(rawEvent)函数处理。之前我们提到InputMapper::process是一个纯虚函数。对于单点触摸屏而言,process函数是由SingleTouchInputMapper类的process函数实现。
在frameworks\base\services\input\InputReader.h文件中有以下代码:

class TouchInputMapper : public InputMapper{
    ……
    virtual voidprocess(const RawEvent* rawEvent);
    ……
};

class SingleTouchInputMapper : publicTouchInputMapper {
    ……
   virtual void process(const RawEvent* rawEvent);
    ……

private:
   SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
};

另外,在frameworks\base\services\input\InputReader.cpp文件中,实现了SingleTouchInputMapper:: process函数和TouchInputMapper::process函数:

void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);

    mSingleTouchMotionAccumulator.process(rawEvent);//将事件保存在SingleTouchMotionAccumulator中的成员变量中
}

void TouchInputMapper::process(const RawEvent* rawEvent) {
    mCursorButtonAccumulator.process(rawEvent);//记录mouse和touch pad按键状态
    mCursorScrollAccumulator.process(rawEvent);//cursor scroll motions
    mTouchButtonAccumulator.process(rawEvent);//记录touch,stylus and toolbutton

    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        sync(rawEvent->when);
    }
}

通过调用TouchInputMapper::process函数,同步CursorButton、CursorScroll和TouchBotton的状态,将事件保存起来。

接下来,分析sync函数:

void TouchInputMapper::sync(nsecs_t when) {
    // Sync button state.
    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
            | mCursorButtonAccumulator.getButtonState();

    // Sync scroll state.
    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
    mCursorScrollAccumulator.finishSync();

    // Sync touch state.
    bool havePointerIds = true;
    mCurrentRawPointerData.clear();
    syncTouch(when, &havePointerIds);//调用SingleTouchInputMapper::syncTouch函数

    ……

    // Reset state that we will compute below.
    mCurrentFingerIdBits.clear();
    mCurrentStylusIdBits.clear();
    mCurrentMouseIdBits.clear();
    mCurrentCookedPointerData.clear();

    if (mDeviceMode == DEVICE_MODE_DISABLED) {
        // Drop all input if the device is disabled.
        mCurrentRawPointerData.clear();
        mCurrentButtonState = 0;
    } else {
        // Preprocess pointer data.
        if (!havePointerIds) {
            assignPointerIds();
        }

        // Handle policy on initial down or hover events.
        uint32_t policyFlags = 0;
        bool initialDown = mLastRawPointerData.pointerCount == 0
                && mCurrentRawPointerData.pointerCount != 0;
        bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
        if (initialDown || buttonsPressed) {
            // If this is a touch screen, hide the pointer on an initial down.
            if (mDeviceMode == DEVICE_MODE_DIRECT) {
                getContext()->fadePointer();
            }

            // Initial downs on external touch devices should wake the device.
            // We don't do this for internal touch screens to prevent them from waking
            // up in your pocket.
            // TODO: Use the input device configuration to control this behavior more finely.
            if (getDevice()->isExternal()) {
                policyFlags |= POLICY_FLAG_WAKE_DROPPED;
            }
        }

        // Synthesize key down from raw buttons if needed.
        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
                policyFlags, mLastButtonState, mCurrentButtonState);//同步Key-down事件

        // Consume raw off-screen touches before cooking pointer data.
        // If touches are consumed, subsequent code will not receive any pointer data.
        if (consumeRawTouches(when, policyFlags)) {
            mCurrentRawPointerData.clear();
        }

        // Cook pointer data.  This call populates the mCurrentCookedPointerData structure
        // with cooked pointer data that has the same ids and indices as the raw data.
        // The following code can use either the raw or cooked data, as needed.
        cookPointerData();

        // Dispatch the touches either directly or by translation through a pointer on screen.
        if (mDeviceMode == DEVICE_MODE_POINTER) {
            for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
                uint32_t id = idBits.clearFirstMarkedBit();
                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
                    mCurrentStylusIdBits.markBit(id);
                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
                    mCurrentFingerIdBits.markBit(id);
                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
                    mCurrentMouseIdBits.markBit(id);
                }
            }
            for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
                uint32_t id = idBits.clearFirstMarkedBit();
                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
                    mCurrentStylusIdBits.markBit(id);
                }
            }

            // Stylus takes precedence over all tools, then mouse, then finger.
            PointerUsage pointerUsage = mPointerUsage;
            if (!mCurrentStylusIdBits.isEmpty()) {
                mCurrentMouseIdBits.clear();
                mCurrentFingerIdBits.clear();
                pointerUsage = POINTER_USAGE_STYLUS;
            } else if (!mCurrentMouseIdBits.isEmpty()) {
                mCurrentFingerIdBits.clear();
                pointerUsage = POINTER_USAGE_MOUSE;
            } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
                pointerUsage = POINTER_USAGE_GESTURES;
            }

            dispatchPointerUsage(when, policyFlags, pointerUsage);//分发Pointer事件---滑动
        } else {
            if (mDeviceMode == DEVICE_MODE_DIRECT
                    && mConfig.showTouches && mPointerController != NULL) {
                mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);

                mPointerController->setButtonState(mCurrentButtonState);
                mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
                        mCurrentCookedPointerData.idToIndex,
                        mCurrentCookedPointerData.touchingIdBits);
            }

            dispatchHoverExit(when, policyFlags);
            dispatchTouches(when, policyFlags);//分发touch事件
            dispatchHoverEnterAndMove(when, policyFlags);
        }

        // Synthesize key up from raw buttons if needed.
        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
                policyFlags, mLastButtonState, mCurrentButtonState);//同步Key-up事件
    }

    // Copy current touch to last touch in preparation for the next cycle.
    mLastRawPointerData.copyFrom(mCurrentRawPointerData);
    mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
    mLastButtonState = mCurrentButtonState;
    mLastFingerIdBits = mCurrentFingerIdBits;
    mLastStylusIdBits = mCurrentStylusIdBits;
    mLastMouseIdBits = mCurrentMouseIdBits;

    // Clear some transient state.
    mCurrentRawVScroll = 0;
    mCurrentRawHScroll = 0;
}

首先着看syncTouch 函数。这里TouchInputMapper中未重写syncTouch 函数,故这里调用的是SingleTouchInputMapper::syncTouch函数(位于frameworks\base\services\input\InputReader.cpp):

void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
    if (mTouchButtonAccumulator.isToolActive()) {
        mCurrentRawPointerData.pointerCount = 1;
        mCurrentRawPointerData.idToIndex[0] = 0;

        bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
                && (mTouchButtonAccumulator.isHovering()
                        || (mRawPointerAxes.pressure.valid
                                && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
        mCurrentRawPointerData.markIdBit(0, isHovering);

        RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];//同步和更新mCurrentRawPointerData.pointers值
        outPointer.id = 0;
        outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
        outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
        outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
        outPointer.touchMajor = 0;
        outPointer.touchMinor = 0;
        outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
        outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
        outPointer.orientation = 0;
        outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
        outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX();
        outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY();
        outPointer.toolType = mTouchButtonAccumulator.getToolType();
        if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
            outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
        }
        outPointer.isHovering = isHovering;
    }
}

接着分析SingleTouchInputMapper:: dispatchTouches函数:

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
    ……

    if (currentIdBits == lastIdBits) {
        if (!currentIdBits.isEmpty()) {
            // No pointer id changes so this is a move event.
            // The listener takes care of batching moves so we don't have to deal with that here.
            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
                    AMOTION_EVENT_EDGE_FLAG_NONE,
                    mCurrentCookedPointerData.pointerProperties,//经坐标转换后的坐标数据
                    mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
                    mCurrentCookedPointerData.idToIndex, //经坐标转换后的坐标数据
                    currentIdBits, -1,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
    } else {
        ……

        // Dispatch pointer up events.
        while (!upIdBits.isEmpty()) {
            uint32_t upId = upIdBits.clearFirstMarkedBit();

            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
                    mLastCookedPointerData.pointerProperties,
                    mLastCookedPointerData.pointerCoords,
                    mLastCookedPointerData.idToIndex,
                    dispatchedIdBits, upId,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
            dispatchedIdBits.clearBit(upId);
        }

        // Dispatch move events if any of the remaining pointers moved from their old locations.
        // Although applications receive new locations as part of individual pointer up
        // events, they do not generally handle them except when presented in a move event.
        if (moveNeeded) {
            ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
                    mCurrentCookedPointerData.pointerProperties, //经坐标转换后的坐标数据
                    mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
                    mCurrentCookedPointerData.idToIndex, //经坐标转换后的坐标数据
                    dispatchedIdBits, -1,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
        // Dispatch pointer down events using the new pointer locations.
        while (!downIdBits.isEmpty()) {
            ……

            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
                    mCurrentCookedPointerData.pointerProperties, //经坐标转换后的坐标数据
                    mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
                    mCurrentCookedPointerData.idToIndex, //经坐标转换后的坐标数据
                    dispatchedIdBits, downId,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
    }
}

dispatchTouches函数中有多处都调用了TouchInputMapper::dispatchMotion函数,那就来分析一下呗。

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
        const PointerProperties* properties, //经坐标转换后的坐标数据
 const PointerCoords* coords, //经坐标转换后的坐标数据
        const uint32_t* idToIndex, //经坐标转换后的坐标数据
 BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
    PointerCoords pointerCoords[MAX_POINTERS];
    PointerProperties pointerProperties[MAX_POINTERS];
    uint32_t pointerCount = 0;
    while (!idBits.isEmpty()) {
        uint32_t id = idBits.clearFirstMarkedBit();
        uint32_t index = idToIndex[id];
        pointerProperties[pointerCount].copyFrom(properties[index]);
        pointerCoords[pointerCount].copyFrom(coords[index]);

        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }

        pointerCount += 1;
    }

    ……

    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}

在dispatchMotion中,根据经坐标转换后的cooked数据创建NotifyMotionArg对象,它描述了一个移动事件,接着调用TouchInputMapper::getListener()->notifyMotion(&args)。
TouchInputMapper::getListener()调用mContext->getListener(),此mContext为InputReader::mContext,所以其getListener()返回的则为InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion函数。下面来围观一下:

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
    mArgsQueue.push(new NotifyMotionArgs(*args));
}

把传递过来的NotifyMotionArg参数复制一份,然后加入QueuedInputListener::mArgsQueue列表中。

  1. 补充1)
    InputReader::mContext在构造时用自己的指针初始化了mContext(见InputReader::InputReader函数),从而mContext::mReader则为此InputReader实例(见InputReader类声明处代码)。

  2. 补充2)
    在InputReader::createDeviceLocked中创建InputDevice时,把自己的mContext作为参数传入,从而把它保存在InputDevice::mContext中;在创建InputMapper时,以InputDevice作为参数,且InputMapper把它保存在mDevice中,然后从把InputDevice中的mContext也保存在InputMapper的mContext中。

回到当初我们开始长途跋涉追寻代码的InputReader::loopOnce函数,在大致追踪完processEventsLocked后,继续分析loopOnce函数的最后一小段代码:

void InputReader::loopOnce() {
    ……

    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);//在NativeInputManager对象创建InputReader对象时传入。(见new NativeInputManager-> new InputManager-> new InputReader)
    }

    // 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();//处理mArgsQueue中的所有NotifyArgs
} 

来见识一下flush函数的庐山真面目,代码位于frameworks\base\services\input\ 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();
}

在new InputReader的时候,将mDispatcher作为参数传递给InputReader的构造函数最为构造函数的第三个参数。可以自行去看看InputReader构造函数和QueueInputListener构造函数的代码,就可以知道mInnerListener实际上是InputManager中的mDispatcher。

与之前分析InputMapper的时候类似。NofifyArgs这个结构体定义了一个纯虚函数notify。因此由其他结构体继承NotifyArgs并改写实现notify函数。
之前假设的触摸触摸屏的事件到达至此步时,调用的是NotifyMotionArgs中的notify函数(代码位于frameworks\base\services\input\ InputListener.cpp文件)。

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyMotion(this);
}

这里调用的InputDispatcher::notifyMotion函数,这样就进入到InputDispatcher的工作职能中了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值