inputdispatcher按键的派发

 

 

 InputReader.pollOnce,EventHub.getEvent这两个函数分别定义在frameworks/base/libs/ui/InputReader.cppframeworks/base/libs/ui/EventHub.cpp文件中,前面我们在分析InputManager的启动过程的Step 17Step 18时,已经看到过这两个函数了。InputReaderThread线程会不断地循环调用InputReader.pollOnce函数来读入键盘事件,而实际的键盘事件读入操作是由EventHub.getEvent函数来进行的。如果当前没有键盘事件发生,InputReaderThread线程就会睡眠在EventHub.getEvent函数上,而当键盘事件发生后,就会把这个事件封装成一个RawEvent对象,然后返回到pollOnce函数中,执行process函数进一步处理:

SETP1

InputReaderThread线程的处理:

void InputReader::loopOnce() {

   int32_t oldGeneration;

   int32_t timeoutMillis;

   bool inputDevicesChanged = false;

   Vector inputDevices;

    {// acquire lock

       AutoMutex _l(mLock);

 

       oldGeneration = mGeneration;

       timeoutMillis = -1;

 

       uint32_t changes = mConfigurationChangesToRefresh;

       if (changes) {

           mConfigurationChangesToRefresh = 0;

           timeoutMillis = 0;

           refreshConfigurationLocked(changes);

       } else if (mNextTimeout != LLONG_MAX) {

           nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

           timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);

       }

    }// release lock

 

    size_t count =mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

//最关键的步骤,获取按键事件。前面有分析过。这里就是调用的地方。

    {// acquire lock

       AutoMutex _l(mLock);

       mReaderIsAliveCondition.broadcast();

 

       if (count) {

           processEventsLocked(mEventBuffer, count);

//继续处理获取到的mEventBuffer.这里只关注流程,细节判断暂时不跟进。

       }

      。。。。。。。。。。。

}

SETP2:

frameworks\native\services\inputflinger\InputReader.cpp

 

void InputReader::processEventsLocked(constRawEvent* rawEvents, size_t count) {

   for (const RawEvent* rawEvent = rawEvents; count;) {

       int32_t type = rawEvent->type;

       size_t batchSize = 1;

        if (type

           int32_t deviceId = rawEvent->deviceId;

           while (batchSize < count) {

                if (rawEvent[batchSize].type>= EventHubInterface::FIRST_SYNTHETIC_EVENT

                        || rawEvent[batchSize].deviceId !=deviceId) {

                    break;

                }

                batchSize += 1;

           }

#if DEBUG_RAW_EVENTS

           ALOGD("BatchSize: %d Count: %d", batchSize, count);

#endif

           processEventsForDeviceLocked(deviceId,rawEvent, batchSize);

       } else {

…….

       }

       count -= batchSize;

       rawEvent += batchSize;

    }

}

Setp3:

void InputReader::processEventsForDeviceLocked(int32_tdeviceId,

       const RawEvent* rawEvents, size_t count) {

   ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

   if (deviceIndex < 0) {

       ALOGW("Discarding event for unknown deviceId %d.", deviceId);

       return;

    }

 

   InputDevice* device = mDevices.valueAt(deviceIndex);

    if (device->isIgnored()) {

       //ALOGD("Discarding event for ignored deviceId %d.",deviceId);

       return;

    }

 

device->process(rawEvents, count);

//首先从rawEvent中取得触发键盘事件设备对象device,然后调用它的process函数进行处理

}

 

SETP4:

