[Android] 输入系统(二)
在上一篇文章的最后,我們發現InputDispatcher是調用了InputChannel->sendMessage把鍵值發送出去,那么相應的,也有接收鍵值的地方。接收函數是InputChannel->receiveMessage。
在InputConsumer::consume內找到了receiveMessage,從類名能看出來發送端與接收端相當于生產者與消費者的關系。
status_t InputConsumer::consume(InputEventFactoryInterface* factory,bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {// Receive a fresh message.status_t result = mChannel->receiveMessage(&mMsg); }?
receiveMessage內調用的是socket的接收函數recv
status_t InputChannel::receiveMessage(InputMessage* msg) {do {nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);} while (nRead == -1 && errno == EINTR); }?
?
事件接收端NativeInputEventReceiver
那么究竟是誰來消費這些事件呢,我們在NativeInputEventReceiver里面找到了答案。
在NativeInputEventReceiver內有個事件處理函數handleEvent,該函數是looperCallback的虛函數,NativeInputEventReceiver作為looperCallback的子類,自然有義務實現handleEvent這個函數。handleEvent就可以監聽I/O事件。一旦有I/O事件,如上述的socket send事件,handleEvent就會被啟動,進行后續的處理。
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL); }?
既然有LooperCallback(NativeInputEventReceiver),必然會有Looper。雖然Looper不是本篇文章的研究對象,但是我們有必要理清下面的問題:
- 究竟與NativeInputEventReceiver對應的這個Looper是什么?
- 這個Looper是怎樣與LooperCallback關聯起來的呢?
???
實際上,一切起始于ViewRootImpl的setView方法:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { ...//在這里傳入了當前線程的Loopernew WindowInputEventReceiver(mInputChannel, Looper.myLooper()); ... }?
InputEventReceiver作為WindowInputEventReceiver的子類,會一起被創建出來。在InputEventReceiver的構造方法中,會調用native方法nativeInit
public InputEventReceiver(InputChannel inputChannel, Looper looper) {mInputChannel = inputChannel;mMessageQueue = looper.getQueue();mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),inputChannel, mMessageQueue); }?
在NativeInputEventReceiver的nativeInit方法中,創建了NativeInputEventReceiver對象,并調用它的initialize方法
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,jobject inputChannelObj, jobject messageQueueObj) {...sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);status_t status = receiver->initialize();... }?
initialize方法只做了一件事,就是把NativeInputEventReceiver與Looper關聯起來
status_t NativeInputEventReceiver::initialize() {setFdEvents(ALOOPER_EVENT_INPUT);return OK; }void NativeInputEventReceiver::setFdEvents(int events) {if (mFdEvents != events) {mFdEvents = events;int fd = mInputConsumer.getChannel()->getFd();if (events) {mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);} else {mMessageQueue->getLooper()->removeFd(fd);}} }Looper的方法addFd實現了關聯Looper與LooperCallback(NativeInputEventReceiver)的功能,我們先來分析一下傳給addFd的參數
- fd,fd即inputChannel的socket fd,Looper會偵測該fd的狀態
- events,即傳入的ALOOPER_EVENT_INPUT,只有fd的狀態是INPUT的時候才會觸發調用LooperCallback中的handleEvent方法
- this,即NativeInputEventReceiver,當fd狀態為Input時,NativeInputEventReceiver中的handleEvent方法會被調用
?
?
在consumeEvents內,我們能看到調用了InputConsume::consume來接收InputDispatcher發送過來的事件
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {for (;;) {status_t status = mInputConsumer.consume(&mInputEventFactory,consumeBatches, frameTime, &seq, &inputEvent);} }?
?
輸入事件在consumeEvents內將會被處理完成,其中包含了四個主要步驟:
?
?
1. 獲取輸入事件已在上面闡述過
?
2. 輸入事件轉換
以Key為例,輸入事件只是把事件內部的成員拆分,然后通過JNI調用java的構造函數來生成相應的java event對象,后面的事件處理都在java層
jobject inputEventObj;switch (inputEvent->getType()) {case AINPUT_EVENT_TYPE_KEY:inputEventObj = android_view_KeyEvent_fromNative(env,static_cast<KeyEvent*>(inputEvent));break;// ----------------------------------------------------------------------------jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz,gKeyEventClassInfo.obtain,nanoseconds_to_milliseconds(event->getDownTime()),nanoseconds_to_milliseconds(event->getEventTime()),event->getAction(),event->getKeyCode(),event->getRepeatCount(),event->getMetaState(),event->getDeviceId(),event->getScanCode(),event->getFlags(),event->getSource(),NULL);if (env->ExceptionCheck()) {ALOGE("An exception occurred while obtaining a key event.");LOGE_EX(env);env->ExceptionClear();return NULL;}return eventObj; }public static KeyEvent obtain(long downTime, long eventTime, int action,int code, int repeat, int metaState,int deviceId, int scancode, int flags, int source, String characters) {KeyEvent ev = obtain();ev.mDownTime = downTime;ev.mEventTime = eventTime;ev.mAction = action;ev.mKeyCode = code;ev.mRepeatCount = repeat;ev.mMetaState = metaState;ev.mDeviceId = deviceId;ev.mScanCode = scancode;ev.mFlags = flags;ev.mSource = source;ev.mCharacters = characters;return ev;}?
?
?
3.輸入事件分發
這里是在java層的事件分發,最終目的是為了調用到窗口的onTouch這類回調函數。
env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);?
?
還記得上面InputEventReceiver初始化時的流程嗎?是通過setView--->new WindowInputEventReceiver--->new InputEventReceiver--->new NativeInputEventReceiver這樣一步一步創建的。
通過上述的JNI調用,會調用到WindowInputEventReceiver的dispatchInputEvent方法,不過由于WindowInputEventReceiver并沒有自己實現這個方法,因此會調用父類InputEventReceiver::dispatchInputEvent,內部會真正調用到WindowInputEventReceiver::onInputEvent
public void dispatchInputEvent(InputEvent event) {onInputEvent(event);}?
在onInputEvent內,轉到了ViewRootImpl這邊進行處理
public void onInputEvent(InputEvent event) {enqueueInputEvent(event, this, 0, true); }void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {doProcessInputEvents(); }?
由于事件隊列內會包含多個事件,因此在doProcessInputEvent時,需要分別對所有的事件都進行分發
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);}}?
deliverInputEvent會調用到InputState的deliver方法
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));}}由于一開始我們的事件還沒有完成,因此不會帶上FLAG_FINISHED,而且我們的事件時一般事件,并不會被丟棄,因此會走apply分支。
?
?
首先會調用onProcess處理事件
protected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);} else {// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchDoneAnimating();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);}}}?
?
以Key為例,我們會調用到processKeyEvent
private int processKeyEvent(QueuedInputEvent q) {// Deliver the key to the view hierarchy.if (mView.dispatchKeyEvent(event)) {return FINISH_HANDLED;}}?
然后調用了View類的dispatchKeyEvent方法,最終會調用到onKey這個回調函數
public boolean dispatchKeyEvent(KeyEvent event) {// Give any attached key listener a first crack at the event.//noinspection SimplifiableIfStatementListenerInfo li = mListenerInfo;if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {return true;}}?
?
4. 處理結果反饋
然后還剩下apply這個方法需要分析。如果onProcess正常處理完成后,會返回FINISH_HANDLED,否則返回FINISHED_NOT_NHANDLED。
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);}}protected void finish(QueuedInputEvent q, boolean handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED;if (handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;}forward(q);}protected void forward(QueuedInputEvent q) {onDeliverToNext(q);}protected void onDeliverToNext(QueuedInputEvent q) {if (mNext != null) {mNext.deliver(q);} else {finishInputEvent(q);}}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);}?????
?
?
mReceiver.finishInputEvent就是NativeInputEvent的finishInputEvent
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {status_t status = mInputConsumer.sendFinishedSignal(seq, handled); }status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {while (!status && chainIndex-- > 0) {status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);} }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); }最后也是調用sendMessage把消息反饋給InputDispatcher。
到這里,上層的處理已經完成,接下來就是InputDispatcher的反饋處理。
?
?
InputDispatcher反饋處理
反饋處理在handleReceiveCallback中進行,其中包含兩個部分:
?
?
1. 接收反饋消息
接收反饋消息是調用的inputPublisher的receiveFinishedSignal方法,內部還是調用了mChannel->receiveMessage
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {status_t result = mChannel->receiveMessage(&msg);}?
?
2. 處理反饋消息
處理反饋消息是調用了finishDispatchCycleLocked。
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection, uint32_t seq, bool handled) {// Notify other system components and prepare to start the next dispatch cycle.onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); }?
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {CommandEntry* commandEntry = postCommandLocked(& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);}?
?
postCommandLocked其實也是發送消息給InputDispatcherThread,那么在分發線程下一次處理消息的時候會首先處理doDispatchCycleFinishedLockedInterruptible。
doDispatchCycleFinishedLockedInterruptible是實際上反饋進行處理的地方,其中包含了下面幾個處理步驟:
?
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {// Handle post-event policy actions.DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {String8 msg;msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ",connection->getWindowName(), eventDuration * 0.000001f);dispatchEntry->eventEntry->appendDescription(msg);ALOGI("%s", msg.string());}if (dispatchEntry == connection->findWaitQueueEntry(seq)) {connection->waitQueue.dequeue(dispatchEntry);}// Start the next dispatch cycle for this connection.startDispatchCycleLocked(now(), connection);} }?
總結
以上是生活随笔為你收集整理的[Android] 输入系统(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个、说到所有的扩展指标
- 下一篇: android sina oauth2.