java 事件分发线程_Android输入事件从读取到分发三:InputDispatcherThread线程分发事件的过程...

分析完事件的读取后,东忙西忙,不知不觉已过去了快五个月了…也不是说没有时间把这部分源码分析完,而是实在是分析不下去,因此转战到其他地方去了。然而这一块始终是心头那不舍的惦记,经过一段时间的沉淀,又参考了网上很多大神的文章,然后再来阅读源码,渐渐感觉到能看出点眉目了。因而事不宜迟,赶紧做个记录吧(注:分析使用的Android源码版本为6.0)。

前面两篇文章分析输入事件的读取,通过分析,发现时间的读取是在EventHub类中实现的,EventHub类的getEevent方法中使用epoll_wait来监听驱动程序上报的事件,而在InputReaderThread的threadLoop方法中调用InputReader的loopOnce方法来不断的调用EventHub的getEvent方法来一直监听事件的到来,getEvent是一个阻塞的方法,当没有事件的时候,epoll_wait方法就会是线程休眠,有事件了就会唤醒线程。

从事件读取线程到事件分发线程的转移过程

既然有个InputReaderThread线程,那么有个InputDispatcherThread就不奇怪了,一个用来读取,一个用来分发,分工合作,相互配合,这样才能高效的完成事件的读取与分发。

我们先梳理下思路:

c2e96e6b688752489023efb0780d210b.png

从事件读取线程到事件分发线程的转移时序图:

6c1a03162ea753865fd5269afba9930e.png

从时序图中我们可以看到两个线程交互的过程。InputReaderThread会唤醒InputDispatcherThread来分发事件。

接下来,我们通过源码的追踪的方式,具体看看时序图中涉及的代码的具体实现。

跟着时序图,我们代码从InputReaderThread开始看起:

InputReaderThread::InputReaderThread(const sp& reader) :

Thread(/*canCallJava*/ true), mReader(reader) {

}

InputReaderThread::~InputReaderThread() {

}

bool InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

构造函数和析构函数都是空的,循环函数简单的就一句。mReader就是当前的InputReader对象,因此loopOnce如下:

void InputReader::loopOnce() {

int32_t oldGeneration;

int32_t timeoutMillis;

bool inputDevicesChanged = false;

Vector inputDevices;

{ // acquire lock

AutoMutex _l(mLock);

oldGeneration = mGeneration;

timeoutMillis = -1;

...

//获取事件

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

{ // acquire lock

AutoMutex _l(mLock);

mReaderIsAliveCondition.broadcast();

if (count) {

//处理事件

processEventsLocked(mEventBuffer, count);

}

...

if (oldGeneration != mGeneration) {

inputDevicesChanged = true;

getInputDevicesLocked(inputDevices);

}

} // release lock

// Send out a message that the describes the changed input devices.

if (inputDevicesChanged) {

mPolicy->notifyInputDevicesChanged(inputDevices);

}

...

mQueuedListener->flush();

}

只列出了比较重要的一些代码。这个函数作如下事情:

1.使用mEventHub->getEvents获取输入事件

2.使用processEventsLocked处理事件

getEvents方法之前也已经有介绍过,它就是使用epoll来监听驱动程序上报的事件的。所以我们从processEventsLocked方法看起:

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

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

int32_t type = rawEvent->type;

size_t batchSize = 1;

if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {

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 {

switch (rawEvent->type) {

case EventHubInterface::DEVICE_ADDED:

addDeviceLocked(rawEvent->when, rawEvent->deviceId);

break;

case EventHubInterface::DEVICE_REMOVED:

removeDeviceLocked(rawEvent->when, rawEvent->deviceId);

break;

case EventHubInterface::FINISHED_DEVICE_SCAN:

handleConfigurationChangedLocked(rawEvent->when);

break;

default:

ALOG_ASSERT(false); // can't happen

break;

}

}

count -= batchSize;

rawEvent += batchSize;

}

}

这个方法会对事件类型进行判断。我们假定用户按了一下返回按键,所以输入的是一个按键事件。而这个函数判断的时间类型的定义如下:

