之前浅显的看过事件传递的过程,但是有一些细节还是不太清除,借这次机会,可以好好的整理一下之前没有想清楚的地方.(基于android 5.0源码),记录一下事件分发流程.
- 准备InputManagerService和WindowManagerService
SystemServer中new一个InputManagerSerivce实例, 并将其作为一个输入参数, new 一个WindowManagerService实例, 将他们都注册到ServiceManager中.
看看InputManagerService的构造方法
public InputManagerService(Context context) { this.mContext = context; this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="+ mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService()); }
调用了nativeInit()方法返回一个长整型,跟进nativeInit()方法
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0); return reinterpret_cast<jlong>(im); }
原来该整型保存的是NativeInputManager实例的指针.
- NativeInputManager实例化InputManager
看看NativeInputManager的构造方法
NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) { // ... sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); }
3 InputManager准备实际工作类
看看InputManager的构造方法
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(); }
InputManager会构造两个实际工作的实例, InputDispather和InputReader两个实例.故名思意,InputReader是用来读取事件,InputDispatcher用来向上层框架和应用分发事件,当然InputDispatcher也会根据策略处理一些事件或者丢弃一些事件.这个类比较简单,就是以InputReader 和 InputDispatcher为参数分别创建两个线程, 线程函数中分别调用InputReader.loopOnce()方法和InputDispatcher.disptachOnce()方法.
4 InputReader 一直运行的工厂
InputReader主要工作是一直获取事件,处理加工事件.
4.1 EventHub 辛勤的小蜜蜂
EventHub主要功能是管理设备文件,对设备分类,读取事件.
EventHub中的getEvent()方法流程比较繁琐,用inotify接口来监控/dev/input目录,观察是否有新设备插入和设备移除, 并打开目录下的所有文件,封装成Device结构,并创建了管道用于唤醒睡眠线程, 使用epoll管理所有的文件描述符.主要的功能是从/dev/input目录下的设备文件读取事件,该方法会一直阻塞,直到有用户事件才会返回. 第一次调用该方法会扫描该目录下的所有文件,获取设备名,设备版本,物理路径,id和设备类型等信息.
4.2 InputReader构造函数
InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener);
可以发现InputReader构造函数需要传入EventHub, InputReaderPolicyInterface, InputListenerInterface.
InputReader构造方法最后一个参数是mDispatcher, mReader中用mQueuedListener来保存.
InputReader主要用来读取和处理事件,具体的处理是由InputMapper及其子类的process方法来完成, 在loopOnce方法中会调用EventHub的getEvents方法不断读取原始事件,并对事件分类,设置不同的InputMapper, 最后调用mQueueListener->flush()方法.
void InputReader::loopOnce() { size_t count = mEventHub->getEvents(timeoutMills, mEventBuffer, EVENT_BUFFER_SIZE); processEventsLocked(mEventBuffer, count); timeoutExpiredLocked(now); mQueueListener->flush(); }
processEventLocked()方法中, 第一次调用loopOnce方法会调用 addDeviceLocked(), addDeviceLocked() 会调用createDeviceLocked()方法.
InputDevice* InputReader::createDeviceLocked( int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { // ... // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // ... }
createDeviceLocked()方法会根据设备类型,添加不同的InputMapper. processEventLocked()方法中,不是第一次调用loopOnce时会调用 processEventsForDeviceLocked().
该方法直接调用每个InputDevice的process方法.
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); }
跟进InputDevice的process方法
void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; } else { } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().string()); mDropUntilNextSync = true; reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } }
可以发现InputDevice.process()方法最终是调用InputMapper的process方法.
class InputMapper 是用来处理加工原始事件, 表示可以处理某一相同类型的事件.
常见的InputMapper有SwitchInputMapper, KeyboardInputMapper, TrackballInputMapper, MultiTouchInputMapper和SingleTouchInputMapper.
InputReader处理完原始事件后构造了一个NofifyArgs, NotifyArgs也有很多子类,如NotifySwitchArgs, NotifyMotionArgs, NotifyKeyArgs等.
通过调用getListener()->notfiy()方法把它投入mQueueListener中. mQueueListener 是类QueuedInputListener的实例.
看看QueuedInputListener的几个方法
构造方法的innerListener参数也是就是InputReader构造方法的第三个参数,也就是InputDispathcer的实例.
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : mInnerListener(innerListener) { }
在InputReader中调用getListener->ntotifyMotion()方法就是调用notifyMotion方法, 在InputReader中构造的NotifyMotionArgs结构是保存在栈上的,所以这里需要保存在堆上,然后入队.
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); }
InputReader loopOnce最后调用的 flush方法就是这个了
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(); } void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this); }
5忙碌的事件快递员
InputDispatcher主要作用是派送InputReader放在队列上的事件,当然,也会处理一些事件或者丢弃一些事件.
NotifyArgs结构体里的listener就是InputDispathcer, 此时函数调用进入了InputDispathcer.
5.1 notifyMotion方法
看看InputDispathcerde notfiyMotion方法
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { // here is debugging info I removed if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { return; } uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (shouldSendMotionToInputFilterLocked(args)) { mLock.unlock(); MotionEvent event; event.initialize(args->deviceId, args->source, args->action, args->flags, args->edgeFlags, args->metaState, args->buttonState, 0, 0, args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } 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, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } }
删除了调试信息和空行后,就剩下这么多了.流程还是好理解, 首先验证NotifyMotionArgs的有效性, 如何验证没有跟进去看, 然后判断是否入队, 再是判断事件是否过滤, 通过了上面3个检查后, 提取NotifyMotionArgs的字段,构造MotionEntry实例, 入队,唤醒其他线程.
至此, 一个触屏事件从获取到加工全部完成,现在已经入队,那是不是准备分发给应用程序了呢? 其实还有会儿.
5.2 enqueueInboundEventLock 方法
跟进 enqueueInboundEventLocked 这个方法看看
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); switch (entry->type) { case EventEntry::TYPE_KEY: { // I have removed. I just care about MotionEvent break; } case EventEntry::TYPE_MOTION: { // Optimize case where the current application is unresponsive and the user // decides to touch a window in a different application. // If the application takes too long to catch up then we drop all events preceding // the touch into the other window. MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && mInputTargetWaitApplicationHandle != NULL) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; needWake = true; } } break; } } return needWake; }
看到了findTouchedWindowAtLocked(displayId, x, y) 这个方法后,感觉把事件派发给应用很近了. 这里的displayId 是在InputReader中设置的, 取值有ADISPLAY_ID_DEFAULT和ADISPLAY_ID_NONE.
InputDispatcherThread的线程函数是InputDispatcher类的dispatchOnce()方法.
5.3 dispatchOnce 方法
看看dispatchOnce
void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); // Run a dispatch loop if there are no pending commands. // The dispatch loop might enqueue commands to run afterwards. if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } // Run all pending commands if there are any. // If any commands were run then force the next poll to wake up immediately. if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); }
5.4 dispatchOnceInnerLocked方法
// Poke user activity for this event. if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } // Get ready to dispatch the event. resetANRTimeoutsLocked();
看下处理触屏事件的处理逻辑
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; } if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); #endif ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to t rue pokeUserActivityLocked(eventEntry); for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTar get); } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " "is no longer registered with the input dispatcher.", inputTarget.inputChannel->getName().string()); #endif } } }
根据inputTarget的inputChannel取得connection, 然后调用prepareDispatchCycleLocked方法. 关于inputChannel 和 Connection 后面再介绍. prepareDispatchCycleLocked方法最后调用enqueueDispatchEntriesLocked方法.
5.5 enqueueDispatchEntriesLocked方法
看enqueueDispatchEntriesLocked方法
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); } }
这个方法首先调用enqueueDispatchEntryLock方法,enqueueDispatchEntryLock方法第四个参数传入的是一些标识请求模式的整型值,整型值具体代表什么意思,以后再分析,然后将EventEntry入队,最后调用startDispatchCycleLocked .
5.6 startDispatchCycleLocked
一路跟踪startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName()); #endif while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); // remove some } // Publish the motion 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; } // Re-enqueue the event on the wait queue. connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } }
发现触屏事件最终是调用connection->inputPublisher.publishMotionEvent方法,这个方法参数有17个. 阅读最后几行代码,可以看到InputDispatcher中队列比较多.
到目前为止,InputDispatcher分发完成了.下一步应该就是通知应用来读取了.
分析应用读取事件之前,不得不看看connection的结构,以及它从哪里来.
connection是从mConnectionsByFd中检索出来的.在registerInputChannel方法中找到了
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); }
Connection是定义在InputDispatcher内部的类,看看定义
class Connection : public RefBase { protected: virtual ~Connection(); public: enum Status { // Everything is peachy. STATUS_NORMAL, // An unrecoverable communication error has occurred. STATUS_BROKEN, // The input channel has been unregistered. STATUS_ZOMBIE }; Status status; sp<InputChannel> inputChannel; // never null sp<InputWindowHandle> inputWindowHandle; // may be null bool monitor; InputPublisher inputPublisher; InputState inputState;
注意有两个陌生的类 InputChannel 和 InputPublisher.
InputPubliser在InputTransport.h文件中的定义(去掉了参数)
class InputPublisher { public: explicit InputPublisher(const sp<InputChannel>& channel); ~InputPublisher(); inline sp<InputChannel> getChannel() { return mChannel; } status_t publishKeyEvent() status_t publishMotionEvent() status_t receiveFinishedSignal(); private: sp<InputChannel> mChannel; };
InputChannel也是在InputTransport.h文件中的定义,只看看openInputChannelPair函数的声明
class InputChannel : public RefBase { public: /* Creates a pair of input channels. * * Returns OK on success. */ static status_t openInputChannelPair(const String8& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); };
感觉像是一对socket. 在WindowManagerService的addWindow方法中发现了同名的方法.
public int addWindow() { // ... String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.setInputChannel(inputChannels[0]); inputChannels[1].transferTo(outInputChannel); mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); // ... }
到了connection->inputPublisher.publishMotionEvent这里,InputDispatcher已经完成了事件的分发,等待窗口处理了.
下一篇文章将记录从应用程序角度来分析publishMotionEvent方法.