按鍵傳遞過程
接收按鍵的傳遞流程
EventHub用來讀取驅動中的event。InputReader負責將EventHub中的消息讀取出來,之後InputDispatcher將event發送出來。
具體代碼如下
InputReader.cpp
void InputReader::loopOnce() {
···
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//讀取event
···
processEventsLocked(mEventBuffer, count);//處理event事件
···
}
這裏處理的event事件有以下四種情況:
1.DEVICE_ADDED添加輸入設備
2.DEVICE_REMOVED移除輸入設備
3.FINISHED_DEVICE_SCAN輸入設備掃描完成
4.普通按鍵
這裏我們只對普通按鍵過程進行分析
InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
···
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
···
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//查找event對應的設備
InputDevice* device = mDevices.valueAt(deviceIndex);//獲取deviceid對應的設備
device->process(rawEvents, count);//調用設備的處理函數
}
這裏我們以KeyboardInputMapper爲例
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)){}//獲取按鍵的keycode
processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
break;
···
}
}
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
int32_t scanCode, uint32_t policyFlags) {
···
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
getListener()->notifyKey(&args);//這個call InputDispatcher.notifyKey
···
}
這個裏面會調用InputDispatcher裏面的notifyKey函數。
InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
···
event.initialize(args->deviceId, args->source, args->action,
flags, args->keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
//這裏面要先call PhoneWindowManager中的interceptKeyBeforeQueueing
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
···
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, args->keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
//然後將這個keyevent放到list中
needWake = enqueueInboundEventLocked(newEntry);//將這個event放入到隊列中,供後面進行處理(1)
if (needWake) {//這個會喚醒dispatcher loop.也就是會調dispatchOnce
mLooper->wake();
}
}
這裏需要注意,PhoneWindowManager裏面的interceptKeyBeforeQueueing實在這個階段調用的。這時候還沒加入到queue中。
將Event加入到Queue中之後還要對queue進行處理。後面調用mLooper->wake()的目的就是開始後續的處理。
void InputDispatcher::dispatchOnce() {
if (!haveCommandsLocked()) {
ALOGE("no commands");
dispatchOnceInnerLocked(&nextWakeupTime);
}
//此時應該已經將要執行的command放入到了queue中。所以要運行queue中的command
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
這個函數比較有意思,下面詳細分析一下
先看haveCommandsLocked函數
bool InputDispatcher::haveCommandsLocked() const {
return !mCommandQueue.isEmpty();
}
這個函數看是否已經存才command,第一次執行會返回false。
下面看dispatchOnceInnerLocked
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
···
case EventEntry::TYPE_KEY: {
···
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
···
}
···
}
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
if (mFocusedWindowHandle != NULL) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
return false; // wait for the command to run
} else {
···
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
···
}
···
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);//這個函數用來查找有哪些對象已經建立了connection。event將會發送給所有的註冊進來的對象。也就是activity。
···
dispatchEventLocked(currentTime, entry, inputTargets);
···
}
postCommandLocked函數就是向mCommandQueue中添加command的實現如下:
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
CommandEntry* commandEntry = new CommandEntry(command);
mCommandQueue.enqueueAtTail(commandEntry);
return commandEntry;
}
執行完這個函數只有command queue中已經存在command,但是還沒執行。
下面繼續分析
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
pokeUserActivityLocked(eventEntry);//用來決定是否要喚醒設備或者點亮屏幕,最終調用的是PowerManagerService。
//下面將會通知所有註冊進來的channen,有event發生了。
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
···
}
}
}
下面的調用順序爲:prepareDispatchCycleLocked-> enqueueDispatchEntriesLocked &startDispatchCycleLocked
這裏面有個小的細節說明一下:enqueueDispatchEntriesLocked函數會調用enqueueDispatchEntryLocked函數。
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
···
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
···
connection->outboundQueue.enqueueAtTail(dispatchEntry);
···
}
這裏會封裝DispatchEntry,之後放到connection,也就是server socket的封裝對象的outboundQueue中。那麼在後面發送的時候就會從這裏面取event。
繼續後面的分析
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
···
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// Publish the key event.
// call InputTransport.cpp
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
···
}
這裏會調用InputTransport中的publishKeyEvent
status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
InputMessage msg;
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg);
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
···
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
···
}
也就是調用socket的send函數。這裏的mFd對應的是Server端的socket。
由於Server/client的socket是通過socketpair的方式打開的,所以向Server端socket寫入數據時,client端的socket就能讀取數據。
根據之前的分析可知client端的socket加入到了epoll中ALOOPER_EVENT_INPUT。所以它將會從epoll中返回。
處理代碼
android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
···
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
···
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);//調用InputManagerService.dispatchInputEvent
···
···
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
···
for (;;) {
status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);
}
···
}
InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
while (!*outEvent) {
status_t result = mChannel->receiveMessage(&mMsg);
}
···
switch (mMsg.header.type) {
case InputMessage::TYPE_KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;
initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;
break;
}
···
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);//調用InputManagerService.dispatchInputEvent
···
}
看到在獲取完event之後就調用了dispatchInputEvent。由前面的分析可以知道,在新的view生成之後,註冊client socket時創建了WindowInputEventReceiver,這個類是繼承自InputEventReceiver。所以這裏面調用的dispatchInputEvent就是WindowInputEventReceiver。根據類的繼承關係,在dispatchInputEvent中會調用onInputEvent。
接下來的就是在ViewRootImpl中對event進行處理。
ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
···
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
···
}
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
//將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;
//處理event
if (processImmediately) {
doProcessInputEvents();//處理event
} else {
scheduleProcessInputEvents();
}
}
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;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
deliverInputEvent(q);
}
···
}
//決定應該是傳遞給那個stage,之後調用stage.deliver()開始處理input event。
private void deliverInputEvent(QueuedInputEvent q) {
InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
通過上面的分析可以發現,jni層獲取到消息之後,會傳遞給framework層的InputEventReceiver。之後交給ViewRootImpl中的stage進行按鍵的處理。下面對stage進行一下分析
ViewRootImpl中stage順序
這裏面的Stage是一個邏輯結構,類似於StateMachine。當有InputEvent之後將會傳遞到這個結構中進行處理。處理完成之後,會調用finishInputEvent函數來通知jni層,這個event已經處理完成。
各個Stage之間的關係如下圖所示:
指定的初始化stage
mFirstInputStage = nativePreImeStage;//按鍵處理的第一個stage
mFirstPostImeInputStage = earlyPostImeStage;
根據打印的log看,當接收到遙控器按鍵時將會調用mView.dispatchKeyEvent(),而這裏的mView就是在創建Activity是通過setView設置進來的。當這個InputEvent事件處理完成之後,會調用finishInputEvent函數。
ViewRootImpl.java
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);
}
public final void finishInputEvent(InputEvent event, boolean handled) {
int index = mSeqMap.indexOfKey(event.getSequenceNumber());
if (index < 0) {
Log.w(TAG, "Attempted to finish an input event that is not in progress.");
} else {
int seq = mSeqMap.valueAt(index);
mSeqMap.removeAt(index);
nativeFinishInputEvent(mReceiverPtr, seq, handled);
}
event.recycleIfNeededAfterDispatch();
}
看到,會調用nativeFinishInputEvent進行處理,也就是會調用NativeInputEventReceiver.finishInputEvent()處理。
android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
···
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
···
}
這裏面的mInputConsumer與之前發送InputEvent是一樣的,
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
···
return sendUnchainedFinishedSignal(seq, 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);
}
通過這部分代碼,可以看出最後是通過client端的socket,將finish事件發送給jni層中的server端的。前面的分析可以知道,在註冊server端的socket時,將socket註冊到epoll中,並且指定有event時的處理函數爲handleReceiveCallback。
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
//根據fd查找到對應的connection
ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
···
//開始下一輪的dispatch
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
if (gotOne) {
d->runCommandsLockedInterruptible();
if (status == WOULD_BLOCK) {
return 1;
}
}
···
d->unregisterInputChannelLocked(connection->inputChannel, notify);
}
至此,InputEvent的整個處理過程已經完全結束。
總結
Input event事件的處理,大概流程如下:
1.EventHub從驅動中獲取InputEvent
2.InputReader從EventHub中讀取數據發送給InputDispatcher
3.InputDispatcher發送給InputTransport,
4.InputTransport將消息發送給framework層的ViewRootImpl
5.ViewRootImpl對事件進行處理,完成之後發送finish給native層,用來啓動下一輪的dispatch
事件是通過註冊到epoll中的Server/Client sockets進行傳遞的。
發送event時會發送到所有的channel中的。