void InputDevice::process(constRawEvent* rawEvents, size_t count) {

   // Process all of the events in order for each mapper.

   // We cannot simply ask each mapper to process them in bulk becausemappers may

   // have side-effects that must be interleaved.  For example, joystick movement events and

   // gamepad button presses are handled by different mappers but theyshould be dispatched

   // in the order received.

   size_t numMappers = mMappers.size();

   for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {

#if DEBUG_RAW_EVENTS

       ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08xwhen=%lld",

                rawEvent->deviceId,rawEvent->type, rawEvent->code, rawEvent->value,

                rawEvent->when);

#endif

 

       if (mDropUntilNextSync) {

           if (rawEvent->type == EV_SYN && rawEvent->code ==SYN_REPORT) {

                mDropUntilNextSync = false;

#if DEBUG_RAW_EVENTS

                ALOGD("Recovered from input event bufferoverrun.");

#endif

           } else {

#if DEBUG_RAW_EVENTS

                ALOGD("Dropped input eventwhile waiting for next input sync.");

#endif

           }

       } else if (rawEvent->type == EV_SYN && rawEvent->code ==SYN_DROPPED) {

           ALOGI("Detected input event buffer overrun for device %s.",getName().string());

           mDropUntilNextSync = true;

           reset(rawEvent->when);

       } else {

           for (size_t i = 0; i < numMappers; i++) {

                InputMapper* mapper =mMappers[i];

                mapper->process(rawEvent);

/*

这里的mMapper成员变量保存了一系列输入设备事件处理象,例如负责处理键盘事件的KeyboardKeyMapper对象、负责处理轨迹球事件的TrackballInputMapper对象以及负责处理触摸屏事件的TouchInputMapper对象,它们是在InputReader类的成员函数createDevice中创建的。这里查询每一个InputMapper对象是否要对当前发生的事件进行处理。由于发生的是键盘事件,真正会对该事件进行处理的只有KeyboardKeyMapper对象。

*/

           }

       }

    }

}

 

STEP5:

frameworks\native\services\inputflinger\InputReader.cpp

 

void KeyboardInputMapper::process(constRawEvent* rawEvent) {

   switch (rawEvent->type) {

   case EV_KEY: {

       int32_t scanCode = rawEvent->code;

       int32_t usageCode = mCurrentHidUsage;

       mCurrentHidUsage = 0;

 

       if (isKeyboardOrGamepadKey(scanCode)) {

           int32_t keyCode;

           uint32_t flags;

           if (getEventHub()->mapKey(getDeviceId(),scanCode, usageCode, &keyCode, &flags))

//      这里应该是将linux_code的键值,转换为了android_key的键值。很关键的一个转换。后面专门分析如何转换。一般是通过generac.lk文件对应的。带验证。

{

                keyCode = AKEYCODE_UNKNOWN;

                flags = 0;

           }

           processKey(rawEvent->when, rawEvent->value!= 0, keyCode, scanCode, flags);

       }

       break;

}

。。。。。。

}

 

STEP6:

voidKeyboardInputMapper::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);

//这个notifyKey 应该是对应InputDispatcher.cpp中的notifykey(),具体如何通讯的,待学习。

    ALOGD_READER("notifyKey - eventTime=%lld,deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "

                "flags=0x%x, keyCode=0x%x,scanCode=0x%x, metaState=0x%x, downTime=%lld",

                args.eventTime, args.deviceId,args.source, args.policyFlags,

                args.action, args.flags,args.keyCode, args.scanCode,

                args.metaState, args.downTime);

}

 

STEP 7:

\frameworks\native\services\inputflinger\InputDispatcher.cpp

 

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

#if DEBUG_INBOUND_EVENT_DETAILS

   ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x,policyFlags=0x%x, action=0x%x, "

           "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x,downTime=%lld",

           args->eventTime, args->deviceId, args->source,args->policyFlags,

           args->action, args->flags, args->keyCode, args->scanCode,

           args->metaState, args->downTime);

