1. 前言

Android中管理Input的两个主要相关角色, 一是WindowManagerService, 一是跟View相关的ViewRootImpl. 基本原理方向从2.3到目前的4.2都一样,在 Android app一启动之后, ViewRootImpl 就会先跟 WindowManagerService 建立inputChannel, 一旦 WindowManagerService 有收到 event 就会经由 inputChannel 通知 ViewRootImpl 去共享内存中抓取 event. 虽然方向一样, 但是里面的架构有改,目前最新的版本是android 4.2, 所以以下的输入事件处理程序是以4.2来说明, 以后的版本一定会再更改.到时候在研究.

2. 事件处理程序

2.1 建立 InputChannel

Android Activity 一启动时会先利用 setContentView 来设置画面, 最后会由 ViewRootImpl 中的 setView函数来做画面的设置, setContentView 跟 setView 有甚么关系, 并不是这里的重点. 那是属于Surface 的范围. 接下来就来看 setView 函数的实作, 跟输入流程无关的程序代码就略掉.

//ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

synchronized (this) {

// do something

mInputChannel = new InputChannel();

// do something

res =mWindowSession.addToDisplay(mWindow, mSeq,

mWindowAttributes,

getHostVisibility(), mDisplay.getDisplayId(),

mAttachInfo.mContentInsets,mInputChannel);

//do something

}

}

由此可知, new出来的 InputChannel 对象会传入 mWindowSession 的 addToDisplay 函数中, 去查了一下 mWindowSession 是由 IWindowSession 宣告, 一般 Ixxxx 的数据型态都是一个 Binder的接口, 通常功能实作都是会定义在由 Ixxxx 衍生的类别, 搜寻了一下程序代码, Session 继承 IWindowSession , 因此 addToDisplay 函数必在 Session 类别实作.

// Session.java

@Override

public int addToDisplay(IWindow window, int seq,

WindowManager.LayoutParams attrs,

int viewVisibility, int displayId, Rect outContentInsets,

InputChannel outInputChannel) {

returnmService.addWindow(this, window, seq, attrs,

viewVisibility, displayId,

outContentInsets, outInputChannel);

}

InputChannel对象 继续传入 WindowManagerService (mService 的数据型态是 WindowManagerService ) 的 addWindow 函数.

// WindowManagerService.java

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

WindowManager.LayoutParams attrs, int viewVisibility,

int displayId,

Rect outContentInsets, InputChannel outInputChannel) {

//do something

String name = win.makeInputChannelName();

InputChannel[] inputChannels =

InputChannel.openInputChannelPair(name);

win.setInputChannel(inputChannels[0]);

inputChannels[1].transferTo(outInputChannel);

mInputManager.registerInputChannel(win.mInputChannel,

win.mInputWindowHandle);

//do something

}

之后就是利用 InputManagerService 的 registerInputChannel 函数将 WindowManagerService 和 ViewRootImpl 之间的 InputChannel 建立起来. 一旦之间的通道建立起来, WindowManagerService 和 ViewRootImpl 之间就可以做输入event的流程沟通. WindowManagerService -> ViewRootImpl,这个方向是 WindowManagerService 通知 ViewRootImpl 去共享内存去取input event. ViewRootImpl -> WindowManagerService,这个方向是 ViewRootImpl 通知 WindowManagerService 已经处理完共享内存的 input event了, 请 WindowManagerService 在检查是否有新的 input event, 若有的话就放入共享内存. 以下就来介绍 input event 流程.

2.2 输入事件处理流程:

一开机的时候, SystemServer 会启动 InputManagerService, 这时 InputManagerService 又会去启动两个Thread,InputReaderThread,InputDispatcherThread和一个EventHubInterface. 因此输入事件处理流程跟此三位角色有关系.InputReaderThreadEventHubInterface抓取新的inputevent, 然后在依各个的eventtype 进入各个的 eventmapper, 各个的 event mapper 处理输入事件完之后,InputReaderThread将new input 放进 Queue 中. 之后InputDispatcherThread再从Queue中取出Input Event 放入共享内存中. 此时再通知 View 去共享内存抓取 new Input Event, 取完之后再通知InputDispatcherThread是否可以再放新的InputEvent到共享内存中, 流程如下