enum {

// Sent when a device is added.

DEVICE_ADDED = 0x10000000,

// Sent when a device is removed.

DEVICE_REMOVED = 0x20000000,

// Sent when all added/removed devices from the most recent scan have been reported.

// This event is always sent at least once.

FINISHED_DEVICE_SCAN = 0x30000000,

FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,

};

调用device->process因一部处理,device是InputDevice的实例,因此看看InputDevice下的process方法:

void InputDevice::process(const RawEvent* 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 because mappers may

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

// gamepad button presses are handled by different mappers but they should 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%08x when=%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 buffer overrun.");

#endif

} else {

#if DEBUG_RAW_EVENTS

ALOGD("Dropped input event while 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);

}

}

}

}

为了更好的理解这段代码,我们列出事件类型的定义:

/* Events */

#define EV_SYN          0x00

#define EV_KEY          0x01

#define EV_REL          0x02

#define EV_ABS          0x03

#define EV_MSC          0x04

#define EV_LED          0x11

#define EV_SND          0x12

#define EV_REP          0x14

#define EV_FF           0x15

#define EV_PWR          0x16

#define EV_FF_STATUS        0x17

#define EV_MAX          0x1f

因此我们的按键时间应该是0x01,所以这段代码执行的下面这个for循环:

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

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

for循环遍历mMappers数组,分别调用每一个mapper的process方法。这个数组包含了所有的输入事件的类型。我们按下的按键,因此会调用按键类型的Mapper来处理。如果想搞清楚这一块,可以看下mMappers数组的构造过程,在createDeviceLocked方法中实现,

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,

const InputDeviceIdentifier& identifier, uint32_t classes) {

InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),

controllerNumber, identifier, classes);

// External devices.

if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {

device->setExternal(true);

}

// Devices with mics.

if (classes & INPUT_DEVICE_CLASS_MIC) {

device->setMic(true);

}

// Switch-like devices.

if (classes & INPUT_DEVICE_CLASS_SWITCH) {

device->addMapper(new SwitchInputMapper(device));

}

// Vibrator-like devices.

if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {

device->addMapper(new VibratorInputMapper(device));

}

// Keyboard-like devices.

uint32_t keyboardSource = 0;

int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;

if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {

keyboardSource |= AINPUT_SOURCE_KEYBOARD;

}

if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {

keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;

}

if (classes & INPUT_DEVICE_CLASS_DPAD) {

keyboardSource |= AINPUT_SOURCE_DPAD;

}

if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {

keyboardSource |= AINPUT_SOURCE_GAMEPAD;

}

if (keyboardSource != 0) {

device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));

}

// Cursor-like devices.

if (classes & INPUT_DEVICE_CLASS_CURSOR) {

device->addMapper(new CursorInputMapper(device));

}

// Touchscreens and touchpad devices.

if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {

device->addMapper(new MultiTouchInputMapper(device));

} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {

device->addMapper(new SingleTouchInputMapper(device));

}

// Joystick-like devices.

if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {

device->addMapper(new JoystickInputMapper(device));

}

// External stylus-like devices.

if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {

device->addMapper(new ExternalStylusInputMapper(device));

}

return device;

}

因为我们事件是按键事件,所以,其他的mapper的process什么都不做,最终是KeyboardInputMapper的process方法。

void KeyboardInputMapper::process(const RawEvent* 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)) {

keyCode = AKEYCODE_UNKNOWN;

flags = 0;

}

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

}

break;

}

case EV_MSC: {

if (rawEvent->code == MSC_SCAN) {

mCurrentHidUsage = rawEvent->value;

}

break;

}

case EV_SYN: {

if (rawEvent->code == SYN_REPORT) {

mCurrentHidUsage = 0;

}

}

}

}

传入的事件类型为按键事件,因此会调用processKey方法进一步处理:

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,

