InputReader封装好KeyEntries,通知InputDispatch处理事件,先看看Dispatcher的构建函数,新建了一个looper,来做dispatcher的分发循环,并获取了一下Dispatcher的配置信息,这里的配置信息的default值有key的超时和延迟时间,更多的配置在ViewConfiguration中,这些配置都是在input dispatcher初始化的时候加载进来的。
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE), mIsPredumping(false) {
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
}
InputManager在start InputReaderThread之后,同时也启动了InputDispatchThread,这里looper循环里就只有一个dispatchOnce方法,mDispatch是一个InputDispatcherInterface对象,这个接口使用来异步通知系统input reader上报上来的input event事件。
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {}
InputDispatcherThread::~InputDispatcherThread() {}
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
}
首先定义了一个超长的下次唤醒时间,然后去获取锁,检查命令队列里面有没有还没有执行的命令,如果有命令的话就会执行dispatchOnceInnerLocked,如果命令列表为空的话就会入队命令继续运行;
Queue<CommandEntry> mCommandQueue;
···
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
//如果设备处于非交互状态,Dispatch被disable了,就去重置key的repeat计时器,保证当设备刚唤醒的时候抛弃key repeat事件
if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
//如果dispatch被冻结,就不处理超时唤醒或者任何新的事件
if (mDispatchFrozen) {
return;
}
// 当发生app切换,比如home键或者挂断键按下,就把app切换的时间作为下一次唤醒的时间
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
if (! mPendingEvent) {
//命令队列为空
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
//刚发生过一次app切换,但此时入站队列是空,所以等的切换事件就不会来,所以不再等待,并重置flag,
//这里的逻辑应该是,如果有事件,入站队列肯定不应为空
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
//mKeyRepeatState是记录key repeat的结构体
//如果repeat key的nexttime已经过了,就重新做了一个mPendingEvent去处理
//如果没有nexttime没有过时,但是wakeup的time在repeat time之后,就得让唤醒时间提前。
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// 如果没有重新做一个mPendingEvent事件退出
if (!mPendingEvent) {
return;
}
} else {
// 入站队列至少有一条item,就将事件出队列赋值到当前的处理对象上去
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// 对比flag看要不要把这一次生成的mPendingEvent捅给用户进程
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// 准备分发数据
resetANRTimeoutsLocked();
}
mPendingEvent是EventEntry对象
struct EventEntry : Link<EventEntry> {
enum {
TYPE_CONFIGURATION_CHANGED,
TYPE_DEVICE_RESET,
TYPE_KEY,
TYPE_MOTION
};
mutable int32_t refCount;
int32_t type;
nsecs_t eventTime;
uint32_t policyFlags;
InjectionState* injectionState;
bool dispatchInProgress; // initially false, set to true while dispatching
inline bool isInjected() const { return injectionState != NULL; }
void release();
virtual void appendDescription(String8& msg) const = 0;
protected:
EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags);
virtual ~EventEntry();
void releaseInjectionState();
};
再看看他是怎么往window manager那里捅的
sp<InputWindowHandle> mFocusedWindowHandle;
//InputWindowHandle是window用来接收InputDispatcher传来的input事件,并且能够使InputDispatcher
//间接的操作到window manager的window state
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
//这个功能可以被window manager 禁用掉
if (mFocusedWindowHandle != NULL) {
const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
return;
}
}
int32_t eventType = USER_ACTIVITY_EVENT_OTHER;
switch (eventEntry->type) {
case EventEntry::TYPE_MOTION:
case EventEntry::TYPE_KEY: {
const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
return;
}
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
}
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doPokeUserActivityLockedInterruptible);
commandEntry->eventTime = eventEntry->eventTime;
commandEntry->userActivityEventType = eventType;
}
postCommandLocked是新建了一个CommandEntry对象,并把对应的command入到队尾。
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
CommandEntry* commandEntry = new CommandEntry(command);
mCommandQueue.enqueueAtTail(commandEntry);
return commandEntry;
}
CommandEntry 是这样一个东西
struct CommandEntry : Link<CommandEntry> {
CommandEntry(Command command);
~CommandEntry();
Command command;
sp<Connection> connection;
nsecs_t eventTime;
KeyEntry* keyEntry;
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
String8 reason;
int32_t userActivityEventType;
uint32_t seq;
bool handled;
};
运行存在的所有命令,如果有命令执行就立马唤醒下一个poll;
释放锁之后,就开始等待回调、超时唤醒、唤醒
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
准备好一次EventEntry事件之后,就开始针对type针对性的处理各种类型的事件,前面说的是入队事件的流程,即使一个事件需要丢弃,也是会走这样的一个流程。这里就以dispatchKeyLocked来看看做了哪些操作。
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
dropReason = DROP_REASON_APP_SWITCH;
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
dispatchKeyLocked的实现,首先是一个处理中的flag判断,如果没有处理,就开始看当前keyevent repeatCount是不是等于0,按键是不是down的状态,策略flag是不是可信的,且没有disable掉重复按键逻辑,如果这一次的keyEvent的按键code是和上一次按键的相同,就认为是一次设备驱动生成的重复按键事件,然后更新当前keyevent的repeat count,为前一次的+1,同时释放前一次按键,由当前按键作为下一次按键事件的lastevent,因为是自己生成的repeat key所以,next repeat time设置成超长的时间间隔;如果本次key event 传过来的是新值,就需要设置新的重复按键计时,并将本次key event更新为last keyevent,refcount+1.repeatCount==1的时候就会设置长按的flag到key event的flag里面,然后修改标记为正在处理。
if (! entry->dispatchInProgress) {
if (entry->repeatCount == 0
&& entry->action == AKEY_EVENT_ACTION_DOWN
&& (entry->policyFlags & POLICY_FLAG_TRUSTED)
&& (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
} else {
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
} else if (! entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
if (entry->repeatCount == 1) {
entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
} else {
entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
}
entry->dispatchInProgress = true;
dispatch policy可以控制处理延迟,可以将本次事件延迟到下一次解决;后续还有允许policy中断keyevent的逻辑,drop的逻辑。
我们关注最重要的这一部分
1.首先是new了一个inputTargets对象,然后通过findFocusedWindowTargetsLocked,找到当前focus的window,这一步里面会检查权限,以及是否有focus的window,以及这个window是否可以接受新的input了,都成功后,会通过addWindowTargetLocked将mFocusedWindowHandle保存的window信息放入到InputTarget对象当中去并将结果setInjectionResultLocked设置进entry中
2.addMonitoringTargetsLocked()是将input target做一个备份,InputChannel会接受所有input的事件的拷贝。
Vector<sp<InputChannel> > mMonitoringChannels;
3.做好这些工作后,就准备分发key了dispatchEventLocked
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);
dispatchEventLocked(currentTime, entry, inputTargets);
dispatchEventLocked这里也做了一个把eventEntry处理一下,发送到command队列里面等待执行。然后针对每个input target,在dispatcher里面,所有的dispatch的事件都通过input target里面指定的一个inputchannel进行连接;所有注册过后的连接,都会通过input channel的文件描述符进行map。
找到connection之后,将eventEntry,currentTime,还有inputTarget一起塞进prepareDispatchCycleLocked。
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
pokeUserActivityLocked(eventEntry);
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 {
//drop已经不再注册表里特定channel的事件
}
}
}
prepareDispatchCycleLocked这里是转了一道
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
//如果连接状态不是normal就不处理event
if (connection->status != Connection::STATUS_NORMAL) {
return;
}
//如果有需求就可以分离出motion事件处理
if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
MotionEntry* splitMotionEntry = splitMotionEvent(
originalMotionEntry, inputTarget->pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
enqueueDispatchEntriesLocked(currentTime, connection,
splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// 如果没有motion分离的需求,直接将事件入队列
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
enqueueDispatchEntriesLocked为实际工作对象,这里暂不清楚为什么要将本次eventEntry通过全模式入队出站队列。
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
//根据要求的模式,入队事件。
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 (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
如果当前出站队列为空的话,就如如下处理,channel通过socket向远端发送eventEntry
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// 封装keyevent消息
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;
}
connection->outboundQueue.dequeue(dispatchEntry);
connection->waitQueue.enqueueAtTail(dispatchEntry);
}
//将keyevent事件通过mChannel->sendMessage(&msg);发送到出站队列内
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);
}
如果出站队列不为空的话enqueueDispatchEntryLocked就处理了一下connection的input state然后就更新了一下,connection的outboundQueue
connection->outboundQueue.enqueueAtTail(dispatchEntry);
至此,我们看到处理逻辑全部都被发送到command队列中去了。
bool InputDispatcher::runCommandsLockedInterruptible() {
if (mCommandQueue.isEmpty()) {
return false;
}
do {
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
(this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
delete commandEntry;
} while (! mCommandQueue.isEmpty());
return true;
}
viewRootImpl的setView方法中,新建了InputChannel,mWindowSession.addToDisplay最后会传递到WindowManagerService的addWindow方法,把InputChannel传输到WindowManagerService中,建立传输通道,然后又新建了WindowInputEventReceiver,
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
···
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
···
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
···
WMS中的addWindow,注册了inputChannel,设定了channel对,数据流向是有InputPublisher和InputConsumer在组合了InputChannel后决定的
mPolicy.adjustWindowParamsLw(win.mAttrs);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
try {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "handle Input channel erorr", e);
return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
}
}
网友评论