首先先由InputReaderThread启动开始, 在android启动 thread 是以下的形式.

// InputManager.cpp

mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

这时候InputReaderThread的 threadLoop 函数就会被触发.

// InputReader.cpp

bool InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

void InputReader::loopOnce() {

//do something

// 从 /dev/input下获得新的Input event

mEventHub->getEvents(timeoutMillis, mEventBuffer,

EVENT_BUFFER_SIZE);

//依各个的event type 进入各个的 event mapper

processEventsLocked(mEventBuffer, count);

//通知InputDispatcherThread去处理new input.

mQueuedListener->flush();

//do something

}

在loopOnce 函式中作了三件事

1. getEvents,

2. processEventsLocked,

3. flush.

在这篇关心的是输入事件处理流程, 所以就先来看从 EventHub 得到的 input event, InputReader 是如何借着 processEventsLocked 去做处理.

//InputReader.cpp

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

//do something

int32_t deviceId = rawEvent->deviceId;

//do something

processEventsForDeviceLocked(deviceId, rawEvent, batchSize);

//do something

}

void InputReader::processEventsForDeviceLocked(int32_t deviceId,

const RawEvent* rawEvents, size_t count) {

//do something

InputDevice* device = mDevices.valueAt(deviceIndex);

if (device->isIgnored()) {

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

return;

}

device->process(rawEvents, count);

}

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

//do something

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

//do something

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

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

//do something

}

//do something

}

由此可知,InputReader 会利用一个mapper来管理所收到的 input event, 这些mapper 有

1. SwitchInputMapper,

2. VibratorInputMapper,

3. KeyboardInputMapper,

4. CursorInputMapper,

5. TouchInputMapper,

6. SingleTouchInputMapper,

7. MultiTouchInputMapper,

8.JoystickInputMapper等等.

由于这些mapper处理的架构都差不多, 就拿TouchInputMapper来作分析

//InputReader.cpp

void TouchInputMapper::process(const RawEvent* rawEvent) {

// 处理以下的输入事件, 并将各个的Touch value作相对应处理

mCursorButtonAccumulator.process(rawEvent);

mCursorScrollAccumulator.process(rawEvent);

mTouchButtonAccumulator.process(rawEvent);

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

sync(rawEvent->when);

}

}

void TouchInputMapper::sync(nsecs_t when) {

//do something

dispatchTouches(when, policyFlags);

//do something

}

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {

//do something

// No pointer id changes so this is a move event.

// The listener takes care of batching moves so we don't have to deal with

// that here.

dispatchMotion(when, policyFlags, mSource,

AMOTION_EVENT_ACTION_MOVE, 0, metaState,

buttonState,

AMOTION_EVENT_EDGE_FLAG_NONE,

mCurrentCookedPointerData.pointerProperties,

mCurrentCookedPointerData.pointerCoords,

mCurrentCookedPointerData.idToIndex,

currentIdBits, -1,

mOrientedXPrecision, mOrientedYPrecision,

mDownTime);

//do something

}

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags,

uint32_t source,

int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,

int32_t edgeFlags,

const PointerProperties* properties, const PointerCoords* coords,

const uint32_t* idToIndex, BitSet32 idBits,

int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {

//do something

NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,

action, flags, metaState, buttonState, edgeFlags,

mViewport.displayId, pointerCount, pointerProperties,

pointerCoords,

xPrecision, yPrecision, downTime);

getListener()->notifyMotion(&args);

}

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

return mReader->mQueuedListener.get();

}

最后会发现会将所收到的Touchmotion 信息打包成message,然后利用 QueuedInputListener 将 message 推入 mArgsQueue 向量里.

// InputListener.h

Vector<NotifyArgs*> mArgsQueue;

// InputListener.cpp

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

mArgsQueue.push(new NotifyMotionArgs(*args));

}