int32_t scanCode, uint32_t policyFlags) {

if (down) {

// Rotate key codes according to orientation if needed.

if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {

keyCode = rotateKeyCode(keyCode, mOrientation);

}

// Add key down.

ssize_t keyDownIndex = findKeyDown(scanCode);

if (keyDownIndex >= 0) {

// key repeat, be sure to use same keycode as before in case of rotation

keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;

} else {

// key down

if ((policyFlags & POLICY_FLAG_VIRTUAL)

&& mContext->shouldDropVirtualKey(when,

getDevice(), keyCode, scanCode)) {

return;

}

if (policyFlags & POLICY_FLAG_GESTURE) {

mDevice->cancelTouch(when);

}

mKeyDowns.push();

KeyDown& keyDown = mKeyDowns.editTop();

keyDown.keyCode = keyCode;

keyDown.scanCode = scanCode;

}

mDownTime = when;

} else {

// Remove key down.

ssize_t keyDownIndex = findKeyDown(scanCode);

if (keyDownIndex >= 0) {

// key up, be sure to use same keycode as before in case of rotation

keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;

mKeyDowns.removeAt(size_t(keyDownIndex));

} else {

// key was not actually down

ALOGI("Dropping key up from device %s because the key was not down.  "

"keyCode=%d, scanCode=%d",

getDeviceName().string(), keyCode, scanCode);

return;

}

}

int32_t oldMetaState = mMetaState;

int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);

bool metaStateChanged = oldMetaState != newMetaState;

if (metaStateChanged) {

mMetaState = newMetaState;

updateLedState(false);

}

nsecs_t downTime = mDownTime;

// Key down on external an keyboard should wake the device.

// We don't do this for internal keyboards to prevent them from waking up in your pocket.

// For internal keyboards, the key layout file should specify the policy flags for

// each wake key individually.

// TODO: Use the input device configuration to control this behavior more finely.

if (down && getDevice()->isExternal()) {

// MStar Android Patch Begin

#ifdef ENABLE_STR

char value[PROPERTY_VALUE_MAX];

property_get("mstar.str.suspending", value, "0");

if (atoi(value) == 0) {

policyFlags |= POLICY_FLAG_WAKE;

}

#else

policyFlags |= POLICY_FLAG_WAKE;

#endif

// MStar Android Patch End

}

if (mParameters.handlesKeyRepeat) {

policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;

}

if (metaStateChanged) {

getContext()->updateGlobalMetaState();

}

if (down && !isMetaKey(keyCode)) {

getContext()->fadePointer();

}

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

}

由于能力有限,我无法关注太多的细节,这个方法的最后调用了 getListener()->notifyKey(&args);其实就是调用了InputDispatcher的notifyKey方法。为什么这么说呢?这个方法展开看一下就明白了。

InputListenerInterface* InputReader::ContextImpl::getListener() {

return mReader->mQueuedListener.get();

}

InpurReader的构造函数中创建了mQueuedListener变量。

InputReader::InputReader(const sp& eventHub,

const sp& policy,

const sp& listener) :

mContext(this), mEventHub(eventHub), mPolicy(policy),

mGlobalMetaState(0), mGeneration(1),

mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),

mConfigurationChangesToRefresh(0) {

mQueuedListener = new QueuedInputListener(listener);

{ // acquire lock

AutoMutex _l(mLock);

refreshConfigurationLocked(0);

updateGlobalMetaStateLocked();

} // release lock

}

QueuedInputListener构造函数中传入了一个listener,这个listener是不是InputDispatcher呢?

我们之前就分析过,InputReader是在InputManager中创建的,看看InputManager得构造函数:

InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

initialize();

}

真相大白了,listener就是mDispatcher。mDispatcher是InputDispatcher的实例。

因此,下一步就进入到了InputDispatcher的notifyKey方法了:

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, check to see if the key

// going up is one we've replaced in a down event and haven't yet replaced 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);

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.把时间封装成了KeyEvent类型的对象。

2.拦截事件。有些事件是必须要拦截的,这类事件不需要发送到window中去,比如关机键,需要系统来处理。拦截的主要代码:

mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

1

这部分也很重要,但是我们暂不展开,先知道这里拦截了事件,因为这里的拦截最终会调用PhoneWindowManager的interceptKeyBeforeQueueing等方法,解开了我PhoneWindowManager中相关方法什么时候调用的不清楚的迷惑。我们先放一放,之后在展开。

