InputSystem發(fā)送輸入事件到應(yīng)用的過程

基于Android 7.0源碼分析

以最基本的MotionEvent(touchsreen single pointer)為例分析

InputReader讀取輸入事件分發(fā)給InputDispatcher的過程

下面從InputReaderloopOnce()開始分析

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    ......
    // 獲取驅(qū)動(dòng)上報(bào)的輸入事件,返回讀取的事件數(shù)
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

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

        if (count) {
            // 處理輸入事件
            processEventsLocked(mEventBuffer, count);
        }
        ......
    }
    ......
    // 發(fā)送事件給InputDispatcher
    mQueuedListener->flush();
}

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        ......
        // Grab the next input event.
        // 讀取輸入事件
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            ......
            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            if (deviceIndex < 0) {
                ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
                        eventItem.events, eventItem.data.u32);
                continue;
            }
            // 找到上報(bào)事件的設(shè)備
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                // 讀取輸入事件
                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.
                    // 讀取失敗,設(shè)備已經(jīng)移除
                    ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                            " bufferSize: %zu capacity: %zu errno: %d)\n",
                            device->fd, readSize, bufferSize, capacity, errno);
                    deviceChanged = true;
                    closeDeviceLocked(device);
                } else if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        ALOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    // 輸入事件不完整
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else {
                    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++) {
                        // 解析讀取的事件,封裝為RawEvent
                        struct input_event& iev = readBuffer[i];
                        ......
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                }
            }
        }
        ......
        // 讀取到一些事件立即返回
        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
            break;
        }
    }
    ......
    // All done, return the number of events we read.
    return event - buffer;
}
  • RawEvent中的時(shí)間使用的是驅(qū)動(dòng)上報(bào)事件的時(shí)間,更加精確;另外還要防止輸入設(shè)備時(shí)鐘源切換引入的問題

下面分析processEventsLocked()的實(shí)現(xiàn)

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;
            // 統(tǒng)計(jì)同一設(shè)備普通輸入事件
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
            ......
            // 處理普通的輸入事件,同一設(shè)備的事件一起處理
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            ......
        }
        count -= batchSize;
        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;
    }
    // 找到對(duì)應(yīng)的設(shè)備
    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }
    // 調(diào)用InputDevice的process處理
    device->process(rawEvents, count);
}

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++) {
            ......
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                // 對(duì)于MotionEvent, 由MultiTouchInputMapper處理
                mapper->process(rawEvent);
            }
            ......
    }
}

在分析MultiTouchInputMapperprocess()實(shí)現(xiàn)之前,先簡(jiǎn)單了解下touchscreen驅(qū)動(dòng)上報(bào)的原始輸入事件的格式。

Down/Move事件類似:
 1) report (EV_ABS, ABS_MT_SLOT) // 存放事件的SLOT
 2) report (EV_ABS, ABS_MT_TRACKING_ID(非負(fù))) // touch軌跡id
 3) report (EV_ABS, ABS_MT_TOOL_TYPE = 0) // touch設(shè)備類型
 4) report (EV_ABS, ABS_MT_POSITION_X(x坐標(biāo))) // touch區(qū)域(橢圓)的中心點(diǎn)的X坐標(biāo)
 5) report (EV_ABS, ABS_MT_POSITION_Y(Y坐標(biāo))) // touch區(qū)域(橢圓)的中心點(diǎn)的Y坐標(biāo)
 6) report (EV_SYN, SYN_REPORT) // 完整事件標(biāo)示

Up事件:
 1) report (EV_ABS, ABS_MT_SLOT)
 2) report (EV_ABS, ABS_MT_TRACKING_ID(-1))
 3) report (EV_SYN, SYN_REPORT)

更多信息請(qǐng)參考kernel multi-touch-protocol.txt文檔
  • 不同的touchscreen驅(qū)動(dòng)會(huì)有所差異

下面看process()實(shí)現(xiàn)

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
    // 原始事件處理
    TouchInputMapper::process(rawEvent);
    // 根據(jù)multi-touch protocol,解析原始事件存放到slot中
    mMultiTouchMotionAccumulator.process(rawEvent);
}

