Android IMS原理解析之processEvent

???????接著上篇文章Android IMS原理解析之InputChannel,上篇文章講到,當有事件到來時,觸發NativeInputEventReceiver的回調接下來會調用到Java層InputEventReceiver的方法,看一下Java層的事件處理:

Input事件處理

???????前面分析到事件已經發送到對應的窗口了,接下來就是事件的處理流程,從onInputEvent()來開始分析:

final class WindowInputEventReceiver extends InputEventReceiver {
    @Override
    public void onInputEvent(InputEvent event, int displayId) {
        enqueueInputEvent(event, this, 0, true);
    }
}

???????在onInputEvent()內部會執行enqueueInputEvent(),傳入了this及InputEvent等參數,接下來看一下enqueueInputEvent():

void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {
        adjustInputEventForCompatibility(event);
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        mPendingInputEventCount += 1;
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
}

???????該方法內部執行執行三項工作:
???????1.通過obtainQueuedInputEvent()來獲取QueuedInputEvent實例,對InputEvent進行封裝,類似Message處理;
???????2.對mPendingInputEventTail及mPendingInputEventTail進相關的處理,接下來事件處理會用到;
???????3.由于processImmediately為true,因此執行doProcessInputEvents()進行邏輯處理;
???????接下來對以上三項工作進行一一分析:

private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags) {
        QueuedInputEvent q = mQueuedInputEventPool;
        if (q != null) {
            mQueuedInputEventPoolSize -= 1;
            mQueuedInputEventPool = q.mNext;
            q.mNext = null;
        } else {
            q = new QueuedInputEvent();
        }

        q.mEvent = event;
        q.mReceiver = receiver;
        q.mFlags = flags;
        return q;
}

???????從obtainQueuedInputEvent()可以看到,執行邏輯跟obtainMessage邏輯是一致的,先從pool里面取,如果沒有的話就重新創建,然后進行賦值,對比messgae的處理邏輯,也有對應的recycle方法:

private void recycleQueuedInputEvent(QueuedInputEvent q) {
        q.mEvent = null;
        q.mReceiver = null;

        if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
            mQueuedInputEventPoolSize += 1;
            q.mNext = mQueuedInputEventPool;
            mQueuedInputEventPool = q;
        }
    }

???????mQueuedInputEventPool賦值是在recycleQueuedInputEvent()內部,pool Size最大為10,超過后就不處理了。
???????第二項工作是賦值操作,是為第三項工作做準備的,直接看第三項工作doProcessInputEvents():

void doProcessInputEvents() {
        // Deliver all pending input events in the queue.
        while (mPendingInputEventHead != null) {
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;

            mPendingInputEventCount -= 1;
            ......
            deliverInputEvent(q);
        }

        .....
    }

???????在doProcessInputEvents()內部最終執行了deliverInputEvent(q):

private void deliverInputEvent(QueuedInputEvent q) {
       .....
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }

???????在deliverInputEvent()內部會執行InputStage的deliver()方法,stage是在setView()中進行賦值的,此處對應的是ViewPostImeInputStage,一起看一下:

abstract class InputStage {
    ......
    public final void deliver(QueuedInputEvent q) {
        if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
            forward(q);
        } else if (shouldDropInputEvent(q)) {
            finish(q, false);
        } else {
            apply(q, onProcess(q));
        }
    }

    protected void apply(QueuedInputEvent q, int result) {
            if (result == FORWARD) {
                forward(q);
            } else if (result == FINISH_HANDLED) {
                finish(q, true);
            } else if (result == FINISH_NOT_HANDLED) {
                finish(q, false);
            } else {
                throw new IllegalArgumentException("Invalid result: " + result);
            }
        }
    .....
}

final class ViewPostImeInputStage extends InputStage {
    ......
    @Override
    protected int onProcess(QueuedInputEvent q) {
        if (q.mEvent instanceof KeyEvent) {
            return processKeyEvent(q);
        } else {
            final int source = q.mEvent.getSource();
            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                return processPointerEvent(q);
            } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                return processTrackballEvent(q);
            } else {
                return processGenericMotionEvent(q);
            }
        }
    }
    ...... 
}

