Android 4.2 Input Event事件处理流程<一>事情派发

事件的开始是从eventhub开始的,我们先来看下流程图


事件派发的整个流程比较复杂,我们只看几个比较重要点的地方,从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;

        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); //获取事件

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

        if (count) { //有事件
            processEventsLocked(mEventBuffer, count);//进行处理
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                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();
}

当eventHup有事件后loopOnce返回,接着调用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;        
        ALOGD("rawEvent->type: %d ", rawEvent->type);//event类型  参考http://wenku.baidu.com/link?url=HLS1P7Hn8qqscyPbZY2JhpuqZLE2n5uXPnBi4xHUbKvNRqUVdGYaRYK5k0BciIWyWZigNels-losqAfS8nRTDnuaNpwuwSTfF0DAXdmYt2e
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {//小于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          
            convertEvent(rawEvent,batchSize); //对事件做一些处理并存到mConvertEventBuffer          
            if(batchSize > 0) {//有事件需要出处理
                int32_t convertdeviceId = mConvertEventBuffer[0].deviceId;              
                processEventsForDeviceLocked(convertdeviceId, mConvertEventBuffer, 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;
    }
}

会对event类型进行判断,event主要有下面几种:

#define EV_SYN 0x00
#define EV_KEY 0x01 //按键
#define EV_REL 0x02 //相对坐标(轨迹球)
#define EV_ABS 0x03 //绝对坐标
#define EV_MSC 0x04 //其他
#define EV_SW 0x05
#define EV_LED 0x11 //LED
#define EV_SND 0x12//声音
#define EV_REP 0x14//repeat
#define EV_FF 0x15 
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1) 
convertEvent对事件做一些处理并存到mConvertEventBuffer,接着调用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);//调用InputDevice::process
}

这里只是简单的调用InputDevice::process,对于按键事件,process最后会调用KeyboardInputMapper.process

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
	ALOGW("KeyboardInputMapper::process.rawEvent->type = %d", rawEvent->type);
    switch (rawEvent->type) {
    case EV_KEY: {
        bool   find = false;
        bool   down = false;
      //  bool   currentindex = 0;
	    int currentindex = 0;
        if(mIsRepeatMode)//重复按键模式
        {
            ALOGW("mIsRepeatMode = true");   
            if(rawEvent->value != 0)
            {
                for(int i = 0;i < MAX_KEYDOWNNUM;i++)
                {
                    if(mCurrentDown[i] == true)
                    {
                        down = true;
                    }
                }

                if(down == false)
                {
                    ALOGW("down = false");     
                    for(int i = 0;i < MAX_KEYDOWNNUM;i++)
                    {
                        if(mCurrentDown[i] == false)
                        {
                            currentindex = i;

                            break ;
                        }
                    }

                    mCurrentDown[currentindex] = true;
                    mCurrentScanCode[currentindex] = rawEvent->code;
                    goto processCurrentEvent;
                }
                else
                {
                    for(int i = 0;i < MAX_KEYDOWNNUM;i++)
                    {
                        if(mCurrentScanCode[i] == rawEvent->code)
                        {
                            find = true;
                        }
                    }

                    if(find == false)
                    {
                        for(int i = 0;i < MAX_KEYDOWNNUM;i++)
                        {
                            if(mCurrentDown[i] == false)
                            {
                                currentindex = i;

                                break;
                            }
                        }

                        mCurrentDown[currentindex] = true;
                        mCurrentScanCode[currentindex] = rawEvent->code;
                        goto processCurrentEvent;
                    }
                }
            }
            else
            {
                for(int i = 0;i < MAX_KEYDOWNNUM;i++)
                {
                    if(mCurrentScanCode[i] == rawEvent->code)
                    {
                        currentindex = i;
                        find = true;

                        break;
                    }
                }

                if(find == true)
                {
                    mCurrentDown[currentindex] = false;
                    mCurrentScanCode[currentindex] = 0;

                    goto processCurrentEvent;
                }
            }
        }
        else
        {
            goto processCurrentEvent;
        }

        return ;
processCurrentEvent:
        int32_t scanCode = rawEvent->code;
        int32_t usageCode = mCurrentHidUsage;
        mCurrentHidUsage = 0;

        if (isKeyboardOrGamepadKey(scanCode)) {//键盘或者手柄
            int32_t keyCode;
            uint32_t flags;
             ALOGW("mapKey");   
            if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {//根据.kl文件映射键值
                keyCode = AKEYCODE_UNKNOWN;
                flags = 0;
            }
            processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);//处理键值
        }
        break;
    }
    case EV_MSC: {
        if (rawEvent->code == MSC_SCAN) {
            mCurrentHidUsage = rawEvent->value;//设置mCurrentHidUsage
        }
        break;
    }
    case EV_SYN: {
        if (rawEvent->code == SYN_REPORT) {//事件的结束
            mCurrentHidUsage = 0;//设置mCurrentHidUsage
        }
    }
    }
    ALOGW("Exit KeyboardInputMapper::process");
}
调用mapKey根据配置文件映射键值,最后调用processKey,processKey又会调用notifyKey,最终会调用到InputDispatcher的notifyKey

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
    ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
            args->eventTime, args->deviceId, args->source, args->policyFlags,
            args->action, args->flags, args->keyCode, args->scanCode,
            args->metaState, args->downTime);
