在Android输入子系统之启动过程分析中,InputManagerService启动之后,会调用start函数,之后调用native层的nativeStart函数,然后调用InputManager::start函数,该函数会调用InputDispatcherThread的threadLoop函数,该函数会调用InputDispatcher的dispatchOnce函数进行一次按键分发,如果没有按键事件发生,则睡眠。
这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
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()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// 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;
}
} // 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);
}
上述函数主要是调用dispatchOnceInnerLocked来进行一次按键分发,当没有按键消息时会走到mLooper->pollOnce(timeoutMillis);这个函数会进入睡眠状态,当有按键消息发生时该函数会返回,然后走到dispatchOnceInnerLocked函数。这里mLooper->pollOnce为何会睡眠涉及到Android的Handler机制,后续再研究
函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
...
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
//当InputReader往队列中插入了一个读取的键盘消息后,此处的mInboundQueue就不为空
if (mInboundQueue.isEmpty()) {
...
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
...
}
...
}
...
switch (mPendingEvent->type) {
...
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
...
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
...
}
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
从前文InputReader读取键盘消息过程分析 InputReader读取到一个消息后会调用KeyboardInputMapper的processKey,该函数会调用InputDispatcher的notifyKey函数,然后InputDispatcher会调用enqueueInboundEventLocked函数,将EventEntry加入到mInboundQueue中,然后调用mLooper->wake函数会唤醒InputDispatcherThread线程,InputDispatcher中把队列的第一个事件取出来,因为这里是键盘事件,所以mPendingEvent->type是EventEntry::TYPE_KEY,然后调用dispatchKeyLocked函数
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
// Give the policy a chance to intercept the key.
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 {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DROP_REASON_NOT_DROPPED) {
*dropReason = DROP_REASON_POLICY;
}
}
...
// Identify targets.
Vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
addMonitoringTargetsLocked(inputTargets);
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
这个函数主要做了下面三件事
A. 如果按键是第一次分发,则将命令封装为CommandEntry加入队列,后续执行doInterceptKeyBeforeDispatchingLockedInterruptible,以给java层拦截按键的机会
B. 找到当前激活的Window窗口,并将其加入到Vendor中
C. 找到需要主动监听按键的InputChannel,封装成InputTarget,加入到Vendor中
D. 将按键分发到上面的Vendor中的InputChannel中,这里存在多个
下面先分析如果将按键分发给InputChannel
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector& inputTargets) {
...
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 = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
}
该函数主要是依次取出Vector中的InputTarget,根据InputTarget的InputChannel找到保存在mConnectionByFd中的Connection对象,并调用prepareDispatchCycleLocked函数进行分发
下面先分析如果将按键分发给InputChannel
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
...
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
函数前面还有一些状态检查,这里默认都是通过的。最后enqueueDispatchEntriesLocked函数进行将connection分装成DispatchEntry,加入到connection->outboundQueue的队列中
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
这个函数首先获取以前的connection的outboundQueue是否为空,然后将该事件调用enqueueDispatchEntryLocked将事件加入到outboundQueue中,如果以前为空,现在不为空,则调用startDispatchCycleLocked开始分发,如果以前的outboundQueue不为空,说明当前的Activity正在处理前面的按键,则不需要再调用startDispatchCycleLocked,因为只要开始处理,会等到队列为空才会停止。
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// Publish the key event.
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;
}
...
}
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
if (connection->waitQueue.isEmpty()) {
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
"event to it, status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
"waiting for the application to catch up",
connection->getInputChannelName());
#endif
connection->inputPublisherBlocked = true;
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
"status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
return;
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}//end of while
}
该函数从outboundQueue中取出需要处理的键盘事件,交给connection的inputPublisher去分发,之后将事件加入到connection的waitQueue中。分发事件是通过InputPublisher的publishKeyEvent来完成的。
该函数定义在frameworks/native/libs/input/InputTransport.cpp
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);
}
该函数主要是将各个参数封装到InputMessage中,然后交给mChannel对象去分发
该函数定义在frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
return OK;
}
该函数主要是通过send函数往socket的server端写入InputMessage对象,应用程序这一侧正睡眠在client端的fd上,此时client端就会收到该InputMessage,client会进行按键按键分发,应用程序这一侧的按键分发看下一篇。
至此InputDispatcher在server端的分发已经结束