???????接著上篇文章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(),本文就不詳細介紹了,到此一個事件就算閉環了。
???????用一張圖來總結一下處理及反饋過程:
???????本文只從整體上分析了事件的處理及反饋過程,對processKeyEvent()及processPointerEvent()的詳細介紹請參考下一篇文章Android IMS原理解析之dispatchEvent