#endif

   if (!validateKeyEvent(args->action)) {

       return;

    }

 

   uint32_t policyFlags = args->policyFlags;

   int32_t flags = args->flags;

   int32_t metaState = args->metaState;

   if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags &AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {

       policyFlags |= POLICY_FLAG_VIRTUAL;

       flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;

    }

   if (policyFlags & POLICY_FLAG_FUNCTION) {

       metaState |= AMETA_FUNCTION_ON;

    }

 

    policyFlags |= POLICY_FLAG_TRUSTED;

 

   int32_t keyCode = args->keyCode;

   if (metaState & AMETA_META_ON && args->action ==AKEY_EVENT_ACTION_DOWN) {

       int32_t newKeyCode = AKEYCODE_UNKNOWN;

       if (keyCode == AKEYCODE_DEL) {

           newKeyCode = AKEYCODE_BACK;

       } else if (keyCode == AKEYCODE_ENTER) {

           newKeyCode = AKEYCODE_HOME;

       }

       if (newKeyCode != AKEYCODE_UNKNOWN) {

           AutoMutex _l(mLock);

           struct KeyReplacement replacement = {keyCode, args->deviceId};

           mReplacedKeys.add(replacement, newKeyCode);

           keyCode = newKeyCode;

           metaState &= ~AMETA_META_ON;

       }

    }else if (args->action == AKEY_EVENT_ACTION_UP) {

       // In order to maintain a consistent stream of up and down events, checkto see if the key

       // going up is one we've replaced in a down event and haven't yetreplaced in an up event,

       // even if the modifier was released between the down and the up events.

       AutoMutex _l(mLock);

       struct KeyReplacement replacement = {keyCode, args->deviceId};

       ssize_t index = mReplacedKeys.indexOfKey(replacement);

       if (index >= 0) {

           keyCode = mReplacedKeys.valueAt(index);

           mReplacedKeys.removeItemsAt(index);

           metaState &= ~AMETA_META_ON;

       }

    }

 

   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);

/*

mPolicyWindowManagerService注册的时候所申请。对应的为PhoneWindowManager

frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

这个interceptKeyBeforeQueueing会拦截一些按键,如POWER,HOME,BACK,VOL+,VOL-等常用的公共按键,所以只要分析这些系统共用的按键,应该就是到这里了。

*/

   bool needWake;

    {// acquire lock

       mLock.lock();

 

       if (shouldSendKeyToInputFilterLocked(args)) {

           mLock.unlock();

 

           policyFlags |= POLICY_FLAG_FILTERED;

           if (!mPolicy->filterInputEvent(&event, policyFlags)) {

               return; // event wasconsumed 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);

//enqueueInboundEventLocked函数把这个按键事件封装成一个KeyEntry结构加入到//InputDispatcher类的mInboundQueue队列中去:还有就是判断是否要唤醒InputDispatccherThread  

//线程

 

       mLock.unlock();

    }// release lock

 

   if (needWake) {

       mLooper->wake();

//looper在另外学习,这里有按键会唤醒InputDispatccherThread,继续对按键进行处理。 

    }

}

参考说明:M版本应该是有修改,没有找到Looper.cpp文档,再学习吧。

Looper.wake:这个函数定义在frameworks/base/libs/utils/Looper.cpp文件中,在前面一篇文章Android应用程序消息处理机制(LooperHandler)分析中,我们已经分析过这个函数了,这里不再详述,简单来说,它的作用就是用来唤醒睡眠在Looper对象内部的管道读端的线程,在我们的这个场景中,睡眠在Looper对象内部的管道读端的线程就是InputDispatccherThread线程了。

     我们知道,此时InputDispatccherThread线程正在InputDispatcher类的dispatchOnce函数中通过调用mLooper->loopOnce函数进入睡眠状态。当它被唤醒以后,它就会从InputDispatcher类的dispatchOnce函数返回到InputDispatcherThread类的threadLoop函数,而InputDispatcherThread类的threadLoop函数是循环执行的,于是,它又会再次进入到InputDispatcher类的dispatchOnce函数来处理当前发生的键盘事件。

 

STEP 8

\frameworks\native\services\inputflinger\InputDispatcher.cpp

voidInputDispatcher::dispatchOnce() {

    nsecs_t nextWakeupTime = LONG_LONG_MAX;

    { // acquire lock

        AutoMutex _l(mLock);

       mDispatcherIsAliveCondition.broadcast();

 

        // Run a dispatch loop if there are nopending commands.

        // The dispatch loop might enqueuecommands to run afterwards.

        if (!haveCommandsLocked()) {

            dispatchOnceInnerLocked(&nextWakeupTime);

        }

……

}

 

STEP 9:

 

voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

   nsecs_t currentTime = now();

 

   // Reset the key repeat timer whenever normal dispatch is suspendedwhile the

   // device is in a non-interactive state. This is to ensure that we abort a key

   // repeat if the device is just coming out of sleep.

   if (!mDispatchEnabled) {

       resetKeyRepeatLocked();

    }

 

   // If dispatching is frozen, do not process timeouts or try to deliverany new events.

   if (mDispatchFrozen) {

#if DEBUG_FOCUS

       ALOGD("Dispatch frozen. Waiting some more.");

#endif

       return;

    }

 

   // Optimize latency of app switches.

   // Essentially we start a short timeout when an app switch key (HOME /ENDCALL) has

   // been pressed.  When it expires,we preempt dispatch and drop all other pending events.

   bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;

   if (mAppSwitchDueTime < *nextWakeupTime) {

       *nextWakeupTime = mAppSwitchDueTime;

    }

 

   // 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 emptyso 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();

//获取到之前增加到管道里面的KEY,管道的知识待学习。

           traceInboundQueueLengthLocked();

       }

 

   。。。。。。

 

    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);