InputReader处理完有关 TouchMotion input event之后, 便会把新的 Touch Motion input event 放进InboundQueue 流程如下:

//InputReader.cpp

mQueuedListener->flush();

//InputListener.cpp

void QueuedInputListener::flush() {

size_t count = mArgsQueue.size();

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

NotifyArgs* args = mArgsQueue[i];

args->notify(mInnerListener);

delete args;

}

mArgsQueue.clear();

}

在此会发现会用个loop来呼叫mArgsQueuevector中的 notify 函数, 继续看下去

//InputListener.cpp

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {

listener->notifyMotion(this);

}

在此发现notifyMotion函数是由 InputListenerInterface 类别的对象所带出来的, 由字符串来看此类别只是当作是一个界面, 所以实作必定是其类别衍生的类别. 搜寻了一下整个程序代码, 发现 InputDispatcherInterface 继承InputListenerInterface,

而 InputDispatcher 继承 InputDispatcherInterface类别, 所以notifyMotion函数必定实作在这类别中

// InputDispatcher.cpp

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {

//do something

// Policy:

// - Ignore untrusted events and pass them along.

// - No special filtering for injected events required at this time.

// - Filter normal events based on screen state.

// - For normal events brighten (but do not wake) the screen if currently dim.

mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/

policyFlags);

bool needWake;

{ // acquire lock

mLock.lock();

if (shouldSendMotionToInputFilterLocked(args)) {

mLock.unlock();

//initialize motion event for secondary display

mLock.lock();

}

// Just enqueue a new motion event.

MotionEntry* newEntry = new MotionEntry(args->eventTime,

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

args->action, args->flags, args->metaState, args->buttonState,

args->edgeFlags, args->xPrecision, args->yPrecision,

args->downTime,

args->displayId,

args->pointerCount, args->pointerProperties,

args->pointerCoords);

needWake = enqueueInboundEventLocked(newEntry);

mLock.unlock();

} // release lock

if (needWake) {

mLooper->wake();

}

}

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

//将新的input event放进InboundQueue

bool needWake = mInboundQueue.isEmpty();

mInboundQueue.enqueueAtTail(entry);

// do something

return needWake;

}

到此为止,InputReader Thread 已经把新的Touch motion event放进InboundQueue了. 接下来就来看InputDispatcher Thread 的输入事件流程.

同样的从InputDispatcherThread的启动流程开始分析

// InputDispatcher.cpp

bool InputDispatcherThread::threadLoop() {

mDispatcher->dispatchOnce();

return true;

}

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); // 用来管理message queue, 负责接收

// 或发送 message.

}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

//do something

// Ready to start a new event.

// If we don't already have a pending event, go grab one.

if (! mPendingEvent) {

if (mInboundQueue.isEmpty()) {

//do something

} else {

// Inbound queue has at least one entry.

mPendingEvent = mInboundQueue.dequeueAtHead();

}

//do something

// Get ready to dispatch the event.

resetANRTimeoutsLocked(); //因为已经取到input event, 所以 reset

//ANR timer.

}

//do something

switch (mPendingEvent->type) {

case EventEntry::TYPE_CONFIGURATION_CHANGED:

//do something

break;

case EventEntry::TYPE_DEVICE_RESET:

//do something

break;

case EventEntry::TYPE_KEY:

//do something

break;

case EventEntry::TYPE_MOTION:

MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);

//do something

done = dispatchMotionLocked(currentTime, typedEntry,

&dropReason, nextWakeupTime);

break;

default:

break;

}

if (done) {

if (dropReason != DROP_REASON_NOT_DROPPED) {

dropInboundEventLocked(mPendingEvent, dropReason);

}

releasePendingEventLocked();

*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up

// immediately

}

}

bool InputDispatcher::dispatchMotionLocked(

nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason,

nsecs_t* nextWakeupTime) {

1. // Preprocessing.

2. // Clean up if dropping the event.

3. // support sending secondary display events to input monitors

// Dispatch the motion.

// do soemthing

dispatchEventLocked(currentTime, entry, inputTargets);

}

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,

EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {

//do something

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 {

//do something

}

}

}

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