void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
    // 絕對(duì)坐標(biāo)事件
    if (rawEvent->type == EV_ABS) {
        bool newSlot = false;
        if (mUsingSlotsProtocol) {
            // 獲取SLOT位置,一次Touch,Down/Move/.../Up通常使用一個(gè)SLOT存儲(chǔ)
            if (rawEvent->code == ABS_MT_SLOT) {
                mCurrentSlot = rawEvent->value;
                newSlot = true;
            }
        } else if (mCurrentSlot < 0) {
            mCurrentSlot = 0;
        }
        ......
        } else {
            Slot* slot = &mSlots[mCurrentSlot];

            switch (rawEvent->code) {
            // 一般只有Down/Move有坐標(biāo)信息
            // X坐標(biāo)
            case ABS_MT_POSITION_X:
                slot->mInUse = true;
                slot->mAbsMTPositionX = rawEvent->value;
                break;
            // Y坐標(biāo)
            case ABS_MT_POSITION_Y:
                slot->mInUse = true;
                slot->mAbsMTPositionY = rawEvent->value;
                break;
            case ABS_MT_TOUCH_MAJOR:
                slot->mInUse = true;
                slot->mAbsMTTouchMajor = rawEvent->value;
                break;
            case ABS_MT_TOUCH_MINOR:
                slot->mInUse = true;
                slot->mAbsMTTouchMinor = rawEvent->value;
                slot->mHaveAbsMTTouchMinor = true;
                break;
            ......
            case ABS_MT_TRACKING_ID:
                // 通常Down/Move事件 id為非負(fù),Up事件id = -1
                if (mUsingSlotsProtocol && rawEvent->value < 0) {
                    // The slot is no longer in use but it retains its previous contents,
                    // which may be reused for subsequent touches.
                    // 注意對(duì)于Up事件,mInUse為false
                    slot->mInUse = false;
                } else {
                    slot->mInUse = true;
                    slot->mAbsMTTrackingId = rawEvent->value;
                }
                break;
            }
        }
    } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
        // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
        mCurrentSlot += 1;
    }
}

下面看TouchInputMapperprocess()實(shí)現(xiàn)

void TouchInputMapper::process(const RawEvent* rawEvent) {
    mCursorButtonAccumulator.process(rawEvent);
    mCursorScrollAccumulator.process(rawEvent);
    mTouchButtonAccumulator.process(rawEvent);

    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        // 獲得一個(gè)完整事件,處理事件后分發(fā)給監(jiān)聽者
        sync(rawEvent->when);
    }
}

void TouchInputMapper::sync(nsecs_t when) {
    const RawState* last = mRawStatesPending.isEmpty() ?
            &mCurrentRawState : &mRawStatesPending.top();

    // Push a new state.
    // 創(chuàng)建一個(gè)RawState
    mRawStatesPending.push();
    RawState* next = &mRawStatesPending.editTop();
    next->clear();
    next->when = when;
    ......
    // Sync touch
    // 調(diào)用MultiTouchInputMapper的syncTouch,將SLOT中的原始事件保存到next中
    syncTouch(when, next);

    // Assign pointer ids.
    // 對(duì)于Up事件,由于pointer數(shù)為0,不分配id
    if (!mHavePointerIds) {
        assignPointerIds(last, next);
    }
    ......
    // 處理分發(fā)原始事件
    processRawTouches(false /*timeout*/);
}

下面首先看syncTouch()的實(shí)現(xiàn),然后分析處理分發(fā)原始事件。

void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
    size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
    size_t outCount = 0;
    BitSet32 newPointerIdBits;

    for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
        const MultiTouchMotionAccumulator::Slot* inSlot =
                mMultiTouchMotionAccumulator.getSlot(inIndex);
        // Up事件跳過
        if (!inSlot->isInUse()) {
            continue;
        }
        ......
        // SLOT中的原始事件信息保存到outState中
        RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
        outPointer.x = inSlot->getX();
        outPointer.y = inSlot->getY();
        outPointer.pressure = inSlot->getPressure();
        outPointer.touchMajor = inSlot->getTouchMajor();
        outPointer.touchMinor = inSlot->getTouchMinor();
        outPointer.toolMajor = inSlot->getToolMajor();
        outPointer.toolMinor = inSlot->getToolMinor();
        outPointer.orientation = inSlot->getOrientation();
        outPointer.distance = inSlot->getDistance();
        outPointer.tiltX = 0;
        outPointer.tiltY = 0;
        ......
        // Assign pointer id using tracking id if available.
        mHavePointerIds = true;
        int32_t trackingId = inSlot->getTrackingId();
        int32_t id = -1;
        if (trackingId >= 0) {
            // 查找當(dāng)前事件的trackingId在mPointerTrackingIdMap中的索引
            for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
                uint32_t n = idBits.clearFirstMarkedBit();
                // mPointerTrackingIdMap用于根據(jù)id快速訪問trackingId
                if (mPointerTrackingIdMap[n] == trackingId) {
                    id = n;
                }
            }

            if (id < 0 && !mPointerIdBits.isFull()) {
                id = mPointerIdBits.markFirstUnmarkedBit();
                mPointerTrackingIdMap[id] = trackingId;
            }
        }
        if (id < 0) {
            mHavePointerIds = false;
            outState->rawPointerData.clearIdBits();
            newPointerIdBits.clear();
        } else {
            // 記錄id(single pointer時(shí)通常為0)
            outPointer.id = id;
            outState->rawPointerData.idToIndex[id] = outCount;
            // 標(biāo)記id掩碼
            outState->rawPointerData.markIdBit(id, isHovering);
            newPointerIdBits.markBit(id);
        }

        outCount += 1;
    }
    // pointer數(shù)這里為1
    outState->rawPointerData.pointerCount = outCount;
    // 更新全局id掩碼
    mPointerIdBits = newPointerIdBits;

    mMultiTouchMotionAccumulator.finishSync();
}
  • 對(duì)于Down/Move事件,SLOT中的原始事件信息保存到outState中,但是對(duì)于Up事件,outState處于初始狀態(tài)