//开始派发KEY

       break;

    }

 

   case EventEntry::TYPE_MOTION: {

        ……

    }

 

   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

    }

}

 

STEP 10:

 

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry*entry,

       DropReason* dropReason, nsecs_t* nextWakeupTime) {

   // Preprocessing.

   ……

   // Identify targets.

   Vector inputTargets;

   int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,

           entry, inputTargets, nextWakeupTime);

//检查mFocusedWindowHandle是否能接收输入事件。如果可以,将之以InputTarget的形式加到目//标窗口数组中

   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;

}

 

Step 11:

 

voidInputDispatcher::dispatchEventLocked(nsecs_t currentTime,

       EventEntry* eventEntry, const Vector&inputTargets) {

#if DEBUG_DISPATCH_CYCLE

   ALOGD("dispatchEventToCurrentInputTargets");

#endif

 

   ALOG_ASSERT(eventEntry->dispatchInProgress); // should already havebeen set to true

 

pokeUserActivityLocked(eventEntry);

//待分析,还不太理解什么意思。

/*

这里会封装成CommandEntry插入到mCommandQueue队列中,后面的runCommandLockedInterruptible()函数中会调用doInterceptKeyBeforeDispatchingLockedInterruptible()来让PWM有机会进行处理

*/

   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);

       } else {

#if DEBUG_FOCUS

           ALOGD("Dropping eventdelivery to target with channel '%s' because it "

                    "is no longerregistered with the input dispatcher.",

                   inputTarget.inputChannel->getName().string());

#endif

       }

    }

}

 

STEP 12:

voidInputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

       const sp& connection, EventEntry* eventEntry,const InputTarget* inputTarget) {

……

 

   // Split a motion event if needed.

   if (inputTarget->flags & InputTarget::FLAG_SPLIT) {

       ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);

 

       MotionEntry* originalMotionEntry =static_cast(eventEntry);

       if (inputTarget->pointerIds.count() !=originalMotionEntry->pointerCount) {

            MotionEntry* splitMotionEntry =splitMotionEvent(

                    originalMotionEntry,inputTarget->pointerIds);

           if (!splitMotionEntry) {

                return; // split event wasdropped

           }

#if DEBUG_FOCUS

           ALOGD("channel '%s' ~ Splitmotion event.",

                   connection->getInputChannelName());

           logOutboundMotionDetailsLocked(" ", splitMotionEntry);

#endif

           enqueueDispatchEntriesLocked(currentTime,connection,

                   splitMotionEntry,inputTarget);

           splitMotionEntry->release();

           return;

       }

    }

 

   // Not splitting.  Enqueuedispatch entries for the event as is.

   enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);

}

 

STEP 13:

//dispatchEntry的封装

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,

       const sp& 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 cyclegoing.

   if (wasEmpty && !connection->outboundQueue.isEmpty()) {

       startDispatchCycleLocked(currentTime,connection);

    }

}

 

 