const sp<Connection>& connection, EventEntry* eventEntry, const

InputTarget* inputTarget) {

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

// We don't want to enqueue additional outbound events if the

// connection is broken.

// Split a motion event if needed.

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

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

//do something

enqueueDispatchEntriesLocked(currentTime, connection,

splitMotionEntry, inputTarget);

//do something

return;

}

}

// Not splitting. Enqueue dispatch entries for the event as is.

enqueueDispatchEntriesLocked(currentTime, connection, eventEntry,

inputTarget);

}

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,

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

bool wasEmpty = connection->outboundQueue.isEmpty();

// Enqueue dispatch entries for the requested modes.

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_OUTSIDE);

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_IS);

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);

enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

// If the outbound queue was previously empty, start the dispatch cycle going.

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

startDispatchCycleLocked(currentTime, connection);

}

}

void InputDispatcher::enqueueDispatchEntryLocked(

const sp<Connection>& connection, EventEntry* eventEntry, const

InputTarget* inputTarget,

int32_t dispatchMode) {

//do something

// This is a new event.

// Enqueue a new dispatch entry onto the outbound queue for this

// connection.

DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry,

inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,

inputTarget->scaleFactor);

// Apply target flags and update the connection's input state.

// Remember that we are waiting for this dispatch to complete.

// Enqueue the dispatch entry.

connection->outboundQueue.enqueueAtTail(dispatchEntry);

}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

const sp<Connection>& connection) {

// do something

// 检查outboundQueue 中是否有新的 input event.

while (connection->status == Connection::STATUS_NORMAL

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

// 从 outboundQueue 中取出新的 input event.

DispatchEntry* dispatchEntry = connection->outboundQueue.head;

// Publish the event.

EventEntry* eventEntry = dispatchEntry->eventEntry;

switch (eventEntry->type) {

case EventEntry::TYPE_KEY:

//do something

break;

case EventEntry::TYPE_MOTION:

//do something

// Publish the motion event.

status =

connection->inputPublisher.publishMotionEvent(

// some argument.

);

break;

default:

return;

}

}

}

//InputTransport.cpp

status_t InputPublisher::publishMotionEvent(

uint32_t seq,

int32_t deviceId,

int32_t source,

int32_t action,

int32_t flags,

int32_t edgeFlags,

int32_t metaState,

int32_t buttonState,

float xOffset,

float yOffset,

float xPrecision,

float yPrecision,

nsecs_t downTime,

nsecs_t eventTime,

size_t pointerCount,

const PointerProperties* pointerProperties,

const PointerCoords* pointerCoords) {

InputMessage msg;

msg.header.type = InputMessage::TYPE_MOTION;

msg.body.motion.seq = seq;

msg.body.motion.deviceId = deviceId;

msg.body.motion.source = source;

msg.body.motion.action = action;

msg.body.motion.flags = flags;

msg.body.motion.edgeFlags = edgeFlags;

msg.body.motion.metaState = metaState;

msg.body.motion.buttonState = buttonState;

msg.body.motion.xOffset = xOffset;

msg.body.motion.yOffset = yOffset;

msg.body.motion.xPrecision = xPrecision;

msg.body.motion.yPrecision = yPrecision;

msg.body.motion.downTime = downTime;

msg.body.motion.eventTime = eventTime;

msg.body.motion.pointerCount = pointerCount;

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

msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);

msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);

}

returnmChannel->sendMessage(&msg);

}

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 (error == EAGAIN || error == EWOULDBLOCK) {

return WOULD_BLOCK;

}

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

return DEAD_OBJECT;

}

return -error;

}

if (size_t(nWrite) != msgLength) {

return DEAD_OBJECT;

}

return OK;

}

上面呼叫了哪么多层函数, InputDispatcherThread 就只做了以下几件事:

1. 从InboundQueue取 newinput event 处理, 处理完放进OutboundQueue

2. 从OutboundQueue 取 new input event 处理, 处理完放进 inputMessage.

3. 利用::send函数送 inputMessage.

