写在前面 本文基于Android 7.1.1 (API 25)
的源码分析编写
安卓是基于触摸操作进行交互的系统,几乎所有的操作都由对屏幕的一次次触摸完成,如何正确处理触摸事件关乎整个应用的操作体验。因此安卓对于触摸事件的分发与处理机制也是我们学习安卓开发的重中之重。同时几乎每一个安卓技术博客中都会对触摸分发机制这一块进行详解,例如比较早期也是最为出名的郭霖 (《第一行代码》的作者)。现在网络上对于这一块的分析也已经比较详尽了,基本上一篇博客中遗漏的部分都可以在其他博客中找到答案。
但是无论别人的文章讲得多好,多么详细,我们都需要自己去打开源码仔细分析好好体会,一是这样一个比较复杂的过程不经历自己的思考很难完全理解,二是随着api
版本的推进这部分源码也会发生很多变化,虽然大致思路相同,但是接触到新的内容总是一件好事。
这也就是我写这篇博文的原因:记录自己思考与分析的过程。
触摸事件的来源 这部分的内容与安卓本身无关,代码大部分也都是C++
实现的,中间的大部分内容来自于我对相关资料的总结,不在代码层面进行详细解释,只是说明一个流程,同时也会对代码进行大部分的删减,只关注最核心的那部分。
从硬件到内核 我们从头开始,从触摸事件最初最初的来源开始,我们知道内核是以处理中断的方式处理用户的输入的,触摸事件作为一种特殊的输入事件,自然也需要这种方式进行处理,只不过触摸事件的提供的信息要稍微复杂一些。
触摸事件来自于我们对硬件的操作,最初的来源当然是硬件引起的中断。而处理特定中断的代码则来自于对应硬件的驱动:
图片来源 (以下系列图片来源相同,不作标注)
当一个输入设备的驱动模块被首次载入内核的时候,会检测它应该管理的硬件设备,如果检测成功,驱动模块会调用include/linux/input.h
中的input_register_device(…)
函数设置一个/dev/input/eventX
(X
为整数)来代表这个输入设备。驱动模块同时也会通过include/linux/interrupt.h
的request_irq(…)
函数注册一个函数去处理这个硬件引发的中断,注册成功以后,当设备因用户交互而产生中断的时候就会交给对应的驱动模块进行处理。
驱动模块处理的细节各不相同,但最终都会将数据处理后存放进对应的/dev/input/eventX
文件中。
系统对触摸事件的处理 现在驱动程序为我们收集好了原始的输入信息并存放在了eventX
文件中,下一步就是系统对于这个文件的处理并发送到应用层面。
可以看到系统服务充当了从内核到应用的桥梁。
系统服务由三个组件构成:EventHub
、InputReader
、InputDispatcher
,关于它们的作用的详细分析在:
http://gityuan.com/2016/12/31/input-ipc/
下面对这个过程作简单介绍。
EventHub 文件在frameworks/native/services/inputflinger/EventHub.cpp
它的作用是监听、读取/dev/input
目录下产生的新事件,并封装成RawEvent
结构体供InputReader
使用。
文件在frameworks/native/services/inputflinger/InputReader.cpp
InputReader
运行在一个单独的进程中,这个进程由InputManagerService
的初始化而新建,具体内容请见:
http://gityuan.com/2016/12/10/input-manager/
它会在内部不断地循环调用loopOnce()
方法来不断读取事件:
1 2 3 4 5 6 7 8 9 void InputReader::loopOnce () { ... size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); ... if (count) { processEventsLocked(mEventBuffer, count); } ... }
第3行调用了mEventHub
的getEvent()
方法以获取事件。
第6行调用processEventLocked()
方法来处理事件,经过一系列判断之后,会执行这行代码:
1 device->process(rawEvents, count);
process
函数会执行如下代码:
1 2 InputMapper* mapper = mMappers[i]; mapper->process(rawEvent);
使用mapper
去处理rawEvent
,不同的输入事件类型会由不同的mapper
去处理,以处理触摸事件的TouchInputMapper
为例:
只看核心调用的话,会依次调用如下函数:
1 2 3 4 5 6 7 8 9 10 11 void TouchInputMapper::process (const RawEvent* rawEvent) void TouchInputMapper::sync (nsecs_t when) void TouchInputMapper::processRawTouches (bool timeout) void TouchInputMapper::cookAndDispatch (nsecs_t when) void TouchInputMapper::dispatchTouches (nsecs_t when, uint32_t policyFlags) void TouchInputMapper::dispatchMotion (nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, 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)
在最终的dispatchMotion()
函数中执行以下代码:
1 2 3 4 5 NotifyMotionArgs args (when, getDeviceId(), source, policyFlags, action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime) ;getListener()->notifyMotion(&args);
可以看到事件已经被处理成了一个args
,然后调用getListener()
:
1 2 3 InputListenerInterface* InputReader::ContextImpl::getListener() { return mReader->mQueuedListener.get(); }
获取的是mQueuedListener
,查看notifyMotion()
函数:
1 2 3 void QueuedInputListener::notifyMotion (const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); }
这里的NotifyMotionArgs()
只是对事件进行了一次再封装。可以看到这个args
最终进入了QueuedInputListener
的mArgsQueue
中。
我们再回到InputReader
的loopOnce()
函数中,函数在执行完上述调用到达最后一行时:
1 mQueuedListener->flush();
调用flush()
函数:
1 2 3 4 5 6 7 8 9 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(); }
调用了各args
的notify()
函数:
1 2 3 void NotifyMotionArgs::notify (const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this ); }
注意这里的listener
传入的是mInnerListener
,它是什么呢?
1 2 3 QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : mInnerListener(innerListener) { }
在构造函数中初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this ), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0 ), mGeneration(1 ), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0 ) { mQueuedListener = new QueuedInputListener(listener); { AutoMutex _l(mLock); refreshConfigurationLocked(0 ); updateGlobalMetaStateLocked(); } }
在InputReader
构造函数中构造QueuedInputListener
。
而InputReader
是由InputManager
类进行初始化的(线程的新建也在这个类中):
1 2 3 4 5 6 7 8 InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); }
注意到第6行中,传入的listener
正是mDispatcher
也就是InputDispatcher
对象。
所以说,listener->notifyMotion(this);
调用的是InputDispatcher
的notifyMotion()
函数,至此,InputReader
的工作已经完成,它从EventHub
中循环读取地rawEvent
事件,并处理成args
再通知InputDispatcher
对事件进行进一步的分发处理。
我们直接来到InputDispatcher
的源码,路径:frameworks/native/services/inputflinger/InputDispatcher.cpp
上面说到最终调用了InputDispatcher
的notifyMotion
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 MotionEvent event; event.initialize(args->deviceId, args->source, args->action, args->actionButton,args->flags, args->edgeFlags, args->metaState, args->buttonState, 0 , 0 , args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); ... MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, args->pointerCount, args->pointerProperties, args->pointerCoords, 0 , 0 ); needWake = enqueueInboundEventLocked(newEntry);
里面新建并初始化了一个MotionEvent
,然后包装成一个Entry
,然后调用enqueueInboundEventLocked()
函数:
1 mInboundQueue.enqueueAtTail(entry);
在enqueueInboundEventLocked()
函数中将这个entry
插入到了mInboundQueue
这个InputDispatcher
维护的成员变量中。
到这里我们可以看到事件经过一系列的处理和传递以后最终作为一个entry
插入到了InputDispatcher
的队列中等待被进一步分发。
这个分发过程是在哪里进行的呢?
InputDispatcher
线程的threadLoop()
函数会被不断调用:
1 2 3 4 bool InputDispatcherThread::threadLoop () { mDispatcher->dispatchOnce(); return true ; }
在dispatcherOnce()
中:
1 2 3 if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); }
在没有待执行的指令时执行dispatchOnceInnerLocked()
函数:
1 mPendingEvent = mInboundQueue.dequeueAtHead();
这个函数中还包含了ANR
的判断信息,关于ANR
的部分之后再另开博文讲。
若mInboundQueue
不为空,则从中取出头部的pendingEvent
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 switch (mPendingEvent->type) {case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry *typedEntry = static_cast <ConfigurationChangedEntry *>(mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; break ; } case EventEntry::TYPE_DEVICE_RESET: { DeviceResetEntry *typedEntry = static_cast <DeviceResetEntry *>(mPendingEvent); done = dispatchDeviceResetLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; break ; } case EventEntry::TYPE_KEY: { KeyEntry *typedEntry = static_cast <KeyEntry *>(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 <MotionEntry *>(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 ; }
下面对取出的mPendingEvent
的类型进行判断,根据不同的类型信息把它转换回原来的Entry
信息,然后调用相应的分发方法,我们还是顺着触摸事件分发这条路继续向下走,调用了bool InputDispatcher::dispatchMotionLocked()
函数:
1 2 3 4 5 6 7 8 9 10 int32_t injectionResult;if (isPointerEvent) { injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); }
对触摸或轨迹球事件做一个判断,再调用findTouchedWindowTargesLocked()
函数:
1 2 3 4 5 int32_t pointerIndex = getMotionEventActionPointerIndex(action);int32_t x = int32_t (entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t (entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y));
在这里取出了entry
里面的pointerIndex
与触摸点坐标的x
y
值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 size_t numWindows = mWindowHandles.size();for (size_t i = 0 ; i < numWindows; i++) { sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo *windowInfo = windowHandle->getInfo(); if (windowInfo->displayId != displayId) { continue ; } int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0 ; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { newTouchedWindowHandle = windowHandle; break ; } } if (maskedAction == AMOTION_EVENT_ACTION_DOWN && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } else if (isWindowObscuredLocked(windowHandle)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } mTempTouchState.addOrUpdateWindow(windowHandle, outsideTargetFlags, BitSet32(0 )); } } }
这段代码的目的是为了遍历所有的window
找到触摸对应的那个window
。
1 2 3 4 5 6 7 8 9 10 if (newTouchedWindowHandle == NULL ) { newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (newTouchedWindowHandle == NULL ) { ALOGI("Dropping event because there is no touchable window at (%d, %d)." , x, y); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } }
如果遍历后没有找到合适的window
,那就取第一个前台的window
。
然后通过addWindowTargetLocked()
方法把缓存下来的结果存放入inputTargets
中。
1 2 3 4 5 for (size_t i = 0 ; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, inputTargets); }
1 2 3 4 5 6 7 8 9 10 11 12 13 void InputDispatcher::addWindowTargetLocked (const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) { inputTargets.push(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget& target = inputTargets.editTop(); target.inputChannel = windowInfo->inputChannel; target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; target.pointerIds = pointerIds; }
函数将原始的window
数据进行了再次封装。
找到合适的window
或是没有找到(处理错误)之后,函数返回到bool InputDispatcher::dispatchMotionLocked()
中:
1 dispatchEventLocked(currentTime, entry, inputTargets);
开始向inputTargets
中的目标分发事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void InputDispatcher::dispatchEventLocked (nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {... 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 { ... } } }
inputTarget
中包含的inputChannel
就是后面用于与window
实例通信的关键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class InputChannel : public RefBase { protected : virtual ~InputChannel(); public : InputChannel(const String8& name, int fd); static status_t openInputChannelPair (const String8& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) ; inline String8 getName () const { return mName; } inline int getFd () const { return mFd; } status_t sendMessage (const InputMessage* msg) ; status_t receiveMessage (InputMessage* msg) ; sp<InputChannel> dup () const ; private : String8 mName; int mFd; };
InputChannel
包含了一个本地unix socket
用于跨进程发送与接收输入信息。
它的接口十分简单,我们就通过sendMessage()
与receiveMessage()
两个函数实现跨进程通信。
回到之前,我们通过这个inputChannel
的Fd
(文件描述符)来获取一个Connection
的索引,然后根据这个索引从mConnectionsByFd
中获取connection
对象。
1 2 3 4 5 6 7 8 9 10 ssize_t InputDispatcher::getConnectionIndexLocked (const sp<InputChannel>& inputChannel) { ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); if (connectionIndex >= 0 ) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputChannel.get() == inputChannel.get()) { return connectionIndex; } } return -1 ; }
这个mConnectionByFd
又是怎么建立起来的呢?在InputDispatcher
中包含了一个registerInputChannel
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 status_t InputDispatcher::registerInputChannel (const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {... { AutoMutex _l(mLock); ... sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0 , ALOOPER_EVENT_INPUT, handleReceiveCallback, this ); } mLooper->wake(); return OK; }
connection
对象就是在这里由inputChannel
构造并加入到mConnectionsByFd
中的。而mConnectionsByFd
本身是一个以Fd
为索引的键值对:
1 KeyedVector<int , sp<Connection> > mConnectionsByFd;
取得connection
对象之后,进入到了prepareDispatchCycleLocked()
函数中,这个函数对连接的状态是否正常进行检测,连接正常会调用enqueueDispatchEntriesLocked()
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void InputDispatcher::enqueueDispatchEntriesLocked (nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); 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 (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } }
中间调用了一系列的enqueueDispatchEntryLocked()
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void InputDispatcher::enqueueDispatchEntryLocked ( const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { int32_t inputTargetFlags = inputTarget->flags; if (!(inputTargetFlags & dispatchMode)) { return ; } inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor); ... connection->outboundQueue.enqueueAtTail(dispatchEntry); traceOutboundQueueLengthLocked(connection); ... }
省略的代码对entry
进行了进一步的包装,然后在最后加入到了connection
维护的outboundQueue
中。
回到上面,之后调用startDispatchCycleLocked()
正式开始分发事件:
1 2 3 4 5 6 7 8 9 while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) {
从connection
的outboundQueue
取出entry
之后,根据事件类型的不同对事件进一步处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast <MotionEntry*>(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; 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 ; if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (uint32_t i = 0 ; i < motionEntry->pointerCount; i++) { scaledCoords[i].clear(); } usingCoords = scaledCoords; } }
在对事件的坐标进行解析(缩放)之后,进入下面的发布过程:
1 2 3 4 5 6 7 8 9 10 11 12 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 ; }
实际上调用了InputPublisher
的publishMotionEvent()
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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.actionButton = actionButton; 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 (uint32_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);
函数里封装了一个msg
,然后最终调用了mChannel
的sendMessage()
方法进行跨进程通信。
现在我们到了图中的这一步:
我们的点击事件来到了建立的socket
中,准备与交付给对应的app
,我们知道每个app
运行在自己的进程中,所以就需要使用socket
来进行跨进程通信。
本段内容主要参考了
Gityuan的博客
详细分析及代码请移步上面链接。
连接的建立是在一个Activity
启动时进行的。
Activity
的启动是一个比较复杂的过程,会经过ActivityManagerService
与WindowManagerService
的层层调用,最终到达WindowManagerGlobal
的addView()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 public void addView (View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ... ViewRootImpl root; View panelParentView = null ; ... root = new ViewRootImpl(view.getContext(), display); ... root.setView(view, wparams, panelParentView); ... }
在addView
中,创建并初始化了一个ViewRootImpl
对象,并调用了它的setView()
方法。
ViewRootImpl
的初始化过程:
1 2 3 4 5 public ViewRootImpl (Context context, Display display) { ... mWindowSession = WindowManagerGlobal.getWindowSession(); ... }
这里我们关注的是这个mWindowSession
对象的初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static IWindowSession getWindowSession () { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null ) { try { InputMethodManager imm = InputMethodManager.getInstance(); IWindowManager windowManager = getWindowManagerService(); sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged (float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } }
下面是setView()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void setView (View view, WindowManager.LayoutParams attrs, View panelParentView) { ... res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); ... if (mInputChannel != null ) { mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } ... }
上面的两行语句分别的对应两个注册过程的开始,先执行服务端的注册与监听,再执行客户端的注册与监听。
下面对这两个过程分别进行追踪。
服务端过程 通过刚刚获取的mWindowSession
去调用系统线程中的addToDisplay()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Override public int addToDisplay (IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this , window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); } ... 这个`mService`自然就是之前获取它使用的`WindowManagerService`,调用它的`addWindow()`方法: ```java public int addWindow (Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ... WindowState win = new WindowState(this , session, client, token, attachedWindow, appOp[0 ], seq, attrs, viewVisibility, displayContent); ... final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ); if (openInputChannels) { win.openInputChannel(outInputChannel); } ... }
我们关注的是它创建并初始化了WindowState
对象,然后调用了它的openInputChannel()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void openInputChannel (InputChannel outInputChannel) { if (mInputChannel != null ) { throw new IllegalStateException("Window already has an input channel." ); } String name = makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); mInputChannel = inputChannels[0 ]; mClientChannel = inputChannels[1 ]; mInputWindowHandle.inputChannel = inputChannels[0 ]; if (outInputChannel != null ) { mClientChannel.transferTo(outInputChannel); mClientChannel.dispose(); mClientChannel = null ; } else { mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); }
在这里创建了两个InputChannel
对象,其中作为服务端存放在系统进程中的是inputChannels[0]
,作为客户端的存放在app
的ui
主线程中的是inputChannels[1]
。它们的传递过程之后再看,我们先看InputChannel
建立时调用的openInputChannelPair()
方法:
1 2 3 4 5 6 7 8 9 10 public static InputChannel[] openInputChannelPair(String name) { if (name == null ) { throw new IllegalArgumentException("name must not be null" ); } if (DEBUG) { Slog.d(TAG, "Opening input channel pair '" + name + "'" ); } return nativeOpenInputChannelPair(name); }
调用了native
方法:
1 2 3 4 5 6 7 8 9 static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair (JNIEnv* env, jclass clazz, jstring nameObj) { ... sp<InputChannel> serverChannel; sp<InputChannel> clientChannel; status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); ... return channelPair; }
在这里就分为了serverChannel
与clientChannel
,作为openInputChannelPair
调用的两参数来成对地创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 status_t InputChannel::openInputChannelPair (const String8& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& 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; }
我们可以看到第4行使用了系统调用socketpair()
来创建一对本地socket
对象,使用int
数组sockets
来接收创建好的fd
。
下面使用系统调用setsockopt()
来为新建的socket
进行配置,设置了socket
实体的输入输出buff
大小。
第21、25行调用了Native
InputChannel
的构造方法以name+(server)
或name+(client)
作为名字参数与创建好的socket
作为fd
参数来构造InputChannel
对象,它的构造方法:
1 2 3 4 5 6 7 8 9 10 11 InputChannel::InputChannel(const String8& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d" , mName.string (), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0 , "channel '%s' ~ Could not make socket " "non-blocking. errno=%d" , mName.string (), errno); }
将name
fd
保存到域中,并配置了fd
。
现在我们的两个InputChannel
(实际上是一对本地socket
的封装)就创建好了。
现在我们回到WindowState
的openInputChannel()
方法中,在成功创建两个InputChannel
后,调用了 mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
:
1 2 3 4 5 6 7 8 public void registerInputChannel (InputChannel inputChannel, InputWindowHandle inputWindowHandle) { if (inputChannel == null ) { throw new IllegalArgumentException("inputChannel must not be null." ); } nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static void nativeRegisterInputChannel (JNIEnv* env, jclass , jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { NativeInputManager* im = reinterpret_cast <NativeInputManager*>(ptr); sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); ... sp<InputWindowHandle> inputWindowHandle = android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); status_t status = im->registerInputChannel( env, inputChannel, inputWindowHandle, monitor); ... }
1 2 3 4 5 6 status_t NativeInputManager::registerInputChannel (JNIEnv* , const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { return mInputManager->getDispatcher()->registerInputChannel( inputChannel, inputWindowHandle, monitor); }
getDispatcher()
返回了InputDispatcher
对象,这个方法就调用了我们之前提到过的InputDispatcher::registerInputchannel()
方法,向InputDispatcher
注册了我们创建好的InputChannel
服务端。
我们回顾一下这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 status_t InputDispatcher::registerInputChannel (const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {... { AutoMutex _l(mLock); ... sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0 , ALOOPER_EVENT_INPUT, handleReceiveCallback, this ); } mLooper->wake(); return OK; }
将InputChannel
的Fd
作为索引保存到InputDispatcher
中。
然后调用mLooper
的addFd
在Native Looper
中设置自定义fd
进行监听,传入了handleReceiveCallback()
函数作为参数,这样一来,在服务端收到消息时就会进行回调。关于Native Looper
处理事件的分析可见另一系列的博文 。
客户端过程 1 2 3 4 if (mInputChannel != null ) { mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); }
这里以客户端InputChannel
与当前应用的Looper
作为参数,初始化了WindowInputEventReceiver
对象:
1 2 3 4 5 6 7 8 9 public InputEventReceiver (InputChannel inputChannel, Looper looper) { ... mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this ), inputChannel, mMessageQueue); mCloseGuard.open("dispose" ); }
获取了app
进程的消息队列,并调用native
方法对mReceiverPtr
进行初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static jlong nativeInit (JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { ... sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); ... sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); status_t status = receiver->initialize(); ... receiver->incStrong(gInputEventReceiverClassInfo.clazz); return reinterpret_cast <jlong>(receiver.get()); }
创建了NativeInputEventReceiver
对象,并调用initialize()
方法进行初始化:
1 2 3 4 status_t NativeInputEventReceiver::initialize () { setFdEvents(ALOOPER_EVENT_INPUT); return OK; }
1 2 3 4 5 6 7 8 9 10 11 void NativeInputEventReceiver::setFdEvents (int events) { if (mFdEvents != events) { mFdEvents = events; int fd = mInputConsumer.getChannel()->getFd(); if (events) { mMessageQueue->getLooper()->addFd(fd, 0 , events, this , NULL ); } else { mMessageQueue->getLooper()->removeFd(fd); } } }
这里将客户端的InputChannel
保存的Fd
加入到了Native Looper
中进行监听,对返回的消息进行处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 int Looper::addFd (int fd, int ident, int events, const sp<LooperCallback>& callback, void * data) { { AutoMutex _l(mLock); Request request; request.fd = fd; request.ident = ident; request.events = events; request.seq = mNextRequestSeq++; request.callback = callback; request.data = data; if (mNextRequestSeq == -1 ) mNextRequestSeq = 0 ; struct epoll_event eventItem ; request.initEventItem(&eventItem); ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0 ) { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); if (epollResult < 0 ) { ALOGE("Error adding epoll events for fd %d: %s" , fd, strerror(errno)); return -1 ; } mRequests.add(fd, request); } else { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); if (epollResult < 0 ) { if (errno == ENOENT) { epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); ... ... } ... } } }
这里将NativeInputEventReceiver
传入的this
作为callback
存入到request
中, 再以fd
为索引向mRequests
映射表中加入request
,然后以fd
作为信号调用epoll_ctl
系统调用,利用它对通信过程进行监听,在收到消息之后最终会根据fd
找到mRequests
中的request
保存的callback
,即NativeInputEventReceiver
对象。
关于addFd
方法的详细分析,可以查看Native消息机制的博文
小结 现在我们了解了从内核到应用整个触摸事件的传输过程,并且知道了InputChannel
在两端的监听建立与触发的函数,至此,触摸事件已经从系统底层来到了我们的应用进程,下一篇博客 将从触发函数开始讲解事件从native
层真正传入java
层的过程。