android inputmanager中事件的传递流程
涉及文件路径:
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
frameworks\base\core\java\android\view\InputChannel.java
frameworks\base\core\jni\android_view_InputChannel.cpp
frameworks\base\core\java\android\hardware\input\InputManager.java
frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
frameworks\native\services\inputflinger\InputManager.h
frameworks\native\services\inputflinger\InputManager.cpp
frameworks\native\services\inputflinger\InputReader.h
frameworks\native\services\inputflinger\InputReader.cpp
frameworks\native\services\inputflinger\InputListener.cpp
frameworks\native\services\inputflinger\InputDispatcher.h
system\core\libutils\include\utils\Looper.h
system\core\libutils\Looper.cpp
frameworks\native\services\inputflinger\InputDispatcher.cpp
frameworks\native\libs\input\InputTransport.cpp
frameworks\native\include\input\InputTransport.h
frameworks\base\core\java\android\view\ViewRootImpl.java
frameworks\native\services\inputflinger\EventHub.h
frameworks\native\include\input\InputDevice.h
frameworks\native\services\inputflinger\EventHub.cpp
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
frameworks\base\services\core\java\com\android\server\wm\Session.java
frameworks\base\core\java\android\view\InputEventReceiver.java
frameworks\base\core\jni\android_view_InputEventReceiver.cpp
概述:
android系统输入管理系统inputmanager主要功能就是监听android输入设备,及时将屏幕点击、按键事件、滚动球、鼠标等输入设备产生的输入事件通过转换成java层可使用的事件,比如motionevent,keyevent等将其从底层设备获取出来传递至android系统或者app,然后由系统或者app来做出相应的处理,比如在一个activity中点击了一个控件,屏幕的点击事件会通过inputmanager系统转化成一次触摸事件,然后将其传递至activity,然后activity继续将其传递至该控件,由该控件来做相应处理。
inputmanager系统主要类关系图如下:
主要从五个流程上来分析:
1、inputmanager系统的初始化
2、InputReader读取事件的流程
3、InputDispatcher事件分发的流程
4、java层事件监听器的注册流程
5、事件如何从C层传递至Java层
inputmanager系统的初始化
inputmanagerservice服务在systemserver中启动:
traceBeginAndSlog("StartInputManagerService"); inputManager = new InputManagerService(context); traceEnd(); ...... ...... traceBeginAndSlog("StartInputManager"); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start(); traceEnd();
InputManagerService服务启动后的流程如下图:
inputmanagerservice初始化方法如下:
public InputManagerService(Context context) { this.mContext = context; this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); //调用native方法的初始化,这个是重点 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); ...... } ...... public void start() { //开始扫描设备发送事件 nativeStart(mPtr); ...... }
com_android_server_input_InputManagerService.cpp中的方法如下:
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } //初始化NativeInputManager NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0); return reinterpret_cast(im);}static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast(ptr); //开始事件的扫描和派发 status_t result = im->getInputManager()->start(); if (result) { jniThrowRuntimeException(env, "Input manager could not be started."); }}NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp& looper) : mLooper(looper), mInteractive(true) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj); { AutoMutex _l(mLock); mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; mLocked.pointerSpeed = 0; mLocked.pointerGesturesEnabled = true; mLocked.showTouches = false; mLocked.pointerCapture = false; } mInteractive = true; //初始化EventHub和InputManager sp eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this);}
EventHub.cpp
EventHub::EventHub(void) : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), mOpeningDevices(0), mClosingDevices(0), mNeedToSendFinishedDeviceScan(false), mNeedToReopenDevices(false), mNeedToScanDevices(true), mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); //新建epoll对象 mEpollFd = epoll_create(EPOLL_SIZE_HINT); //新建notify对象 mINotifyFd = inotify_init(); //将存储设备点的路径dev/input作为监听对象添加到inotify对象中 int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); //将mINotifyFd作为epoll的一个监控对象 struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; //将对mINotifyFd的监听注册到epoll对象中 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); int wakeFds[2]; result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); int major, minor; getLinuxRelease(&major, &minor); mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);}
在EventHub的构造函数中,它通过INotify与Epoll机制建立起对设备点增删事件及可读状态的监听。INotify是Linux内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等等。它有两个基本对象,inotify对象对应一个队列,应用程序可以向inotify对象添加多个监听,当被监听的事件发生时,可以通过read()函数从inotify对象中将事件信息读取出来;而watch对象则用来描述文件系统的变化事件的监听,它是一个二元组,包括监听目标和事件掩码两个元素,监听目标是文件系统的一个路径,可以是文件也可以是文件夹。Epoll可以使用一次等待监听多个描述符的可读/可写状态。
InputManager.cpp
InputManager::InputManager( const sp& eventHub, const sp& readerPolicy, const sp& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); //reader的初始化中将mDispatcher作为参数传入 mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize();}
从类关系图可知,InputDispatcher继承自InputListenerInterface
void InputManager::initialize() { //初始化两个线程 mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher);}
status_t InputManager::start() { //启动线程开始派发事件 status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } //启动线程开始读取设备输入事件 result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK;}
InputReader读取事件的流程
事件读取流程如下图:
事件的读取流程通过threadLoop的机制(如果返回true,则不没有调用requestExit的情况下会继续在此调用一次threadLoop),实现了反复调用loopOnce,通过eventhub读取原始事件,然后将其加工后通过不同的mapper,将其发送到inputdispatch的事件缓存队列中。
bool InputReaderThread::threadLoop() { //这里会循环调用 mReader->loopOnce(); return true;}void InputReader::loopOnce() { ...... //从eventhub中读取事件 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // 持锁 AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { //如果读取到原始事件,则继续往下 processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) {#if DEBUG_RAW_EVENTS ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);#endif mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // 释放锁 // 发送设备变换信息 if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // 将队列中的事件发送至监听器 mQueuedListener->flush();}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { //对缓存中的事件依次操作直到全部处理完 for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } //处理事件,传入deviceId processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { //处理设备相关信息,添加,删除,修改设置 switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; }}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是根据事件RawEvent中的deviceId来确定 device->process(rawEvents, count);}void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { ...... ...... for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; //将事件交给了各自的mapper mapper->process(rawEvent); } } }}
这里将事件交给了具体的mapper来处理,mapper与device的关系如下:
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); ...... // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); } // Scroll wheel-like devices. if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { device->addMapper(new RotaryEncoderInputMapper(device)); } // Vibrator-like devices. if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { device->addMapper(new VibratorInputMapper(device)); } ...... if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { device->addMapper(new JoystickInputMapper(device)); } // External stylus-like devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { device->addMapper(new ExternalStylusInputMapper(device)); } return device;}
这里以触摸事件为例:
void TouchInputMapper::process(const RawEvent* rawEvent) { //记录事件 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) { const RawState* last = mRawStatesPending.isEmpty() ? &mCurrentRawState : &mRawStatesPending.top(); // Push a new state. mRawStatesPending.push(); RawState* next = &mRawStatesPending.editTop(); next->clear(); next->when = when; // Sync button state. next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); // Sync scroll next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); // Sync touch syncTouch(when, next); // Assign pointer ids. if (!mHavePointerIds) { assignPointerIds(last, next); }#if DEBUG_RAW_EVENTS ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " "hovering ids 0x%08x -> 0x%08x", last->rawPointerData.pointerCount, next->rawPointerData.pointerCount, last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value, last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);#endif processRawTouches(false /*timeout*/);}void TouchInputMapper::processRawTouches(bool timeout) { ...... cookAndDispatch(mCurrentRawState.when); ......}void TouchInputMapper::cookAndDispatch(nsecs_t when) { if (!mCurrentMotionAborted) { dispatchButtonRelease(when, policyFlags); dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); dispatchButtonPress(when, policyFlags); } }void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { ...... dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); ......}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) { ...... NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args);}
至此,从eventhub中读取上来的输入设备事件,经过层层包装,最终以NotifyMotionArgs的形式发送至dispatchthread中。
InputDispatcher事件分发的流程
事件分发流程如下图:
InputDispatcher的派发和inputread一样,都是利用线程的threadLoop的循环原理,反复调用dispatchOnce将存在缓存队列中的事件派发出去,换队队列的添加,则是通过Inputread将eventhub中获取的事件加工后添加到队列中。
事件添加到队列流程:
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ...... if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, args->pointerProperties)) { return; } uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; android::base::Timer t; mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", std::to_string(t.duration().count()).c_str()); } bool needWake; { // acquire lock ...... // Just enqueue a new motion event. 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); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); }}bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); //加入到队列末尾 mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); ......} inline void enqueueAtTail(T* entry) { entryCount++; entry->prev = tail; if (tail) { tail->next = entry; } else { head = entry; } entry->next = NULL; tail = entry; }
事件派发流程如下:
bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true;}void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); // 如果当前没有待运行命令,就发送事件 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 //等待回调或者超时或者唤醒 nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); //这里开启looper循环 mLooper->pollOnce(timeoutMillis);}
dispatchOnce中启动了pollOnce,查看源码可知,会进入循环调用pollInner,利用epoll机制,查看是否有监测文件发生了修改,activity监听屏幕点击事件,正式通过looper循环利用epoll机制,获取事件的回调。
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); //当处于非交互状态时候不管正常的事件派发是否暂停都重置下按键重复定时 if (!mDispatchEnabled) { resetKeyRepeatLocked(); } //如果当前派发冻结,则停止一切派发活动 if (mDispatchFrozen) {#if DEBUG_FOCUS ALOGD("Dispatch frozen. Waiting some more.");#endif return; } /...... //准备开始发送一个新event //如果当前还没有要准备发送的事件,就抓一个来发送 if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { if (isAppSwitchDue) { //inbound 队列是空的,所有等待app switch事件都到达不了,所以停止等待 resetPendingAppSwitchLocked(false); isAppSwitchDue = false; } //合成一个合适的重复key if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; } } } // 如果自己合成也还是没有即将需要发送的,就返回了 if (!mPendingEvent) { return; } } else { // 队列非空,将队列头的事件获取出来 mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } // 拦截用户事件 if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } //准备发送点击事件ANR信号 resetANRTimeoutsLocked(); } //现在有一个需要发送的事件,根据不用类型,采取不同的派送方式,这里以TYPE_MOTION为例 switch (mPendingEvent->type) { ...... case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } //派发事件 done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } default: ALOG_ASSERT(false); break; } ......发送完成一次事件后的处理 }}
bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { ...... bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; // 事件发送目标 Vector inputTargets; bool conflictingPointerActions = false; int32_t injectionResult; if (isPointerEvent) { // 屏幕触摸事件,找到目标窗口 injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { //按键事件,找到目标窗口 injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { CancelationOptions::Mode mode(isPointerEvent ? CancelationOptions::CANCEL_POINTER_EVENTS : CancelationOptions::CANCEL_NON_POINTER_EVENTS); CancelationOptions options(mode, "input event injection failed"); synthesizeCancelationEventsForMonitorsLocked(options); } return true; } addMonitoringTargetsLocked(inputTargets); // 派发事件 ...... dispatchEventLocked(currentTime, entry, inputTargets); return true;}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector& inputTargets) { ...... pokeUserActivityLocked(eventEntry); for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); //得到connection之后发送 prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { ...... } }}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { ...... // 检查connection状态是否正常,如果不正常,就放弃本次发送 if (connection->status != Connection::STATUS_NORMAL) {#if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", connection->getInputChannelName().c_str(), connection->getStatusLabel());#endif return; } //如果需要,拆分动作事件后发送。 if (inputTarget->flags & InputTarget::FLAG_SPLIT) { ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); MotionEntry* originalMotionEntry = static_cast(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { MotionEntry* splitMotionEntry = splitMotionEvent( originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } ...... enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } } //如果不用拆分,则按照排列顺序发送 enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& 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); }}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp& connection) { ...... //如果connection状态正常,并且出栈队列非空,就开始发送了 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); // 发送按键事件 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; // 设置X/Y偏移量 float xOffset, yOffset; ...... //发送点击事件, status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, motionEntry->displayId, dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); break; } default: ALOG_ASSERT(false); return; } ......检查发送结果处理 }}
InputTransport.cpp中发送流程如下:
status_t InputPublisher::publishMotionEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action, int32_t actionButton, 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, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { ...... if (!seq) { ALOGE("Attempted to publish a motion event with sequence number 0."); return BAD_VALUE; } if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".", mChannel->getName().c_str(), pointerCount); return BAD_VALUE; } //转换成inputmessage 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.displayId = displayId; 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]); } //通过inputchannle发送 return mChannel->sendMessage(&msg);}
status_t InputChannel::sendMessage(const InputMessage* msg) { size_t msgLength = msg->size(); ssize_t nWrite; do { 将信息写入到InputChannel类对应的文件描述符中 nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); ......写入之后的处理}
一次屏幕点击事件在dispatchthread中的发送流程到这里就走完了,最终结果是,将事件转换成inputmessage后写入到了inputchannle中的mFd所描述的文件中去了,之后会通过looper来获取文件的写入事件,将信息读出,继续向java层传递。
java层事件监听器的注册流程
java事件的监听,这里以activity为例,下图展示activity如何向inputmanager系统添加事件监听:
在activity设置界面时,viewrootimpl中会新建inputchannle,并通过window系统添加到inputmanager系统
ViewRootImpl if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { //新建inputchannle mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); //添加到window res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); } catch (RemoteException e) {
Session.java
@Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel); }
WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ...... final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow); ...... final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0); if (openInputChannels) { win.openInputChannel(outInputChannel); } ......
WindowState.java
void openInputChannel(InputChannel outInputChannel) { ...... //向inputmanager注册channel mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); }
com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { NativeInputManager* im = reinterpret_cast(ptr); sp inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == NULL) { throwInputChannelNotInitialized(env); return; } sp inputWindowHandle = android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); //向NativeInputManager调用注册方法 status_t status = im->registerInputChannel( env, inputChannel, inputWindowHandle, monitor); if (status) { std::string message; message += StringPrintf("Failed to register input channel. status=%d", status); jniThrowRuntimeException(env, message.c_str()); return; } if (! monitor) { android_view_InputChannel_setDisposeCallback(env, inputChannelObj, handleInputChannelDisposed, im); }}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */, const sp& inputChannel, const sp& inputWindowHandle, bool monitor) { ATRACE_CALL(); //向dispatchthread注册 return mInputManager->getDispatcher()->registerInputChannel( inputChannel, inputWindowHandle, monitor);}
status_t InputDispatcher::registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) { ...... { // acquire lock AutoMutex _l(mLock); //如果该inputchannel已经注册过了,则不再添加 if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", inputChannel->getName().c_str()); return BAD_VALUE; } // sp connection = new Connection(inputChannel, inputWindowHandle, monitor); // int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); //向looper中添加fd mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); } // release lock // Wake the looper because some connections have changed. mLooper->wake(); return OK;}
InputEventReceiver.java
public InputEventReceiver(InputChannel inputChannel, Looper looper) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null"); } if (looper == null) { throw new IllegalArgumentException("looper must not be null"); } mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference(this), inputChannel, mMessageQueue); mCloseGuard.open("dispose"); }
android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { sp inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == NULL) { jniThrowRuntimeException(env, "InputChannel is not initialized."); return 0; } sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } //新建NativeInputEventReceiver sp receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); //初始化 status_t status = receiver->initialize(); if (status) { String8 message; message.appendFormat("Failed to initialize input event receiver. status=%d", status); jniThrowRuntimeException(env, message.string()); return 0; } receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast(receiver.get());}status_t NativeInputEventReceiver::initialize() { setFdEvents(ALOOPER_EVENT_INPUT); return OK;}void NativeInputEventReceiver::setFdEvents(int events) { if (mFdEvents != events) { mFdEvents = events; int fd = mInputConsumer.getChannel()->getFd(); if (events) { //想looper添加fd,传入的回调就是NativeInputEventReceiver mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL); } else { mMessageQueue->getLooper()->removeFd(fd); } }}
事件如何从C层传递至Java层
事件向java层传递流程图如下:
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { ...... if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? 1 : 0; } ......}status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { ...... if (inputEventObj) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str()); } //回调java层的dispatchInputEvent方法 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj, displayId); if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event."); skipCallbacks = true; } env->DeleteLocalRef(inputEventObj); }
@SuppressWarnings("unused") private void dispatchInputEvent(int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); //这里会调用WindowInputEventReceiver中的重载方法 onInputEvent(event, displayId); }
final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); } @Override public void onInputEvent(InputEvent event, int displayId) { //开始在activity中的传递 enqueueInputEvent(event, this, 0, true); }
至此,一个从底层硬件设备产生的屏幕触摸事件就经过了eventhub的获取,inputread线程的读取和加工,inputdispatch线程的派发,在looper中回调进入NativeInputEventReceiver,然后再回调到java层的InputEventReceiver子类中,到这里,一个事件就成功的发送到了activity中,然后再由activity继续向下级子view传递。
更多相关文章
- android ListView嵌套checkbox并取代checkbox点击事件
- EventBus 《三》 事件的具体用法及其讲解
- Android事件处理分析+Android事件处理 +Android输入事件流程
- Android View 绘制流程之三:draw绘制
- android 电池(二):android关机充电流程、充电画面显示
- Android OTA升级原理和流程分析(一)--update.zip包的制作