世上万物常是一体两面, 在程序设计上也是如此, 因此有了sendMessage函数设计, 必有一个receiveMessage的函数. 所以有了 InputChannel::sendMessage 就会提供 InputChannel::receiveMessage 函数作接收message的处理. 搜寻了一下程序代码发现呼叫 InputChannel::receiveMessage 函数的地方是在InputConsumer::consume函数中. 而这consume函数又是在哪被呼叫呢? 此流程牵扯到Thread 通讯课题, 在这不做详细分析, 为了篇幅只能做简单的说明, 在android中每一个Process都有一个looper,此looper里有一个messageQueue,messageQueue中有很多来自此process中不同的thread所发出来的message.管理这些message 就是这个名为 looper 的对象. 因此就去搜寻一下跟looper 相关的程序代码, 发现android 有定义一个LooperCallback的抽象类, 此抽象类里有一个purevirtual functionhandleEvent函数, 因此只要找到谁继承LooperCallback类别, 就能找到handleEvent 函数实作的地方. 最后在 NativeInputEventReceiver 发现handleEvent 函数实作足迹.

// android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

//do something

status_t status = consumeEvents(env, false /*consumeBatches*/, -1);

// do something

}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

bool consumeBatches, nsecs_t frameTime) {

//do something

bool skipCallbacks = false; // 用来做为通知是否已完成dispach input event

// 的一个判断值.

for (;;) {

uint32_t seq;

InputEvent* inputEvent;

//果然在这里发现了呼叫 InputConsumer::consume 函数的地方

status_t status = mInputConsumer.consume(&mInputEventFactory,

consumeBatches, frameTime, &seq, &inputEvent);

//do something

if (!skipCallbacks) {

jobject inputEventObj;

switch (inputEvent->getType()) {

case AINPUT_EVENT_TYPE_KEY:

inputEventObj = android_view_KeyEvent_fromNative(env,

static_cast<KeyEvent*>(inputEvent));

break;

case AINPUT_EVENT_TYPE_MOTION:

inputEventObj =

android_view_MotionEvent_obtainAsCopy(env,

static_cast<MotionEvent*>(inputEvent));

break;

default:

assert(false); // InputConsumer should prevent this from ever

// happening

inputEventObj = NULL;

}

if (inputEventObj) {

env->CallVoidMethod(mReceiverObjGlobal,

gInputEventReceiverClassInfo.dispatchInputEvent,

seq, inputEventObj);

if (env->ExceptionCheck()) {

skipCallbacks = true;

}

} else {

skipCallbacks = true;

}

}

if (skipCallbacks) {

mInputConsumer.sendFinishedSignal(seq, false);

}

}

}

由这段程序代码可以发现, 当利用InputConsumer对象收到由 InputDispatcherThread 送过来的InputEvent message时, 便会利用一个boolean variable skipCallbacks 当作一个是否完成dispatch input event的判断值. 一收到inputevent马上分析为是 Key event type 还是 Motionevent type. 由于我们这里是以 Motion event type 为例, 所以就分析 Motionevent type 这个 case流程.

// android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

bool consumeBatches, nsecs_t frameTime) {

//do something

case AINPUT_EVENT_TYPE_MOTION:

inputEventObj =

android_view_MotionEvent_obtainAsCopy(env,

static_cast<MotionEvent*>(inputEvent));

break;

//do something

}

// android_view_MotionEvent.cpp

jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const

MotionEvent* event) {

//回呼MotionEvent Java Layer配置一块MotionEvent type

//物件.

jobject eventObj =

env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,

gMotionEventClassInfo.obtain);

// eventObj exception handler

//MotionEventjava layer读取MotionEvent对象指针值.

MotionEvent* destEvent =

android_view_MotionEvent_getNativePtr(env, eventObj);

if (!destEvent) {

destEvent = new MotionEvent();

android_view_MotionEvent_setNativePtr(env, eventObj,

destEvent);

}

destEvent->copyFrom(event, true);

return eventObj;

}