#endif
    if (!validateKeyEvent(args->action)) {//验证action参数是否正确
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    int32_t flags = args->flags;
    int32_t metaState = args->metaState;
    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
        policyFlags |= POLICY_FLAG_VIRTUAL;
        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
    }
    if (policyFlags & POLICY_FLAG_ALT) {//检查一下同时是否有ALT和SHIFT键被按下
        metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
    }
    if (policyFlags & POLICY_FLAG_ALT_GR) {
        metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
    }
    if (policyFlags & POLICY_FLAG_SHIFT) {
        metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
    }
    if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
        metaState |= AMETA_CAPS_LOCK_ON;
    }
    if (policyFlags & POLICY_FLAG_FUNCTION) {
        metaState |= AMETA_FUNCTION_ON;
    }

    policyFlags |= POLICY_FLAG_TRUSTED;

    KeyEvent event;
    event.initialize(args->deviceId, args->source, args->action, 
            flags, args->keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);
    ALOGD("lijj before mPolicy->interceptKeyBeforeQueueing");
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); //调度前处理 会调用到interceptKeyBeforeDispatching 的interceptKeyBeforeDispatching
    ALOGD("lijj after  mPolicy->interceptKeyBeforeQueueing");  
    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
    }

    bool needWake;
    { // acquire lock
        mLock.lock();

        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }

        int32_t repeatCount = 0;
        KeyEntry* newEntry = new KeyEntry(args->eventTime,//封装成一个KeyEntry结构
                args->deviceId, args->source, policyFlags,
                args->action, flags, args->keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);

        needWake = enqueueInboundEventLocked(newEntry);//interceptKeyBeforeQueueing
        mLock.unlock();
    } // release lock

    if (needWake) {
        mLooper->wake();//唤醒InputDispatccherThread线程
    }
}
在正式分发按键前,会调用interceptKeyBeforeQueueing对按键做一些预先处理,该函数最终会调用到PhoneWindowManager的interceptKeyBeforeQueueing,在里面会对一些系统的按键如 音量键、电源键、耳机进行一些处理,接着把按键消息封装程一个KeyEntry,并调用enqueueInboundEventLocked插入mInboundQueue队列,最后唤醒InputDispatccherThread线程,这个过程中可能会唤醒或者睡眠系统