3.唤醒InputDispatcherThread线程:

mLooper->wake();

1

这个线程唤醒意味着事件的分发终于转入到InputDispatcherThread了,InputReaderThread线程完成了它的使命。为什么这行代码能唤醒InputDispatcherThread呢?这还的从InputDispatcherThread说起:

InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) :

Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {

}

InputDispatcherThread::~InputDispatcherThread() {

}

bool InputDispatcherThread::threadLoop() {

mDispatcher->dispatchOnce();

return true;

}

这个线程和InputReaderThread线程类似,调用InputDispatcher的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);

}

可以看到它内部使用Looper,调用mLooper->pollOnce(timeoutMillis)后,如果没有数据可以读取,会导致线程休眠,调用mLooper->wake可以唤醒它,唤醒后dispatchOnceInnerLocked来分发事件。至此,我们绘制的事件读取线程到事件分发线程的转移时序图就走到了尽头。下一部分到底是怎么把分发到window的呢?于是我们进入到了事件发送的第二个阶段。

InputDispatcherThread中的事件发送

我们先看一下这个阶段的时序图:

396bd0dd81cd7ab81f22da67c7427c7f.png

事件的发送和接收一定是你情我愿的事情,强求不来的。但是,我们目前已知在分析事件的发送,没有关注事件的接收端,因此,真正的发送流程中有很多东西理解不来,不过没关系,我们先理清发送的流程,等我们理解了事件的接收端以后,再反过头来看这部分就豁然开朗了。因此,这之后的代码我们主要是追踪事件发送的流程,而不苛求一定要理解透彻这部分代码。

我们从上一个时序图结束的位置开始追踪吧,dispatchOnceInnerLocked函数定义如下:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

nsecs_t currentTime = now();

// Reset the key repeat timer whenever normal dispatch is suspended while 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 deliver any 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 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_CONFIGURATION_CHANGED: {

ConfigurationChangedEntry* typedEntry =

static_cast(mPendingEvent);

done = dispatchConfigurationChangedLocked(currentTime, typedEntry);

dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped

break;

}

case EventEntry::TYPE_DEVICE_RESET: {

DeviceResetEntry* typedEntry =

static_cast(mPendingEvent);

done = dispatchDeviceResetLocked(currentTime, typedEntry);

dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped

break;

}

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;

}

case EventEntry::TYPE_MOTION: {

MotionEntry* typedEntry = static_cast(mPendingEvent);

if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {

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 = dispatchMotionLocked(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

}

}

我们的时间类型为TYPE_KEY,所以会调用到dispatchKeyLocked方法:

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

DropReason* dropReason, nsecs_t* nextWakeupTime) {

// Preprocessing.

...

// Dispatch the key.

dispatchEventLocked(currentTime, entry, inputTargets);

return true;

}

省略了很多类容。我的目的是理清框架,所以想理解细节的就请绕道吧。再看看dispatchEventLocked方法的实现:

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,

EventEntry* eventEntry, const Vector& inputTargets) {

#if DEBUG_DISPATCH_CYCLE

ALOGD("dispatchEventToCurrentInputTargets");

#endif

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

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 = mConnectionsByFd.valueAt(connectionIndex);

prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);

} else {

#if DEBUG_FOCUS

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

"is no longer registered with the input dispatcher.",

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

#endif

}

}

}

调用prepareDispatchCycleLocked方法进一步处理:

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

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

...

// Skip this event if the connection status is not normal.

// We don't want to enqueue additional outbound events if the connection is broken.

if (connection->status != Connection::STATUS_NORMAL) {

return;

}

// 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 was dropped

}

#if DEBUG_FOCUS

ALOGD("channel '%s' ~ Split motion event.",

connection->getInputChannelName());

logOutboundMotionDetailsLocked("  ", splitMotionEntry);

#endif

enqueueDispatchEntriesLocked(currentTime, connection,

splitMotionEntry, inputTarget);

splitMotionEntry->release();

return;

}

}

这个函数检查connect状态是不是正常,什么连接状态?

又调用到enqueueDispatchEntriesLocked方法了:

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 cycle going.

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