到此利用java layer来配置一块MotionEvent 对象来使用. 为何要这么大费周章还要去回呼Javalayer作配置对象的动作, 推论应该是要藉由DVM的 GC来做回收未用到的内存. 接下来继续分析后续动作

// android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

bool consumeBatches, nsecs_t frameTime) {

//do something

//do something

//将上面所得到的MotionEvent对象指针值,在传入Java Layer

//函数里

env->CallVoidMethod(mReceiverObjGlobal,

gInputEventReceiverClassInfo.dispatchInputEvent,

seq, inputEventObj);

//do something

}

//InputEventReceiver.java

// Called from native code.

@SuppressWarnings("unused")

private void dispatchInputEvent(int seq, InputEvent event) {

mSeqMap.put(event.getSequenceNumber(), seq);

onInputEvent(event);

}

/**

* Called when an input event is received.

* The recipient should process the input event and then call {@link

#finishInputEvent}

* to indicate whether the event was handled. No new input events will be

received

* until {@link #finishInputEvent} is called.

*

* @param event The input event that was received.

*/

public void onInputEvent(InputEvent event) {

finishInputEvent(event, false);

}

到这里先停一下, 若继续分析下去, 会发现似乎直接就呼叫 finishInputEvent 函数, 然后就送finishmessage 通知 InputDispatcherThread 之后, 就完成了这一个输入事件流程了. 然而, 依照过去写app的经验, 一般在app若要接收一些Touchevent 会有个 call back functiononTouch函数要实作, 方便app可以接收到Touchevent 然后作相关的应用. 然而刚刚分析的输入事件的流程似乎没有去呼叫onTouch函数, 这到底是怎么一回事? 原因在于 InputEventReceiver 这个类别, 这个类别是属于abstract类别, 在java的语法中, abstract类别即使类别中的成员函数都有实作, 也是无法实体化的, 因此只能有abstract类别的衍生类别才能实体化. 搜寻了一下程序代码发现了几个abstractInputEventReceiver类别的衍生类别, 跟InputEvent处理有关的衍生类别就是WindowInputEventReceiver, 原因如下, 再一开始ViewRootImpl在作 setView 时, 除了new 一个新的 InputChannel 对象之后, 又 new 了一个 WindowInputEventReceiver 对象. 此 WindowInputEventReceiver 类别正好又overwriteonInputEvent函数, 因此可以大胆推测dispatchInputEvent呼叫的 onInputEvent 函数, 会是此类别的 onInputEvent 函数, 就在从 WindowInputEventReceiver 中的 onInputEvent 函数开始分析.

// ViewRootImpl.java

//此类别是定义在ViewRootImpl类别中,最前面又是挂final,java的语法//中代表此类别只能给ViewRootImpl类别中使用且无法被继承.

final class WindowInputEventReceiver extends InputEventReceiver {

//data member

@Override

public void onInputEvent(InputEvent event) {

enqueueInputEvent(event, this, 0, true);

}

// member function

}

void enqueueInputEvent(InputEvent event,

InputEventReceiver receiver, int flags, boolean processImmediately) {

QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

// Always enqueue the input event in order, regardless of its time stamp.

// We do this because the application or the IME may inject key events

// in response to touch events and we want to ensure that the injected

// keys are processed in the order they were received and we cannot

// trust that the time stamp of injected events are monotonic.

QueuedInputEvent last = mFirstPendingInputEvent;

if (last == null) {

mFirstPendingInputEvent = q;

} else {

while (last.mNext != null) {

last = last.mNext;

}

last.mNext = q;

}

if (processImmediately) {

doProcessInputEvents(); //一般的input event都是即使的

} else {

scheduleProcessInputEvents();

}

}

void doProcessInputEvents() {

while (mCurrentInputEvent == null && mFirstPendingInputEvent != null)

{

QueuedInputEvent q = mFirstPendingInputEvent;

mFirstPendingInputEvent = q.mNext;

q.mNext = null;

mCurrentInputEvent = q;

deliverInputEvent(q);

}

// We are done processing all input events that we can process right now

// so we can clear the pending flag immediately.

}

