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
}
}
// Session.java
@Override
public int addToDisplay(IWindow window, int seq,
WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.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
}
2.2 输入事件处理流程:
一开机的时候, SystemServer 会启动 InputManagerService, 这时 InputManagerService 又会去启动两个Thread,InputReaderThread,InputDispatcherThread和一个 EventHubInterface . 因此输入事件处理流程跟此三位角色有关系.InputReaderThread从EventHubInterface抓取新的inputevent, 然后在依各个的eventtype 进入各个的 event mapper, 各个的 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();
}
最后会发现会将所收到的Touch motion 信息打包成message,然后利用 QueuedInputListener 将 message 推入 mArgsQueue 向量里.
// InputListener.h
Vector mArgsQueue;
// InputListener.cpp
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
InputReader处理完有关 Touch Motion 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来呼叫
mArgsQueue vector中的 notify 函数, 继续看下去
//InputListener.cpp
void NotifyMotionArgs::notify(const sp& 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;
}
从
InputDispatcherThread的启动流程开始分析到此为止,InputReader Thread 已经把新的Touch motion event放进InboundQueue了. 接下来就来看InputDispatcher Thread 的输入事件流程.
// 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(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& 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 =
mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry,
&inputTarget);
} else {
//do something
}
}
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& 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, 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, 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) {
// 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]);
}
return mChannel->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 取 new input 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 的抽象类, 此抽象类里有一个pure virtual function handleEvent函数, 因此只要找到谁继承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(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION:
inputEventObj =
android_view_MotionEvent_obtainAsCopy(env,
static_cast(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 还是 Motion event 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(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
// 从MotionEvent的java 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来配置一块Motion Event 对象来使用. 为何要这么大费周章还要去回呼Java layer作配置对象的动作, 推论应该是要
藉由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 function
onTouch 函数要实作, 方便app可以接收到Touch event 然后作相关的应用. 然而刚刚分析的输入事件的流程似乎没有去呼叫
onTouch函数, 这到底是怎么一回事? 原因在于 InputEventReceiver 这个类别, 这个类别是属于
abstract 类别, 在java的语法中,abstract类别即使类别中的成员函数都有实作, 也是无法实体化的, 因此只能有abstract类别的衍生类别才能实体化. 搜寻了一下程序代码发现了几个abstract InputEventReceiver类别的衍生类别, 跟InputEvent处理有关的衍生类别就是
WindowInputEventReceiver , 原因如下, 再一开始ViewRootImpl在作 setView 时, 除了new 一个新的 InputChannel 对象之后, 又 new 了一个 WindowInputEventReceiver 对象. 此 WindowInputEventReceiver 类别正好又overwrite
onInputEvent函数, 因此可以大胆推测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或是无法掌握的input event就会被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 receiver =
reinterpret_cast(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.
return sendUnchainedFinishedSignal(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;
return mChannel->sendMessage(&msg);
}
一旦ViewRootImpl 藉由 InputChannel对象传送 finish的message 时, 这时InputDispatcher类别的 handleReceiveCallback 函数就会被触发. 原因在于InputDispatcher在初始化的时候有去做register InputChannel 的动作, 在 register InputChannel时, 会在自己new 出来的 looper对象上增加一个 callback function
handleReceiveCallback.// 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, 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, 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) {
//检查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(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;
//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.