下面分析processRawTouches()

void TouchInputMapper::processRawTouches(bool timeout) {
    if (mDeviceMode == DEVICE_MODE_DISABLED) {
        // Drop all input if the device is disabled.
        // 設(shè)備被禁止,丟棄輸入事件
        mCurrentRawState.clear();
        mRawStatesPending.clear();
        return;
    }
    ......
    const size_t N = mRawStatesPending.size();
    size_t count;
    for(count = 0; count < N; count++) {
        const RawState& next = mRawStatesPending[count];

        // A failure to assign the stylus id means that we're waiting on stylus data
        // and so should defer the rest of the pipeline.
        if (assignExternalStylusId(next, timeout)) {
            break;
        }

        // All ready to go.
        clearStylusDataPendingFlags();
        // 原始事件信息拷貝至mCurrentRawState
        mCurrentRawState.copyFrom(next);
        if (mCurrentRawState.when < mLastRawState.when) {
            mCurrentRawState.when = mLastRawState.when;
        }
        // 校準(zhǔn)分發(fā)事件
        cookAndDispatch(mCurrentRawState.when);
    }
    if (count != 0) {
        // 移除處理完成的事件
        mRawStatesPending.removeItemsAt(0, count);
    }
    ......
}

下面看cookAndDispatch()的實(shí)現(xiàn)