private void deliverInputEvent(QueuedInputEvent q) {

// do something

if (q.mEvent instanceof KeyEvent) {

deliverKeyEvent(q);

} else {

final int source = q.mEvent.getSource();

if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0)

{

deliverPointerEvent(q);

} else if ((source &

InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {

deliverTrackballEvent(q);

} else {

deliverGenericMotionEvent(q);

}

}

// do something

}

private void deliverPointerEvent(QueuedInputEvent q) {

// If there is no view, then the event will not be handled.

if (mView == null || !mAdded) {

finishInputEvent(q, false);

return;

}

// Translate the pointer event for compatibility, if needed.

// Enter touch mode on down or scroll.

// Offset the scroll position.

// Remember the touch position for possible drag-initiation.

// Dispatch touch to view hierarchy.

boolean handled =mView.dispatchPointerEvent(event);

if (handled) {

finishInputEvent(q, true);

return;

}

// Pointer event was unhandled.

finishInputEvent(q, false);

}

由此可以发现只要检查到没有view或是无法掌握的inputevent就会被ignore掉不去处理.最后会去呼叫 View 类别的 dispatchTouchEvent 函数.

//View .java

public boolean dispatchTouchEvent(MotionEvent event) {

if (mInputEventConsistencyVerifier != null) {

mInputEventConsistencyVerifier.onTouchEvent(event, 0);

}

if (onFilterTouchEventForSecurity(event)) {

//noinspection SimplifiableIfStatement

ListenerInfo li = mListenerInfo;

if (li != null && li.mOnTouchListener != null && (mViewFlags &

ENABLED_MASK) == ENABLED

&&li.mOnTouchListener.onTouch(this, event)) {

return true;

}

// 主要是用来实作触控的一般通用的功能, ex press, click, long

// press etc.

if (onTouchEvent(event)) {

return true;

}

}

if (mInputEventConsistencyVerifier != null) {

mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);

}

return false;

}

终于发现呼叫onTouch函数的地方了. 在这里只要app有注册onTouchListener 接口,onTouch函数就会被触发了. 到目前为止分析的方向是WindowManagerService-> ViewRootImpl, 接下来 ViewRootImpl 处理完 inputevent 之后, 再来分析 ViewRootImpl -> WindowManagerService这方向. 由前面的 deliverPointerEvent 函数分析中, 会发现都会解由finishInputEvent来完成这一次的输入事件流程. 就由finishInputEvent函数开始分析

// ViewRootImpl.java

private void finishInputEvent(QueuedInputEvent q, boolean handled) {

//do something

if (q.mReceiver != null) {

q.mReceiver.finishInputEvent(q.mEvent, handled);

} else {

q.mEvent.recycleIfNeededAfterDispatch();

}

//do something

}

// InputEventReceiver.cpp

public final void finishInputEvent(InputEvent event, boolean handled) {

//do something

nativeFinishInputEvent(mReceiverPtr, seq, handled);

//do something

}

// android_view_InputEventReceiver.cpp

static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,

jint seq, jboolean handled) {

sp<NativeInputEventReceiver> receiver =

reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);

status_t status = receiver->finishInputEvent(seq, handled);

// exception handler

}

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {

// do something

status_t status = mInputConsumer.sendFinishedSignal(seq, handled);

// exception handler

}

// InputTransport.cpp

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {

// do something

// Send finished signal for the last message in the batch.

returnsendUnchainedFinishedSignal(seq, handled);

}

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {

InputMessage msg;

msg.header.type = InputMessage::TYPE_FINISHED;

msg.body.finished.seq = seq;

msg.body.finished.handled = handled;

returnmChannel->sendMessage(&msg);

}

一旦ViewRootImpl 藉由 InputChannel对象传送 finish的message 时, 这时

InputDispatcher类别的 handleReceiveCallback 函数就会被触发. 原因在于InputDispatcher在初始化的时候有去做register InputChannel 的动作, 在 register InputChannel时, 会在自己new 出来的 looper对象上增加一个 callback functionhandleReceiveCallback.