startDispatchCycleLocked(currentTime, connection);

}

}

舍繁求简抓骨干,继续追踪,代码进入到startDispatchCycleLocked

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

const sp& connection) {

#if DEBUG_DISPATCH_CYCLE

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

connection->getInputChannelName());

#endif

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

MotionEntry* motionEntry = static_cast(eventEntry);

PointerCoords scaledCoords[MAX_POINTERS];

const PointerCoords* usingCoords = motionEntry->pointerCoords;

// Set the X and Y offset depending on the input source.

float xOffset, yOffset, scaleFactor;

if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)

&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {

scaleFactor = dispatchEntry->scaleFactor;

xOffset = dispatchEntry->xOffset * scaleFactor;

yOffset = dispatchEntry->yOffset * scaleFactor;

if (scaleFactor != 1.0f) {

for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {

scaledCoords[i] = motionEntry->pointerCoords[i];

scaledCoords[i].scale(scaleFactor);

}

usingCoords = scaledCoords;

}

} else {

xOffset = 0.0f;

yOffset = 0.0f;

scaleFactor = 1.0f;

// We don't want the dispatch target to know.

if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {

for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {

scaledCoords[i].clear();

}

usingCoords = scaledCoords;

}

}

// Publish the motion event.

status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,

motionEntry->deviceId, motionEntry->source,

dispatchEntry->resolvedAction, motionEntry->actionButton,

dispatchEntry->resolvedFlags, motionEntry->edgeFlags,

motionEntry->metaState, motionEntry->buttonState,

xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,

motionEntry->downTime, motionEntry->eventTime,

motionEntry->pointerCount, motionEntry->pointerProperties,

usingCoords);

break;

}

default:

ALOG_ASSERT(false);

return;

}

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

}

}

只关注我们的TYPE_KEY类型的事件:

connection->inputPublisher.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) {

#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 number 0.");

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

}

继续追踪代码流程:调用到了InputChannel的sendMessage方法了。

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

if (nWrite < 0) {

int error = errno;

#if DEBUG_CHANNEL_MESSAGES

ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),

msg->header.type, error);

#endif

if (error == EAGAIN || error == EWOULDBLOCK) {

return WOULD_BLOCK;

}

if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {

return DEAD_OBJECT;

}

return -error;

}

if (size_t(nWrite) != msgLength) {

#if DEBUG_CHANNEL_MESSAGES

ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",

mName.string(), msg->header.type);

#endif

return DEAD_OBJECT;

}

#if DEBUG_CHANNEL_MESSAGES

ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);

#endif

return OK;

}

这个方法中,重点是下面这行代码:

::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);

1

InputChannel的本质是linux本地套接字。linux本地套接字可以用于进程间通信,InputChannel的openInputChannelPair方法中使用了socketpair函数创建了Linux本地套接字,socketpair会返回两个文件描述符,持有这两个文件描述符的进程就可以进行进程间的通信。

status_t InputChannel::openInputChannelPair(const String8& name,

sp& outServerChannel, sp& outClientChannel) {

int sockets[2];

if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {

status_t result = -errno;

ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",

name.string(), errno);

outServerChannel.clear();

outClientChannel.clear();

return result;

}

int bufferSize = SOCKET_BUFFER_SIZE;

setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));

setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));

setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

String8 serverChannelName = name;

serverChannelName.append(" (server)");

outServerChannel = new InputChannel(serverChannelName, sockets[0]);

String8 clientChannelName = name;

clientChannelName.append(" (client)");

outClientChannel = new InputChannel(clientChannelName, sockets[1]);

return OK;

}

这个方法的最后创建了两个InputChannel,分别传入一个文件描述符。因此持有这两个InputChannel实例的进程就可以做进程间的通信。

当我们调用到InputChannel的sendMessage方法时,其实已经是在和另一端通信了,另一端收到的消息就是我们的按键事件了。我们消息分发到此就到了尽头,另一端到底是谁在接收?我们需要另做分析,我不太喜欢写特别长的博客,读起来太费劲,因此,预知是谁在接收事件,请见下回分解。

---------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值