该篇文章仅分析notifyKey之后的流程,InputReader怎么读取之类的本文不关心.本文重点关注InputDispatcher和java层的交互,包括调用interceptKeyBeforeQueueing和interceptKeyBeforeDispatching方法,以及有辅助服务拦截按键时的处理.
1.notifyKey主函数
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
...
...
...
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
主函数中有四个重要的调用,我们需要分别分析:
1.mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);//最终会调用到PWM中对应的方法
2.shouldSendKeyToInputFilterLocked(args)//和辅助服务相关
3.needWake = enqueueInboundEventLocked(newEntry);//把按键加入队列
4.mLooper->wake();//唤醒线程,从队列中去除按键事件执行分发
首先分析第一步interceptKeyBeforeQueueing,mPolicy其实是NativeInputManager对象,去该对象中看看具体调用:
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
// Policy:
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
// - For normal events wake and brighten the screen if currently off or dim.
bool interactive = mInteractive.load();
if (interactive) {
policyFlags |= POLICY_FLAG_INTERACTIVE;
}
if ((policyFlags & POLICY_FLAG_TRUSTED)) {
nsecs_t when = keyEvent->getEventTime();
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
} else {
if (interactive) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
}
其中会主要是调用env->CallIntMethod(mServiceObj,gServiceClassInfo.interceptKeyBeforeQueueing,keyEventObj, policyFlags).该方法会调用InputManagerService的interceptKeyBeforeQueueing,InputManagerService又会调用PhoneWindowManager的interceptKeyBeforeQueueing,然后会有一个返回值赋给wmActions,而接下来handleInterceptActions会根据wmActions的值来更新policyFlags:
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions: Not passing key to user.");
#endif
}
}
也就意味着我们在PhoneWindowManager中可以通过返回值来控制policyFlags的值,事件分发过程中多次判断该值,决定要不要继续分发.
第二步shouldSendKeyToInputFilterLocked,当有辅助服务配置接收按键的话,该方法返回true,进入判断,然后调用如下代码:
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
逻辑很简单,调用NativeInputManager的filterInputEvent方法,如果该返回值返回false则notifyKey方法直接返回,实际上只要shouldSendKeyToInputFilterLocked走进来的话,如果没有异常产生filterInputEvent总是返回false的,那么事件怎么分发传递的?这就是我们接下来要分析的:
bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
// The callee is responsible for recycling the event.
jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
inputEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
pass = true;
}
env->DeleteLocalRef(inputEventObj);
return pass;
}
可以看出没有异常发生的话,返回的值为InputManagerService中返回的值:
// Native callback.
final boolean filterInputEvent(InputEvent event, int policyFlags) {
synchronized (mInputFilterLock) {
if (mInputFilter != null) {
try {
mInputFilter.filterInputEvent(event, policyFlags);
} catch (RemoteException e) {
/* ignore */
}
return false;
}
}
event.recycle();
return true;
}
在InputManagerService中,可以看到只要mInputFilter不为空就返回false,而上篇文章分析过了,如果系统存在接收按键的辅助服务,AccessibilityManagerService会调用setInputFilter,会更新mInputFilter,该值不会为空.所以可以得出结论,只要有接收按键的辅助服务,则notifyKey不会传递,但是,实际情况按键还是有效的,到底哪里把这些按键传递了呢?我们回到上篇文章分析过得mInputManager.setInputFilter(filter)方法里面去:
public void setInputFilter(IInputFilter filter) {
if (filter != null) {
mInputFilter = filter;
mInputFilterHost = new InputFilterHost();
try {
filter.install(mInputFilterHost);
} catch (RemoteException re) {
/* ignore */
}
}
nativeSetInputFilterEnabled(mPtr, filter != null);
}
我们看见,有一个filter.install(mInputFilterHost)的操作,奥秘就在这里,InputFilter的filterInputEvent方法同时会调用到InputFilterHost的sendInputEvent方法,其中的调用读者可以自己去看,限于篇幅,不作分析,很简单.
@Override
public void sendInputEvent(InputEvent event, int policyFlags) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
synchronized (mInputFilterLock) {
if (!mDisconnected) {
nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
policyFlags | WindowManagerPolicy.FLAG_FILTERED);
}
}
}
谜底已经揭开,nativeInjectInputEvent最终回调用InputDispatcher的injectInputEvent方法,该方法和notifyKey有相同的调用,就是我们上面分析的3,4步
3.needWake = enqueueInboundEventLocked(newEntry);//把按键加入队列
4.mLooper->wake();//唤醒线程,从队列中去除按键事件执行分发
第三步比较简单,只是调用mInboundQueue.enqueueAtTail(entry),把事件放入队列.
重点是第四步,相当复杂,开头就很复杂mLooper->wake()怎么就能唤醒线程了呢?这个我们要细细捋一捋了,里面牵扯到native的线程和looper的pollOnce,wake.
SystemServer在启动的时候会去创建InputManagerService,在InputManagerService的构造函数中回调用nativeInit来初始化native层的InputManager,最终调用的的代码如下:
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
其中创建了一个InputDispatcherThread对象,该对象父类为Thread,我们去看看Thread的源码
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast(user);
sp strong(self->mHoldSelf);
wp weak(strong);
self->mHoldSelf.clear();
#if defined(__ANDROID__)
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
// running at least once after a successful ::readyToRun()
// (unless, of course, the thread has already been asked to exit
// at that point).
// This is because threads are essentially used like this:
// (new ThreadSubclass())->run();
// The caller therefore does not retain a strong reference to
// the thread and the thread would simply disappear after the
// successful ::readyToRun() call instead of entering the
// threadLoop at least once.
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
// establish a scope for mLock
{
Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mRunning = false;
// clear thread ID so that requestExitAndWait() does not exit if
// called by a new thread using the same thread ID as this one.
self->mThread = thread_id_t(-1);
// note that interested observers blocked in requestExitAndWait are
// awoken by broadcast, but blocked on mLock until break exits scope
self->mThreadExitedCondition.broadcast();
break;
}
}
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
strong.clear();
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
} while(strong != 0);
return 0;
}
native层其实是调用pthread_create来创建线程的,把上述代码中的_threadLoop函数作为参数传递进去,那么实际会运行还函数,该函数会一直调用threadLoop函数,直到该函数返回值为false才执行完毕,而InputDispatcherThread的threadLoop方法返回值永远是true,那么该线程起来后会不断调用threadLoop方法
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
其实会一直循环调用dispatchOnce方法,我们进入该方法看看:
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,runCommandsLockedInterruptible方法这两个方法我们以后分析,还有会调用mLooper->pollOnce(timeoutMillis),该方法会使线程wait,wait的时间就是timeoutMillis,而timeoutMillis在一次按键被处理完成之后值其实是非常大的数字,可以理解为,该线程永远在wait的状态,而mLooper->wake()则可以让其退出wait的状态,综上所述我们可以简单描述下InputDispatcher分发时间的基本流程
1.会有一个InputDispatcherThread线程一直循环读取事件队列中的事件,没有事件则会wait
2.有事件触发的话则该事件会进入事件队列,并且会调用mLooper->wake()来唤醒InputDispatcherThread线程
好了,现在我们第四步中的背景知识已经介绍完毕了,我们现在正式分析dispatchOnce方法,我们逐步分析,先分析
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) {
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
bool done = false;
DropReason dropReason = DROP_REASON_NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DROP_REASON_POLICY;
} else if (!mDispatchEnabled) {
dropReason = DROP_REASON_DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = NULL;
}
switch (mPendingEvent->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast(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;
}
default:
ALOG_ASSERT(false);
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
}
}
首次进入时候mPendingEvent为空,则需要去队列中拿一个出来赋值给mPendingEvent,然后会调用dispatchKeyLocked方法并且把mPendingEvent作为参数传入,dispatchKeyLocked方法有一个返回值,如果为true的则会调用releasePendingEventLocked把mPendingEvent释放并置为空,去dispatchKeyLocked中看看
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// 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;
}
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
Vector 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;
}
可以看到主要逻辑为判断entry->interceptKeyResult的值,该值来决定进入哪个逻辑,interceptKeyResult的初始值为INTERCEPT_KEY_RESULT_UNKNOWN,我们先去看看该逻辑,该逻辑主要判断如果policyFlags中有POLICY_FLAG_PASS_TO_USER的话,则把该事件和doInterceptKeyBeforeDispatchingLockedInterruptible方法包装成一个commandEntry,放入command队列,并且该方法返回false.上段分析过如果返回为true才会去把mPendingEvent释放并置为空,则这个时候mPendingEvent还是不为空,dispatchOnceInnerLocked已经分析完了,我们接着走
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
runCommandsLockedInterruptible中会去判断command队列是否为空,如果是空则返回false,刚才分析该队列不为空,则会执行那个command,并且返回true,其实会执行doInterceptKeyBeforeDispatchingLockedInterruptible方法:
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
KeyEvent event;
initializeKeyEvent(&event, entry);
mLock.unlock();
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);
mLock.lock();
if (delay < 0) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
} else if (!delay) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
entry->interceptKeyWakeupTime = now() + delay;
}
entry->release();
}
该方法最终会调用PWM的interceptKeyBeforeDispatching方法,然后根据返回值来更新interceptKeyResult,这个地方就是java层的第二次拦截了,我们完全可以返回负数,从而导致interceptKeyResult为INTERCEPT_KEY_RESULT_SKIP,从而跳过该事件.
我们回到runCommandsLockedInterruptible中,该方法返回true,则nextWakeupTime = LONG_LONG_MIN,那么mLooper->pollOnce(timeoutMillis)不会等待马上执行,又会回到threadLoop函数中,回到了我们最初分析的第四步的开头,不同的是此时mPendingEvent不为空并且mPendingEvent的interceptKeyResult也不为INTERCEPT_KEY_RESULT_UNKNOWN,进入真正的按键传递,最终会调用publishKeyEvent传递给应用,这些流程读者自己分析.