void TouchInputMapper::cookAndDispatch(nsecs_t when) {
    // Always start with a clean state.
    mCurrentCookedState.clear();
    ......
    // Cook pointer data.  This call populates the mCurrentCookedState.cookedPointerData 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.
    // 校準(zhǔn)原始事件數(shù)據(jù)存放到mCurrentCookedState, Up事件,pointer數(shù)為0無需校準(zhǔn)
    cookPointerData();
    ......
    if (mDeviceMode == DEVICE_MODE_POINTER) {
        ......
    } else {
        ......
        if (!mCurrentMotionAborted) {
            dispatchButtonRelease(when, policyFlags);
            dispatchHoverExit(when, policyFlags);
            // 分發(fā)Touch事件
            dispatchTouches(when, policyFlags);
            dispatchHoverEnterAndMove(when, policyFlags);
            dispatchButtonPress(when, policyFlags);
        }
    }
    ......
    // Copy current touch to last touch in preparation for the next cycle.
    // 當(dāng)前事件處理完成,拷貝至mLastRawState及mLastCookedState
    mLastRawState.copyFrom(mCurrentRawState);
    mLastCookedState.copyFrom(mCurrentCookedState);
}

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
    // 當(dāng)前事件的id掩碼
    BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
    // 先前的事件的id掩碼
    BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
    int32_t metaState = getContext()->getGlobalMetaState();
    int32_t buttonState = mCurrentCookedState.buttonState;

    if (currentIdBits == lastIdBits) {
        if (!currentIdBits.isEmpty()) {
            // id掩碼相等且非零,那么current為Move事件
            // 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, 0, metaState, buttonState,
                    AMOTION_EVENT_EDGE_FLAG_NONE,
                    mCurrentCookedState.cookedPointerData.pointerProperties,
                    mCurrentCookedState.cookedPointerData.pointerCoords,
                    mCurrentCookedState.cookedPointerData.idToIndex,
                    currentIdBits, -1,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
    } else {
        // There may be pointers going up and pointers going down and pointers moving
        // all at the same time.
        // 考慮single pointer事件
        // 1) Up事件(lastIdBits.value非0,currentIdBits.value為0)
        // 2) Down事件(lastIdBits.value為0,currentIdBits.value非0)
        BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
        BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
        BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
        BitSet32 dispatchedIdBits(lastIdBits.value);
        ......
        // Dispatch pointer up events.
        // 分發(fā)Up事件,這里注意Up事件信息使用mLastCookedState(例如,Up事件的坐標(biāo)是前驅(qū)事件的坐標(biāo))
        while (!upIdBits.isEmpty()) {
            uint32_t upId = upIdBits.clearFirstMarkedBit();

            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
                    mLastCookedState.cookedPointerData.pointerProperties,
                    mLastCookedState.cookedPointerData.pointerCoords,
                    mLastCookedState.cookedPointerData.idToIndex,
                    dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
            dispatchedIdBits.clearBit(upId);
        }
        ......
        // Dispatch pointer down events using the new pointer locations.
        // 分發(fā)Down事件
        while (!downIdBits.isEmpty()) {
            uint32_t downId = downIdBits.clearFirstMarkedBit();
            dispatchedIdBits.markBit(downId);

            if (dispatchedIdBits.count() == 1) {
                // First pointer is going down.  Set down time.
                mDownTime = when;
            }

            dispatchMotion(when, policyFlags, mSource,
                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
                    mCurrentCookedState.cookedPointerData.pointerProperties,
                    mCurrentCookedState.cookedPointerData.pointerCoords,
                    mCurrentCookedState.cookedPointerData.idToIndex,
                    dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
    }
}

下面看dispatchMotion()的實(shí)現(xiàn)

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t actionButton, 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;
    // 拷貝指尖屬性及坐標(biāo)數(shù)據(jù)
    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;
    }
    ......
    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        // 修改single pointer Down/Up事件的action
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            action = AMOTION_EVENT_ACTION_UP;
        } else {
            // Can't happen.
            ALOG_ASSERT(false);
        }
    }
    // 向監(jiān)聽者(QueuedInputListener)發(fā)送事件
    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, actionButton, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}

// NotifyMotionArgs存放到mArgsQueue容器中
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
    mArgsQueue.push(new NotifyMotionArgs(*args));
}
  • PointerCoords 保存指尖坐標(biāo)數(shù)據(jù)
  • PointerProperties 保存指尖屬性信息
  • NotifyMotionArgs 描述一個(gè)Motion事件,采用命令模式

這里QueuedInputListener只是將事件封裝成NotifyArgs存放到容器中。回到InputReaderloopOnce()中,驅(qū)動(dòng)上報(bào)的事件都放到容器中后,QueuedInputListener調(diào)用flush()分發(fā)給InputDispatcher

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

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
    // 調(diào)用InputDispatcher的notifyMotion
    listener->notifyMotion(this);
}

下面分析InputDispatchernotifyMotion()

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
    // 檢查MotionEvent是否合法
    if (!validateMotionEvent(args->action, args->actionButton,
                args->pointerCount, args->pointerProperties)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;
    // mPolicy為NativeInputManager
    // 檢查系統(tǒng)是否需要攔截事件
    mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);

    bool needWake;
    { // acquire lock
        mLock.lock();
        ......
        // Just enqueue a new motion event.
        MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, args->actionButton, args->flags,
                args->metaState, args->buttonState,
                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                args->displayId,
                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
        // MotionEntry放入InboundQueue中
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) {
        // 喚醒InputDispatcher處理事件
        mLooper->wake();
    }
}

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    // 事件放入InboundQueue tail
    mInboundQueue.enqueueAtTail(entry);
    // 更新systrace中iq信息
    traceInboundQueueLengthLocked();

    ......
}

最終,InputReader線程將事件放入InboundQueue中,如果有必要,喚醒InputDispatcher線程處理事件。

小結(jié)

InputDispatcher發(fā)送MotionEvent到應(yīng)用的過程

下面從InputDispatcherdispatchOnce()開始分析

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        // 如果沒有待處理的命令,分發(fā)事件(此過程中可能產(chǎn)生命令)
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }
        ......
    }

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    // 如果被喚醒,從此返回
    mLooper->pollOnce(timeoutMillis);
}