// InputDispatcher.cpp

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

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {

// do something

for (;;) {

// do something

status = connection->inputPublisher.receiveFinishedSignal(&seq,

&handled);

// do something

d->finishDispatchCycleLocked(currentTime, connection, seq,

handled);

gotOne = true;

}

}

// InputTransport.cpp

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {

//do something

status_t result = mChannel->receiveMessage(&msg);

//do something

*outSeq = msg.body.finished.seq;

*outHandled = msg.body.finished.handled;

return OK;

}

// InputDispatcher.cpp

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,

const sp<Connection>& connection, uint32_t seq, bool handled) {

//do something

// Notify other system components and prepare to start the next dispatch cycle.

onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);

}

void InputDispatcher::onDispatchCycleFinishedLocked(

nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq,

bool handled) {

CommandEntry* commandEntry = postCommandLocked(

&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);

commandEntry->connection = connection;

commandEntry->eventTime = currentTime;

commandEntry->seq = seq;

commandEntry->handled = handled;

}

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(

CommandEntry* commandEntry) {

//do something

// Start the next dispatch cycle for this connection.

startDispatchCycleLocked(now(), connection);

}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

const sp<Connection>& connection) {

//检查outboundQueue中是否还有新的input event.

while (connection->status == Connection::STATUS_NORMAL

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

DispatchEntry* dispatchEntry = connection->outboundQueue.head;

dispatchEntry->deliveryTime = currentTime;

// Publish the event.

status_t status;

EventEntry* eventEntry = dispatchEntry->eventEntry;

switch (eventEntry->type) {

case EventEntry::TYPE_KEY: {

KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

// Publish the key event.

status =

connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,

keyEntry->deviceId, keyEntry->source,

dispatchEntry->resolvedAction,

dispatchEntry->resolvedFlags,

keyEntry->keyCode, keyEntry->scanCode,

keyEntry->metaState, keyEntry->repeatCount,

keyEntry->downTime,

keyEntry->eventTime);

break;

}

case EventEntry::TYPE_MOTION:{

MotionEntry* motionEntry =

static_cast<MotionEntry*>(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;

//do something

} 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 (size_t i = 0; i < motionEntry->pointerCount; i++) {

scaledCoords[i].clear();

}

usingCoords = scaledCoords;

}

}

// Publish the motion event.

//通知ViewRootImpl去共享内存抓取新的input event

status =

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

motionEntry->deviceId, motionEntry->source,

dispatchEntry->resolvedAction,

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

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.

connection->inputPublisherBlocked = true;

}

} else {

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

} //while loop end

}

由此可知在 InputDispatcher 一收到InputConsumer对象送的 finish message之后, 就马上去呼叫startDispatchCycleLocked函数去检查 outboundQueue 里面还有没有新的inputevent. 若有的话就放入 InputMessage 共享内存, 然后通知 ViewRootImpl 去共享内存抓取新的 inputevent. 若没有新的 input event, 就不做事等待有新的inputevent进 outboundQueue.

更多相关文章

  1. Android(安卓)vold核心篇(VolumeManager)
  2. Android关于view按键音的修改
  3. Android(安卓)touch事件的派发流程
  4. android 显示系统
  5. Android媒体扫描详细解析之二(MediaScanner & MediaProvider)
  6. Android(安卓)Hook框架Xposed详解:从源代码分析到开发指南
  7. Android(安卓)ART dex2oat 浅析
  8. android 背光驱动
  9. android ViewTreeObserver详细讲解

随机推荐

  1. 深入Android(安卓)【一】 —— 序及开篇
  2. Android(安卓)内功心法(1.1)——android
  3. Android(安卓)Pay正式启用 支付宝们还好
  4. Android(安卓)内存浅析【一】【管理、机
  5. Android对移动计算的影响及产业变革
  6. 【Rayeager PX2】andoid开机logo分析及PX
  7. Android嵌入unity界面,崩溃及卸载activity
  8. 让Android自带的Gallery实现多点缩放,拖动
  9. Android(安卓)菜鸟认知总结——Android初
  10. 利用OpenCV在Android上DIY相机——第二届