回到notifyKey唤醒InputDispatcherThread,运行dispatchOnce

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.
        if (!haveCommandsLocked()) {//mCommandQueue不为空
            dispatchOnceInnerLocked(&nextWakeupTime);//调用dispatchOnceInnerLocked函数来进一步处理
        }
        ALOGD("InputDispatcher::dispatchOnce");
        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) {//运行command
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock

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

这里最终会调用publishKeyEvent,把按键信息通过inputmanager端的socket发送给客户端的socket,而这个时候会触发NativeInputEventReceiver的handleEvent,在这个过程中,还会postCommandLocked(InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible)把一个命令压入到mCommandQueue,这样,当执行这个队列中的命令时 doInterceptKeyBeforeDispatchingLockedInterruptible会执行,这里会调用到PhoneWindowManager的interceptKeyBeforeDispatching,执行一些按键分发前的处理。

我们看handleEvent

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    ALOGD("NativeInputEventReceiver::handleEvent");
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
        ALOGE("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                "events=0x%x", getInputChannelName(), events);
        return 0; // remove the callback
    }

    if (!(events & ALOOPER_EVENT_INPUT)) {
        ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                "events=0x%x", getInputChannelName(), events);
        return 1;
    }

    JNIEnv* env = AndroidRuntime::getJNIEnv();
    status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
    mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
    return status == OK || status == NO_MEMORY ? 1 : 0;
}

他会调用consumeEvents继续来消耗这个消息

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime) {
#if DEBUG_DISPATCH_CYCLE
  //  ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
  //          getInputChannelName(), consumeBatches ? "true" : "false", frameTime);
#endif
    ALOGD("NativeInputEventReceiver::consumeEvents");
    if (consumeBatches) {
        mBatchedInputEventPending = false;
    }

    bool skipCallbacks = false;
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);//取出按键
        if (status) {
            if (status == WOULD_BLOCK) {
                if (!skipCallbacks && !mBatchedInputEventPending
                        && mInputConsumer.hasPendingBatch()) {//暂停
                    // There is a pending batch.  Come back later.
                    mBatchedInputEventPending = true;
#if DEBUG_DISPATCH_CYCLE
                    ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
                            getInputChannelName());
#endif
                    env->CallVoidMethod(mReceiverObjGlobal,
                            gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
                    if (env->ExceptionCheck()) {
                        ALOGE("Exception dispatching batched input events.");
                        mBatchedInputEventPending = false; // try again later
                    }
                }
                return OK;
            }
            ALOGE("channel '%s' ~ Failed to consume input event.  status=%d",
                    getInputChannelName(), status);
            return status;
        }
        assert(inputEvent);

        if (!skipCallbacks) {
            jobject inputEventObj;
            switch (inputEvent->getType()) {
            case AINPUT_EVENT_TYPE_KEY:
#if DEBUG_DISPATCH_CYCLE
                ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
#endif
                inputEventObj = android_view_KeyEvent_fromNative(env, //转换
                        static_cast<KeyEvent*>(inputEvent));
                break;

            case AINPUT_EVENT_TYPE_MOTION:
#if DEBUG_DISPATCH_CYCLE
                ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
#endif
                inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
                        static_cast<MotionEvent*>(inputEvent));
                break;

            default:
                assert(false); // InputConsumer should prevent this from ever happening
                inputEventObj = NULL;
            }

            if (inputEventObj) {
#if DEBUG_DISPATCH_CYCLE
                ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
#endif
                env->CallVoidMethod(mReceiverObjGlobal, //调用java层处理
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching input event.");
                    skipCallbacks = true;
                }
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
                skipCallbacks = true;
            }
        }

        if (skipCallbacks) {
            mInputConsumer.sendFinishedSignal(seq, false);
        }
    }
}

consumeEvents最终调用Java层的dispatchInputEvent对按键消息做进一步处理,这里通过一系列的调用,从ViewRootImpl到InputMethodManager,最终会调用到我们应用的onKeyDow,或者onKeyUp,应用处理玩按键之后,会回调finishInputEvent,最终调用C++层的nativeFinishInputEvent,最终会调用到inputManager中注册的handleReceiveCallback,告诉inputManager事件已经消耗完了,

到这里,事件消息就已经处理完成了,主要是是那个点:

1、interceptKeyBeforeQueueing

2、doInterceptKeyBeforeDispatchingLockedInterruptible

3、dispatchInputEvent

这里面的具体过程比较复杂,涉及的模块也比较多,流程图都有列出来了。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值