???????可以看到,在執行deliver()時會執行apply(),然后執行onProcess(),在onProcess()內部來選擇執行processKeyEvent()或processPointerEvent()[在其內部將Event傳遞到對應的目標控件,后面進行分析]來對事件進行處理,在處理完后針對不同的返回result來調用finish()-->forward()-->onDeliverToNext()[mNext不null,繼續deliver;為null]-->finishInputEvent()來發送事件結束信息到InputDispatcher進行接下來的處理工作,看一下finishInputEvent()方法實現:

private void finishInputEvent(QueuedInputEvent q) {

    if (q.mReceiver != null) {
        boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
        q.mReceiver.finishInputEvent(q.mEvent, handled);
    } else {
        q.mEvent.recycleIfNeededAfterDispatch();
    }

    recycleQueuedInputEvent(q);
}

???????q.mReceiver是在obtainQueuedInputEvent()時傳入的是InputEventReceiver對象,因此調用的是InputEventReceiver的finishInputEvent(),然后執行recycleQueuedInputEvent(q)來回收QueuedInputEvent ,前面已經分析過,邏輯跟Message處理是一致的,此處用的是享元模式;接下來看一下InputEventReceiver的finishInputEvent()方法:

public final void finishInputEvent(InputEvent event, boolean handled) {
    ......
    int index = mSeqMap.indexOfKey(event.getSequenceNumber());
    int seq = mSeqMap.valueAt(index);
    mSeqMap.removeAt(index);
    nativeFinishInputEvent(mReceiverPtr, seq, handled);
}

???????從mSeqMap里面取出對應的seq,然后執行nativeFinishInputEvent(),mReceiverPtr是在nativeInit時返回的NativeInputEventReceiver對象引用,一起去native層去看一下nativeFinishInputEvent()的具體實現:

static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
        jint seq, jboolean handled) {
    sp<NativeInputEventReceiver> receiver =
            reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
    status_t status = receiver->finishInputEvent(seq, handled);
}

???????調用的是NativeInputEventReceiver的finishInputEvent():

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
    status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
     ......
    return status;
}

???????接著通過InputConsumer的sendFinishedSignal()來進行發送:

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
   ......
   return sendUnchainedFinishedSignal(seq, handled);
   ......
}            

???????最終是通過mChannel來進行發送;

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
    InputMessage msg;
    msg.header.type = InputMessage::TYPE_FINISHED;
    msg.body.finished.seq = seq;
    msg.body.finished.handled = handled;
    return mChannel->sendMessage(&msg);
}

???????前面講到在addView()時執行registerInputChannel()時會在InputDispatcher里面通過mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this)注冊了對InputChannel fd的監聽,當有可讀消息時,會回調handleReceiveCallback()方法:

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);

    { // acquire lock
        AutoMutex _l(d->mLock);
        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
        bool notify;
        //根據可讀的InputChannel的描述符獲取對應的Connection對象
        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);

            nsecs_t currentTime = now();
            bool gotOne = false;
            status_t status;
            for (;;) {
                uint32_t seq;
                bool handled;
                //在循環中不斷地讀取盡可能多的反饋信息
                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
                if (status) {
                    break;
                }
                //調用finishDispatchCycleLocked()函數完成對反饋的處理
                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                gotOne = true;
            }
            if (gotOne) {
                d->runCommandsLockedInterruptible();
                if (status == WOULD_BLOCK) {
                    return 1;
                }
            }
        }

        // Unregister the channel.
        d->unregisterInputChannelLocked(connection->inputChannel, notify);
        return 0; // remove the callback
    } // release lock
}

???????finishDispatchCycleLocked()函數只是將向InputDispatcher發送一個命令。最終處理反饋的函數是doDispatchCycleFinishedLockedInterruptible(),本文就不詳細介紹了,到此一個事件就算閉環了。
???????用一張圖來總結一下處理及反饋過程:

事件處理及反饋.png

???????本文只從整體上分析了事件的處理及反饋過程,對processKeyEvent()及processPointerEvent()的詳細介紹請參考下一篇文章Android IMS原理解析之dispatchEvent

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。