STEP 14:

voidInputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

       const sp& connection) {

#if DEBUG_DISPATCH_CYCLE

   ALOGD("channel '%s' ~ startDispatchCycle",

           connection->getInputChannelName());

#endif

//startDispatchCycleLocked函数会检查相应连接的输出缓冲中(connection->outboundQueue)是否////有事件要发送的,有的话会通过InputChannel发送出去。

   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(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;

       }

 

       case EventEntry::TYPE_MOTION: {

   ……

       }

 

     …….

 

       // Re-enqueue the event on the wait queue.

       connection->outboundQueue.dequeue(dispatchEntry);

       traceOutboundQueueLengthLocked(connection);

       connection->waitQueue.enqueueAtTail(dispatchEntry);

       traceWaitQueueLengthLocked(connection);

    }

}

 

Step 15:

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) {

#if DEBUG_TRANSPORT_ACTIONS

   ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u,deviceId=%d, source=0x%x, "

           "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x,repeatCount=%d,"

           "downTime=%lld, eventTime=%lld",

           mChannel->getName().string(), seq,

           deviceId, source, action, flags, keyCode, scanCode, metaState,repeatCount,

           downTime, eventTime);

#endif

 

   if (!seq) {

       ALOGE("Attempted to publish a key event with sequence number0.");

       return BAD_VALUE;

    }

 

   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);

}

到这里,inputdispatcher的工作就完成了。通过mchannel将消息发送出去。但是同时问题又来了。Mchannel是谁,消息有事发送给谁呢。这里我理解也是一个客户端服务器机制。这里的客户端为上层的ViewRootImpl的setView中注册。服务器端则是注册到InputDispatcher中。所以这个mChannel->sendMessage(&msg); 其实就是将服务器端的InputDispatcher 注册的inputchannel,发送给其对于的客户端ViewRootImpl。下面我们来具体看看该服务器和客户端的建立和配对过程。

 

STEP 1:

frameworks\base\core\java\android\view\ViewRootImpl.java

    publicvoid setView(Viewview, WindowManager.LayoutParams attrs, View panelParentView) {

       synchronized (this) {

           ……

               // Schedule the first layout -before- adding to the window

               // manager, to make sure we do the relayout before receiving

               // any other events from the system.

                requestLayout();

               if ((mWindowAttributes.inputFeatures

                        &WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {

                    mInputChannel = new InputChannel();//创建客户端的inputchanel

               }

               try {

                    mOrigWindowType =mWindowAttributes.type;

                   mAttachInfo.mRecomputeGlobalAttributes = true;

                    collectViewAttributes();

                    res = mWindowSession.addToDisplay(mWindow, mSeq,mWindowAttributes,

                           getHostVisibility(), mDisplay.getDisplayId(),

                           mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,

                            mAttachInfo.mOutsets,mInputChannel);//将客户端带入WMS,去创建对应的服务器端。

……

    }

/*

setView方法中如果Window的属性能接受输入,而且还没有创建InputChannel,则会新创建一个InputChannel对象。这个对象会通过mWindowSessionaddToDisplay方法传递到WindowManagerService中,最后再会调用WMSaddWindow方法,addWindow有下面这段代码:

*/

Step 2:

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

 

   public int addWindow(Session session, IWindow client, int seq,

           WindowManager.LayoutParams attrs, int viewVisibility, int displayId,

           Rect outContentInsets, Rect outStableInsets, Rect outOutsets,

           InputChannel outInputChannel) {

       int[] appOp = new int[1];

       int res = mPolicy.checkAddPermission(attrs, appOp);

       if (res != WindowManagerGlobal.ADD_OKAY) {

           return res;

       }

……

 

           if (outInputChannel != null &&(attrs.inputFeatures

                    &WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {

                /** M: [ALPS00044207] @{ */

try {

String name = win.makeInputChannelName();

InputChannel[] inputChannels =InputChannel.openInputChannelPair(name);//创建channelPair

win.setInputChannel(inputChannels[0]);// channelPair inputChannels[0]给到win.mInputChannel,让下面去继续注册。

inputChannels[1].transferTo(outInputChannel);//参数传进来的client端填充到channelPair inputChannels[1]中去。

 

mInputManager.registerInputChannel(win.mInputChannel,win.mInputWindowHandle);//继续去注册

 

}

 ……

}

/*

addWIndow方法中先调用了InputChannelopenInputChannelPair来返回一个InputChannel对象的数组channelPairinputChannels[0]为其创建的server 端,inputChannels[1]则为client端。然后将inputChannel[0]设置到win中去。接着inputChannel[1]转换成和客户端传递过来的outInputChannel对象,最后调用了InputManagerService中的registerInputChannel方法。

*/

 

SETP3:

frameworks\base\services\core\java\com\android\server\input\ InputManagerService.java

 

    public voidregisterInputChannel(InputChannel inputChannel,

            InputWindowHandleinputWindowHandle) {

        if (inputChannel == null) {

            throw newIllegalArgumentException("inputChannel must not be null.");

        }

 

        nativeRegisterInputChannel(mPtr, inputChannel,inputWindowHandle, false);

    }

 

          STEP4:

\frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp

 

static voidnativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,

       jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj,jboolean monitor) {

   NativeInputManager* im =reinterpret_cast(ptr);

 

   sp inputChannel =android_view_InputChannel_getInputChannel(env,

            inputChannelObj);

   if (inputChannel == NULL) {

       throwInputChannelNotInitialized(env);

       return;

   }

 

   sp inputWindowHandle =

           android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

 

   status_t status = im->registerInputChannel(

            env, inputChannel,inputWindowHandle, monitor);

   if (status) {

       String8 message;

       message.appendFormat("Failed to register input channel.  status=%d", status);

       jniThrowRuntimeException(env, message.string());

       return;

   }

 

   if (! monitor) {

       android_view_InputChannel_setDisposeCallback(env, inputChannelObj,

                handleInputChannelDisposed,im);

   }

}

 

STEP 5:

status_tNativeInputManager::registerInputChannel(JNIEnv* /* env */,

       const sp& inputChannel,

       const sp& inputWindowHandle, bool monitor){

   return mInputManager->getDispatcher()->registerInputChannel(

            inputChannel, inputWindowHandle,monitor);

 

}

 

STEP 6:

frameworks\native\services\inputflinger\ InputDispatcher.cpp

status_t InputDispatcher::registerInputChannel(constsp& inputChannel,

       const sp& inputWindowHandle, bool monitor){

#if DEBUG_REGISTRATION

   ALOGD("channel '%s' ~ registerInputChannel - monitor=%s",inputChannel->getName().string(),

            toString(monitor));

#endif

 

   { // acquire lock

       AutoMutex _l(mLock);

 

       if (getConnectionIndexLocked(inputChannel) >= 0) {

            ALOGW("Attempted to registeralready registered input channel '%s'",

                    inputChannel->getName().string());

            return BAD_VALUE;

       }

 

       sp connection = new Connection(inputChannel, inputWindowHandle, monitor);//inputChannel封装到Connection里面去。startDispatchCycleLocked中派发消息的时候就将inputChannel取出来,然后再派发。

 

       int fd = inputChannel->getFd();

       mConnectionsByFd.add(fd, connection);

 

       if (monitor) {

           mMonitoringChannels.push(inputChannel);

       }

 

       mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);

   } // release lock

 

   // Wake the looper because some connections have changed.

   mLooper->wake();

   return OK;

}

/*

这里的inputChannel 就是publishKeyEvent中的mChannel。但是这个是怎么对应起来的,我现在还没有搞清楚。

所以mChannel->sendMessage(&msg) 实际上就是向ViewRootImpl中的InputChannel客户端发送消息。

到这里,消息就发送到ViewRootImpl里面去了。后面的处理再分析吧。

*/

 

你可能感兴趣的:(android,按键处理学习)