下面看dispatchOnceInnerLocked()的實(shí)現(xiàn)

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
    ......
    // If dispatching is frozen, do not process timeouts or try to deliver any new events.
    // 事件分發(fā)凍住直接返回
    if (mDispatchFrozen) {
#if DEBUG_FOCUS
        ALOGD("Dispatch frozen.  Waiting some more.");
#endif
        return;
    }

    // Optimize latency of app switches.
    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
    // 檢查app switch key處理是否超時(shí)
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // Ready to start a new event.
    // If we don't already have a pending event, go grab one.
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            ......
        } else {
            // Inbound queue has at least one entry.
            // 從InboundQueue中取出一個(gè)事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
            // 更新systrace中iq信息
            traceInboundQueueLengthLocked();
        }
        // Poke user activity for this event.
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            // 通知PowerManagerService更新電源狀態(tài)
            pokeUserActivityLocked(mPendingEvent);
        }

        // Get ready to dispatch the event.
        // 重置等待輸入目標(biāo)超時(shí)信息
        resetANRTimeoutsLocked();
    }
    ......
    switch (mPendingEvent->type) {
    ......
    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            // app switch key事件處理超時(shí),丟棄后續(xù)事件
            dropReason = DROP_REASON_APP_SWITCH;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            // 丟棄已經(jīng)超時(shí)失效的事件
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            // 丟棄將要發(fā)送給不響應(yīng)的應(yīng)用的事件
            dropReason = DROP_REASON_BLOCKED;
        }
        // 分發(fā)事件
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }
    ......
    }

    if (done) {
        // 分發(fā)結(jié)束清理
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;

        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    }
}

下面分析dispatchMotionLocked()實(shí)現(xiàn)

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    if (! entry->dispatchInProgress) {
        // 標(biāo)記正在分發(fā)事件
        entry->dispatchInProgress = true;

        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
    }

    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        // 由于某種原因需要丟棄事件
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }

    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    Vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        // 查找InputTarget
        // findTouchedWindowTargetsLocked的實(shí)現(xiàn)與WindowManagerService關(guān)系密切,這里
        // 暫不詳細(xì)討論,另外它也處理應(yīng)用不響應(yīng)輸入ANR的情況
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        ......
    }
    ......
    // 分發(fā)事件給inputTargets
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}
  • InputTarget 描述如何將事件分發(fā)到特定的窗口,它包含目標(biāo)窗口的InputChannel以及控制標(biāo)志等

下面看dispatchEventLocked()的實(shí)現(xiàn)

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif

    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);

        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            // 通過InputChannel找到Connection
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            // 分發(fā)事件
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
#if DEBUG_FOCUS
            ALOGD("Dropping event delivery to target with channel '%s' because it "
                    "is no longer registered with the input dispatcher.",
                    inputTarget.inputChannel->getName().string());
#endif
        }
    }
}

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    ......
    // Skip this event if the connection status is not normal.
    // We don't want to enqueue additional outbound events if the connection is broken.
    // 如果Connection的狀態(tài)異常,跳過事件
    if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
                connection->getInputChannelName(), connection->getStatusLabel());
#endif
        return;
    }
    ......
    // Not splitting.  Enqueue dispatch entries for the event as is.
    // 分發(fā)事件
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();
    ......
    // 事件封裝成DispatchEntry,放入Connection的OutboundQueue中,更新systrace中oq信息
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_IS);
    ......
    // If the outbound queue was previously empty, start the dispatch cycle going.
    // 如果之前Connection的OutboundQueue為空,啟動(dòng)分發(fā)事件
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

下面看startDispatchCycleLocked()的實(shí)現(xiàn)

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ startDispatchCycle",
            connection->getInputChannelName());
#endif

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        ......
        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;
            ......
            // Publish the motion event.
            // 通過socket將事件分發(fā)給應(yīng)用
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                    motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
            break;
        }

        default:
            ALOG_ASSERT(false);
            return;
        }
        ......
        // Re-enqueue the event on the wait queue.
        // 從Connection的OutboundQueue中刪除事件
        connection->outboundQueue.dequeue(dispatchEntry);
        // 更新systrace中oq信息
        traceOutboundQueueLengthLocked(connection);
        // 事件添加到WaitQueue中
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        // 更新systrace中wq信息
        traceWaitQueueLengthLocked(connection);
    }
}

至此,輸入事件從InputDispatcher已經(jīng)分發(fā)到應(yīng)用。

小結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容