当用户触摸屏幕或者按键操作。
首先触发硬件驱动,驱动收到事件后,将相应事件写入到输入设备节点
输入系统取出内核事件,封装成为KeyEvent或MotionEvent
交付给对应的Window消费该事件。
硬件中断
物理设备将数据发送给内核是通过设备驱动
传输的,在dev/input/
目录下有几个设备文件eventX
。
其中event0
对应的就是触摸屏,当触摸屏的驱动被挂载后,驱动程序就会进行初始化。
当触发对应的硬件中断后,就会调用对应的处理方法,把对应事件写到设备节点(/dev/input/event0)
中.
IMS获取内核事件 IMS启动过程
在Android系统启动过程 有介绍系统的启动流程,其中IMS
属于system_server
,随着system_server
的启动而启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //SystemServer.java private void startOtherServices() { ... InputManagerService inputManager = null ; ... traceBeginAndSlog("StartInputManagerService"); //新建IMS对象 inputManager = new InputManagerService(context); traceEnd(); //启动IMS traceBeginAndSlog("StartInputManager"); inputManager.setWindowManagerCallbacks(wm.getInputMonitor());//与window进行绑定 inputManager.start(); traceEnd(); }
1 2 3 4 5 6 7 8 9 10 //InputManagerService.java public InputManagerService(Context context) { this .mContext = context; this .mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); ... //初始化Native对象 mPtr = nativeInit(this , mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService()); }
nativeInit()
执行在Native层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //services/core/jni/com_android_server_input_InputManagerService.cppstatic jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { //获取Native的消息队列 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); ... //创建Native的 InputManager对象 NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); //增加强引用 im->incStrong(0); //返回 NativeInputManager的指针 return reinterpret_cast <jlong>(im); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 //services/core/jni/com_android_server_input_InputManagerService.cpp NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true ) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj);//IMS对象 { 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对象 sp<EventHub> eventHub = new EventHub(); //初始InputManager对象 mInputManager = new InputManager(eventHub, this , this ); }
初始EventHub
EventHub
主要用于监控设备节点是否更新
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 //frameworks/native/services/inputflinger/EventHub.cppstatic const char *WAKE_LOCK_ID = "KeyEvents";static const char *DEVICE_PATH = "/dev/input";//设备文件 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); //创建iNotify实例 mINotifyFd = inotify_init(); //iNotify实例 监听 DEVICE_PATH int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); struct epoll_event eventItem; memset (&eventItem, 0, sizeof (eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; //epoll 监听 iNotify实例 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); int wakeFds[2]; result = pipe(wakeFds);//创造管道 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; //epoll监听 管道实例 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); int major, minor; getLinuxRelease(&major, &minor); // EPOLLWAKEUP was introduced in kernel 3.5 mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5); }
EventHub
主要执行了以下几步:
初始化epoll
实例
初始化iNotify
实例,用于监控/dev/input
目录的变化。若发生变化,意味设备发生变化,需要处理。epoll
添加iNotify实例
监听
创建非阻塞模式的管道(pipe
),epoll监听管道的内容。(主要用于 唤醒InputReader线程)
1 2 3 4 5 6 7 8 9 //frameworks/native/services/inputflinger/InputManager.cpp 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(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //frameworks/native/services/inputflinger/InputDispatcher.cpp InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), mPendingEvent(NULL ), mLastDropReason(DROP_REASON_NOT_DROPPED), mAppSwitchSawKeyDown(false ), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL ), mDispatchEnabled(false ), mDispatchFrozen(false ), mInputFilterEnabled(false ), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { //新建Looper对象 mLooper = new Looper(false ); mKeyRepeatState.lastKeyEntry = NULL ; policy->getDispatcherConfiguration(&mConfig); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //frameworks/native/services/inputflinger/InputReader.cpp 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) { //listener 对象 就是 InputDispatcher mQueuedListener = new QueuedInputListener(listener); { // acquire lock AutoMutex _l(mLock); refreshConfigurationLocked(0); updateGlobalMetaStateLocked(); } // release lock }
负责监听InputDispatcher
对象
initalize() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //frameworks/native /services/inputflinger/InputManager.cppvoid InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } //frameworks/native /services/inputflinger/InputDispatcher.cpp InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : Thread(/*canCallJava*/ true ), mDispatcher(dispatcher) { } //frameworks/native /services/inputflinger/InputReader.cpp InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : Thread(/*canCallJava*/ true ), mReader(reader) { }
initalize()
主要是创建两个能访问Java代码的native线程。
1.The InputReaderThread (called “InputReader”) reads and preprocesses raw input events,applies policy, and posts messages to a queue managed by the DispatcherThread.
2.The InputDispatcherThread (called “InputDispatcher”) thread waits for new events on the queue and asynchronously dispatches them to applications.
IMS启动——start()
IMS
初始化完毕就准备启动
1 2 3 4 5 6 //InputManagerService.java public void start() { Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); ... }
1 2 3 4 5 6 //services/core/jni/com_android_server_input_InputManagerService.cppstatic void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast <NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); }
1 2 3 4 5 6 7 8 9 //frameworks/native/services/inputflinger/InputManager.cpp status_t InputManager::start() { //启动InputDispatcherThread status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY) //启动InputReaderThread result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); return OK; }
IMS
启动,会带着InputDispatcherThread
和InputReaderThread
一起启动。
总结
IMS启动过程重点在于Native的初始化,分别创建以下对象:
初始化完毕上述对象后,然后启动以下线程:
InputReaderThread :从EventHub
取出事件并处理,再转发给InputDispatcher
InputDispatcherThread :接收来自InputReader
的事件,并派发事件到合适的窗口(window)去处理
内核事件转发APP进程过程 IMS
启动之后,InputDispatcherThread
与InputReaderThread
随之启动。
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 //frameworks/native/services/inputflinger/InputReader.cppbool InputReaderThread::threadLoop() { mReader->loopOnce(); return true ; }void InputReader::loopOnce() { ... //从EventHub获取事件列表,返回的是 事件的个数。无事件时将阻塞 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { //处理获取的事件 processEventsLocked(mEventBuffer, count); } } // release lock ... //处理完毕后发送到 InputDispatcher mQueuedListener->flush(); }
EventHub->getEvents() 获取事件
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 //frameworks/native/services/inputflinger/EventHub.cpp size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { //原始事件构造 RawEvent* event = buffer; size_t capacity = bufferSize; for (;;) {//开启循环 ... if (mNeedToScanDevices) { mNeedToScanDevices = false ; scanDevicesLocked();//开始扫描设备 mNeedToSendFinishedDeviceScan = true ; } ... while (mOpeningDevices != NULL ) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string ()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; event->type = DEVICE_ADDED;//添加设备 event += 1; mNeedToSendFinishedDeviceScan = true ; if (--capacity == 0) { break ; } } ... while (mPendingEventIndex < mPendingEventCount) { ... ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); ... Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { ... int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t(readSize) / sizeof (struct input_event); for (size_t i = 0; i < count; i++) { //获取readBuffer的数据 struct input_event& iev = readBuffer[i]; //封装成RawEvent对象 event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1; capacity -= 1; } } } ... //等待input事件 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); ... // readNotify() will modify the list of devices so this must be done after // processing all other events to ensure that we read all remaining events // before closing the devices. if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false ; //从INotify事件 读取发生的事件 readNotifyLocked(); deviceChanged = true ; } } ... // 返回读取的事件个数 return event - buffer; }
getEvents()
采用INotify + epoll
监听/dev/input/
目录下的设备节点,再转换deviceId + input_event
为RawEvent
1 2 3 4 5 6 7 8 // frameworks/native/services/inputflinger/EventHub.h struct RawEvent { nsecs_t when;//事件发生的时间点 int32_t deviceId;//设备id int32_t type;//事件类型 int32_t code; int32_t value; };
type
可以为以下几种
DEVICE_ADDED
:添加设备
DEVICE_REMOVED
:移除设备
FINISHED_DEVICE_SCAN
:扫描完成
type < FIRST_SYNTHETIC_EVENT
:其他事件
getEvents()
大概执行流程:
当设备节点(/dev/input)
发生变化时,epoll_wait()
会响应到对应的变化,然后getEvents()
可以知道对应的变化。继续从mINotifyFd
读取iNotify事件
,进行输入设备的操作,最后生成相应的RawEvent
此时,EventHub从设备节点获取到了事件,并转化为RawEvent
向下处理。
processEventsLocked() 处理事件
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 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; } //处理其他事件的数据 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; } }
addDeviceLocked() 添加设备 1 2 3 4 5 6 7 8 9 10 11 12 13 void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); //根据deviceId 创建设备 InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); device->configure(when, &mConfig, 0); device->reset(when); //添加设备 mDevices.add(deviceId, device); bumpGenerationLocked(); }
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 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); ... // Keyboard-like devices. 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)); } ... return device; }
addDeviceLocked()
主要创建InputDevice
,并且根据不同的设备类型来创建相应的InputMapper
。
根据上述代码列举对应关系:
Keyboard-like
:键盘类设备 –> KeyboardInputMapper
Cursor-like
:鼠标类设备 –> CursorInputMapper
TouchScreens
:触摸屏设备 –> MultiTouchInputMapper(多点触控) / SingleTouchInputMapper(单点触控)
processEventsForDeviceLocked() 处理设备事件 1 2 3 4 5 6 7 8 void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); //获取输入设备 InputDevice* device = mDevices.valueAt(deviceIndex); device->process(rawEvents, count); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //frameworks/native/services/inputflinger/InputReader.cppvoid InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { if (mDropUntilNextSync) { } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; //获取mapper继续执行process任务 mapper->process(rawEvent); } } --count; } }
以触摸屏为例,mapper
指向MultiTouchInputMapper
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 58 void MultiTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); }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::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering) { ... if (mPointerSimple.down && !down) { mPointerSimple.down = false ; // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, /* deviceTimestamp */ 0, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (down) { if (!mPointerSimple.down) { mPointerSimple.down = true ; mPointerSimple.downTime = when; // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } }
getListener()
指的就是mQueuedListener
1 2 3 4 //frameworks/native/services/inputflinger/InputListener.cppvoid QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); }
将触摸事件放入mArgsQueue
,此时事件加工完成。
1 2 3 4 5 6 7 8 9 10 //frameworks/native/services/inputflinger/InputListener.cppvoid 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(); }
NotifyArgs
主要有以下几类:
NotifyConfigurationChangedArgs:配置变化
NotifyKeyArgs:键盘事件
NotifyMotionArgs:触摸事件
NotifySwitchArgs:切换事件
NotifyDeviceResetArgs:设备重置事件
根据上节可知args
为NotifyMotionArgs
1 2 3 void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this ); }
listener
指的就是InputDispatcher
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 //frameworks/native/services/inputflinger/InputDispatcher.cppvoid 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); bool needWake; { // acquire lock mLock.lock(); //拦截事件分发 if (shouldSendMotionToInputFilterLocked(args)) { mLock.unlock(); MotionEvent event;//初始化MotionEvent对象 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); 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->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(); } }
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 bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry);//将事件放入`mInBoundQueue`的尾部,等待处理 traceInboundQueueLengthLocked(); switch (entry->type) { case EventEntry::TYPE_MOTION: { 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; }
总结
InputReaderThread
主要负责事件封装转换
EventHub.getEvents()
:通过epoll
监听iNotify实例(监听 /dev/input/ 目录)
读取事件放入mEventBuffer
,然后转换成RawEvent
processEventsLocked()
:对RawEvent
进行加工,转换成NotifyMotionArgs
flush()
:将事件NotifyMotionArgs
发送到InputDispatcher
进行处理,最后转换成MotionEntry
并写入到InputDispatcher.mInBoundQueue
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 // frameworks/native/services/inputflinger/InputDispatcher.cppbool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true ; }void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); //唤醒等待线程,监听当前是否发生死锁 mDispatcherIsAliveCondition.broadcast(); //派发输入事件,`nextWakeUpTime`决定下次派发线程执行时间 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); mLooper->pollOnce(timeoutMillis); }
dispatchOnceInnerLocked() 获取事件
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Ready to start a new event. // If we don't already have a pending event, go grab one. if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { //派发队列为空,进入线程休眠状态 ... // Nothing to do if there is no pending event. if (!mPendingEvent) { return ; } } else { // 从 mInBoundQueue获取事件 实质就是上一步的 MotionEntry mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } ... // 重置ANR时间 resetANRTimeoutsLocked(); } // Now we have an event to dispatch. // All events are eventually dequeued and processed this way, even if we intend to drop them. ALOG_ASSERT(mPendingEvent != NULL ); bool done = false ; DropReason dropReason = DROP_REASON_NOT_DROPPED; //检查事件是否需要丢弃 if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY; } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ... break ; } case EventEntry::TYPE_DEVICE_RESET: { ... break ; } case EventEntry::TYPE_KEY: { ... 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 ; } //准备派发下一个事件 if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } mLastDropReason = dropReason; releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } }
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 bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; // 保存触摸事件的发送目标 Vector<InputTarget> inputTargets; bool conflictingPointerActions = false ; int32_t injectionResult; if (isPointerEvent) { // 基于坐标点的形式,如触屏,根据坐标点获取目标窗口 injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { // 无坐标点的触摸事件,例如 轨迹球 injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } addMonitoringTargetsLocked(inputTargets); //将 entry 分发到 对应window上 dispatchEventLocked(currentTime, entry, inputTargets); return true ; }
InputTarget
的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //frameworks/native/services/inputflinger/InputDispatcher.h struct InputTarget { // 连接InputDispatcher与Window的通信管道 sp<InputChannel> inputChannel; // Flags for the input target. int32_t flags; // The x and y offset to add to a MotionEvent as it is delivered. // (ignored for KeyEvents) float xOffset, yOffset; // Scaling factor to apply to MotionEvent as it is delivered. // (ignored for KeyEvents) float scaleFactor; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set . BitSet32 pointerIds; }
dispatchEventLocked() 发送事件 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { pokeUserActivityLocked(eventEntry); for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); //根据InputTarget的InputChannel 获取 connection ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); //准备分发消息 prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } } }void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { ... // 将事件添加到Connections的发送队列 enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); }void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); ... // If the outbound queue was previously empty, start the dispatch cycle going. 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_MOTION: { MotionEntry* motionEntry = static_cast <MotionEntry*>(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; // Set the X and Y offset depending on the input source. float xOffset, yOffset; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { float 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; // We don't want the dispatch target to know. if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i].clear(); } usingCoords = scaledCoords; } } // Publish the motion event. 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 ; } // 回收队列 connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); // 等待执行队列 connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } }
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 //frameworks/native/libs/input/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) { 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]); } return mChannel->sendMessage(&msg); }
1 2 3 4 //frameworks/native/libs/input/InputTransport.cpp status_t InputChannel::sendMessage(const InputMessage* msg) { ... }
最终通过InputChannel.sendMessage()
发送包装好的触摸事件
TODO
handleReceiveCallback 接收事件 这一节的触发条件会在后面讲到,简单来说就是
后面Java层的事件分发结束,调用到InputEventReceiver.finishInputEvent()
,会向UI进程持有的InputChannel
写入数据,然后唤醒InputDispatcher
线程被唤醒后执行handleReceiveCallback()
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 //frameworks/native/services/inputflinger/InputDispatcher.cppint InputDispatcher::handleReceiveCallback(int fd, int events, void * data) { ... sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex); ... for (;;) { uint32_t seq; bool handled; //从 connection 获取消息 status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); if (status) { break ; } d->finishDispatchCycleLocked(currentTime, connection, seq, handled); gotOne = true ; } }void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { connection->inputPublisherBlocked = false ; if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return ; } // Notify other system components and prepare to start the next dispatch cycle. onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); }void InputDispatcher::onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { //发送命令到 doDispatchCycleFinishedLockedInterruptible CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; }void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { ... if (dispatchEntry == connection->findWaitQueueEntry(seq)) { //事件执行完毕后,从waitQueue移除事件 connection->waitQueue.dequeue(dispatchEntry); traceWaitQueueLengthLocked(connection); } // 开始下一次发送循环 startDispatchCycleLocked(now(), connection); }
总结
InputReader
发送触摸事件到InputDispatcher
,通过findFocusedWindowTargetsLocked()
寻找触摸事件对应的窗口,如果没有找到就使用第一个Window
。把结果写入inputTargets
中,然后通过publishMotionEvent
分发触摸事件,再通过InputChannel
发送消息到UI线程。
触摸事件发送至Activity
InputDispatcher
负责分发触摸事件,最后通过InputChannel->sendMessage()
发出消息
1 2 3 4 5 6 7 8 9 10 11 12 //frameworks/native/libs/input/InputTransport.cpp status_t InputChannel::sendMessage(const InputMessage* msg) { const size_t msgLength = msg->size(); InputMessage cleanMsg; msg->getSanitizedCopy(&cleanMsg); ssize_t nWrite; do { nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); return OK; }
InputChannel
通过socket
发送消息。
既然存在sendMessage()
就需要找到相对的receiveMessage()
调用的地方。
当前是InputDispatcher
调用的sendMessage()
,对应就需要去Window
找receiveMessage()
本质是SocketPair(非网络套接字)
。SocketPair
用于实现本机内的进程间通信。
SocketPair
提供方法:
socketPair()
:创建SocketPair,返回一对相互连接的fd
send()
:写入数据,可在另一个fd读取
recv()
:读取数据
非常适合用来进行进程间的交互式通讯。
InputChannel
就是SocketPair
的封装,分别分配给InputDispatcher
与Window
。
InputDispatcher
写入的事件,Window
可以从自己持有的InputChannel
获取;反向也是如此。
InputChannel
提供方法:位于InputTransport.cpp
中
openInputChannelPair()
:封装socketPair()
sendMessage()
:封装send()
receiveMessage()
:封装recv()
最后屏幕的触摸事件都需要反映到一个Activity上,然后再一步步传递到对应的View上。所以需要先从Activity开始分析触摸事件的传递流程。
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 //ActivityThread.java public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... wm.addView(decor, l); ... } // ==> WindowManagerGlobal.java public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //新建ViewRootImpl root = new ViewRootImpl(view.getContext(), display); root.setView(view, wparams, panelParentView); } // ==> ViewRootImpl.java public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { //创建InputChannel对象 if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } //创建Socket的服务端 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); //创建Socket的客户端 if (mInputChannel != null ) { if (mInputQueueCallback != null ) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } //创建WindowEventReceiver对象 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } }
addToDisplay() 1 2 3 4 5 6 7 8 9 //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); }
其中mService
指的就是WindowManagerService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //frameworks/base/services/core/java/com/android/server/wm/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); } }
addWindow()
主要创建了WindowState
对象,然后继续调用到openInputChannels()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //frameworks/base/services/core/java/com/android/server/wm/WindowState.java void openInputChannel(InputChannel outInputChannel) { if (mInputChannel != null ) { throw new IllegalStateException("Window already has an input channel."); } String name = getName(); 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 { // If the window died visible, we setup a dummy input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. // Create dummy event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); }
1 2 3 4 5 6 //InputManagerService.java public void registerInputChannel(InputChannel inputChannel, InputWindowHandle inputWindowHandle) { //通过Native层完成注册 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false ); }
1 2 3 4 5 6 7 8 status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */, const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { ATRACE_CALL(); //再通过 InputDispatcher 继续注册 return mInputManager->getDispatcher()->registerInputChannel( inputChannel, inputWindowHandle, monitor); }
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 //frameworks/native/services/inputflinger/InputDispatcher.cpp status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { { // acquire lock AutoMutex _l(mLock); //为传入的 InputChannel 创建Connection对象 sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); //监听connection的变化 mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } //如果发生变化,回调handleReceiveCallback方法 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this ); } // release lock // Wake the looper because some connections have changed. mLooper->wake(); return OK; }
addToDisplay()
主要处理两部分内容
创建Socket pair,作为InputChannel
socket服务端
保存在WidnowState
中的mInputChannel
中
socket客户端
通过binder
传到ViewRootImpl
中的mInputChannel
通过IMS.registerInputChannel()
注册InputChannel
,监听socket服务端,收到消息后回调InputDispatcher::handleReceiveCallback()
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 //ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super (inputChannel, looper); } ... @Override public void onInputEvent(InputEvent event, int displayId) { enqueueInputEvent(event, this , 0, true ); } } //InputeventReceiver.java public InputEventReceiver(InputChannel inputChannel, Looper looper) { mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this ), inputChannel, mMessageQueue); mCloseGuard.open("dispose"); } //Native层调用该方法 private void dispatchInputEvent(int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); }
初始化 InputEventReceiver
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 //frameworks/base/core/jni/android_view_InputEventReceiver.cppstatic jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == NULL ) { jniThrowRuntimeException(env, "InputChannel is not initialized."); return 0; } //获取消息队列 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL ) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } //创建NativeInputEventReceiver对象 sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); status_t status = receiver->initialize(); receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast <jlong>(receiver.get()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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) { mMessageQueue->getLooper()->addFd(fd, 0, events, this , NULL ); } else { mMessageQueue->getLooper()->removeFd(fd); } } }
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 //system/core/libutils/Looper.cppint Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void * data) { //构造native Request消息 Request request; request.fd = fd; request.ident = ident; request.events = events; request.seq = mNextRequestSeq++; request.callback = callback; //NativeInputReceiver request.data = data; if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1 struct epoll_event eventItem; request.initEventItem(&eventItem); ... //在epoll实例 添加native request监听 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); //唤醒线程 scheduleEpollRebuildLocked(); }void Looper::scheduleEpollRebuildLocked() { if (!mEpollRebuildRequired) { mEpollRebuildRequired = true ; wake(); } }
这一部分涉及looper
在Handler
就有详细介绍,wake
之后,native request
相关消息触发后会回调到callback->handleEvent()
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 //frameworks/base/core/jni/android_view_InputEventReceiver.cppint NativeInputEventReceiver::handleEvent(int receiveFd, int events, void * data) { ... if (events & ALOOPER_EVENT_INPUT) { //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) { for (;;) { status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent, &displayId); //将事件进行打包,避免量过大 if (status) { if (status == WOULD_BLOCK) { if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) { // There is a pending batch. Come back later. if (!receiverObj.get()) { receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); if (!receiverObj.get()) { ALOGW("channel '%s' ~ Receiver object was finalized " "without being disposed.", getInputChannelName().c_str()); return DEAD_OBJECT; } } mBatchedInputEventPending = true ; if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Dispatching batched input event pending notification.", getInputChannelName().c_str()); } //调用 InputReceiver.dispatchBatchedInputEventPending() env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchBatchedInputEventPending); if (env->ExceptionCheck()) { ALOGE("Exception dispatching batched input events."); mBatchedInputEventPending = false ; // try again later } } return OK; } ALOGE("channel '%s' ~ Failed to consume input event. status=%d", getInputChannelName().c_str(), status); return status; } ... if (!skipCallbacks) { jobject inputEventObj; switch (inputEvent->getType()) { case AINPUT_EVENT_TYPE_MOTION: { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str()); } //封装MotionEvent对象 MotionEvent* motionEvent = static_cast <MotionEvent*>(inputEvent); if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { *outConsumedBatch = true ; } inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); break ; } default : assert(false ); // InputConsumer should prevent this from ever happening inputEventObj = NULL ; } 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); } else { ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName().c_str()); skipCallbacks = true ; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //frameworks/native/libs/input/InputTransport.cpp status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) { while (!*outEvent) { mMsgDeferred = false ; } else { // 收到新消息 status_t result = mChannel->receiveMessage(&mMsg); if (result) { if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId); if (*outEvent) { break ; } } return result; } } }
WindowInputEventReceiver
主要执行了以下几步:
初始化了NativeInputReceiver
,调用了sendFdEvents()
发出了消息
往主线程Looper添加了一条Native Request
,且callback
为NativeInputReceiver
向Looper的mEpollFd
添加了监听,只要收到触摸事件的消息就会调用到callback->handleEvent()
NativeInputReceiver::handleEvent()
主要回调到Java层的dispatchInputEvent()
且携带InputEvent
回去(在触摸场景下,实际为MotionEvent
)。
回调到Activity
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 //InputEventReceiver.javaprivate void dispatchInputEvent(int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); } private void dispatchBatchedInputEventPending() { onBatchedInputEventPending(); } //ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { @Override public void onInputEvent(InputEvent event, int displayId) { enqueueInputEvent(event, this , 0, true ); } @Override public void onBatchedInputEventPending() { if (mUnbufferedInputDispatch) { super .onBatchedInputEventPending(); } else { scheduleConsumeBatchedInput();//按照Vsync信号进行分发 } } } //事件 void scheduleConsumeBatchedInput() { if (!mConsumeBatchedInputScheduled) { mConsumeBatchedInputScheduled = true ; //根据Vsync信号 进行触摸事件的回调 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mConsumedBatchedInputRunnable, null ); } } void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } } void doProcessInputEvents() { // Deliver all pending input events in the queue. while (mPendingInputEventHead != null ) { QueuedInputEvent q = mPendingInputEventHead; mPendingInputEventHead = q.mNext; if (mPendingInputEventHead == null ) { mPendingInputEventTail = null ; } q.mNext = null ; if (q.mEvent instanceof MotionEvent) { MotionEvent me = (MotionEvent)q.mEvent; if (me.getHistorySize() > 0) { oldestEventTime = me.getHistoricalEventTimeNano(0); } } mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); deliverInputEvent(q); } } private void deliverInputEvent(QueuedInputEvent q) { InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null ) { handleWindowFocusChanged(); stage.deliver(q); } else { //事件分发完成后 执行 finishInputEvent(q); } } abstract class InputStage { public final void deliver(QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { forward(q); } else if (shouldDropInputEvent(q)) { finish(q, false ); } else { apply(q, onProcess(q)); } } }
此处stage
是ViewPostImeInputStage
,向下继续调用到onProcess()
ViewPostImeInputStage
:视图处理阶段 ,主要处理按键、手指触摸等事件,分发的对象是View。
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 //viewRootImpl.java final class ViewPostImeInputStage extends InputStage { protected int onProcess(QueuedInputEvent q) { //按键事件 if (q.mEvent instanceof KeyEvent) { return processKeyEvent(q); } else { //触摸事件 final int source = q.mEvent.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { return processPointerEvent(q); } } } private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false ; mAttachInfo.mHandlingPointerEvent = true ; //向下分发到View boolean handled = mView.dispatchPointerEvent(event); return handled ? FINISH_HANDLED : FORWARD; } }
此时mView
表示的就是DecorView
,本质就是View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //view.java public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } //DecorView.java public boolean dispatchTouchEvent(MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); }
mWindow.getCallback()
就是与Window绑定的Activity
1 2 3 4 5 6 7 8 9 10 //Activity.java public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true ; } return onTouchEvent(ev); }
所以经过一系列操作 让用户的屏幕触摸操作,最终走到了Activity.dispatchTouchEvent()
事件分发 MotionEvent
当用户点击View或ViewGroup的时候,将会产生一个事件对象,就是MotionEvent
。
MotionEvent
记录了事件的类型(action)、触摸的位置(x,y)以及触摸的时间等
。
事件的类型主要分为以下几种:
ACTION_DOWN
:监听用户手指按下的操作,一次按下标志触摸事件的开始。
ACTION_MOVE
:用户按压屏幕后,在抬起之前,如果移动的距离超过一定数值,就判定为移动事件。
ACTION_UP
:监听用户手指离开屏幕的操作,一次抬起标志触摸事件的结束。
ACTION_CANCEL
:当用户保持按下操作,并把手指移动到了控件外部区域时且父View处理事件触发。
用户手指触摸到屏幕到离开屏幕可能产生的事件序列如下:
ACTION_DOWN
-> ACTION_MOVE
-> ACTION_MOVE
-> … ACTION_MOVE
-> ACTION_UP
MotionEvent产生时机
在ViewRootImpl.setView()
时,创建了WindowInputReceiver
,当IMS写入事件(通过EventHub监听到/dev/input/
),通过一系列的操作回调到dispatchInputEvent()
,最后走到了processPointerEvent()
,此时把从Native层传递过来的InputEvent
强转成MotionEvent
,然后继续向下传递。
MotionEvent传递顺序-事件分发顺序
事件分发本质就是MotionEvent
的传递过程。
1 2 3 4 5 6 7 8 9 10 11 //ViewRootImpl.java private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false ; mAttachInfo.mHandlingPointerEvent = true ; //向下分发到View boolean handled = mView.dispatchPointerEvent(event); return handled ? FINISH_HANDLED : FORWARD; }
mView
就是DecorView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //DecorView.java 没有实现对应方法。。。 向上寻找父类 //View.java public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } //DecorView.java @Override public boolean dispatchTouchEvent(MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); }
此时mWindow.getCallback()
指的就是Activity
Activity事件分发 1 2 3 4 5 6 7 8 9 10 11 12 13 public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { //在此处可以监听到 用户触摸屏幕的操作 onUserInteraction(); } //若dispatchTouchEvent返回true ,事件到此结束,返回false ,继续向下传递 //对应PhoneWindow if (getWindow().superDispatchTouchEvent(ev)) { return true ; } //没有任何View去处理,交给Activity自身的onTouchEvent处理 return onTouchEvent(ev); }
getWindow()
对应唯一实现类PhoneWindow
1 2 3 4 5 6 //PhoneWindow.java @Override public boolean superDispatchTouchEvent(MotionEvent event) { //mDecor 是DecorView的一个实例,DecoeView就是顶层View中的实例对象 return mDecor.superDispatchTouchEvent(event); }
mDecor
指的就是DecorView
1 2 3 4 5 //DecorView.java public boolean superDispatchTouchEvent(MotionEvent event) { //调用父类的方法即FrameLayout.dispatchTouchEvent = ViewGroup.dispatchTouchEvent(),由父类去处理事件分发 return super .dispatchTouchEvent(event);//指向了 ViewGroup }
总结一下:按照上述流程图,当一个点击事件进来时,Activity上的事件流程如下:
调用Activity.dispatchTouchEvent()
,然后调用onUserInteraction()
调用getWindow()即PhoneWindow.superDispatchTouchEvent()
调用mDecor即DecorView.superDispatchTouchEvent()
调用DecorView父类即ViewGroup.dispatchTouchEvent()
在这里实现了事件从Activity传递至ViewGroup
ViewGroup事件分发
上述Activity分发后,执行到ViewGroup.dispatchTouchEvent()
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 //ViewGroup.java @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... if (actionMasked == MotionEvent.ACTION_DOWN) { //发生ACTION_DOWN事件,取消并清除之前的触摸 cancelAndClearTouchTargets(ev); resetTouchState(); } ... //判定当前事件是否需要拦截 final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null ) {//只有ACTION_DOWN才可以触发拦截 //FLAG_DISALLOW_INTERCEPT:禁止ViewGroup拦截除了DOWN以外的事件 //可由View调用requestDisallowInterceptTouchEvent设置标记 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { //调用拦截方法 intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false ; } } else { //没有触摸targets 且 非ACTION_DOWN 需要拦截 intercepted = true ; } ... //非取消事件 且 没被拦截 if (!canceled && !intercepted) { if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {//当前为 DOWN 事件 final int actionIndex = ev.getActionIndex(); // always 0 for down //存在子View if (newTouchTarget == null && childrenCount != 0) { final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); //从上往下 寻找能处理触摸事件的子View final ArrayList<View> preorderedList = buildTouchDispatchChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); //无法获取焦点,跳过循环 if (childWithAccessibilityFocus != null ) { if (childWithAccessibilityFocus != child) { continue ; } childWithAccessibilityFocus = null ; i = childrenCount - 1; } //View不可见 或者 触摸的坐标点不在View的范围内,跳过循环 if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null )) { ev.setTargetAccessibilityFocus(false ); continue ; } newTouchTarget = getTouchTarget(child); //当前正在循环 ,退出当前循环 if (newTouchTarget != null ) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the ones it is handling. newTouchTarget.pointerIdBits |= idBitsToAssign; break ; } resetCancelNextUpFlag(child); ////事件传递下来后,调用dispatchTransformedTouchEvent,事件就会传递到View/ViewGroup中 if (dispatchTransformedTouchEvent(ev, false , child, idBitsToAssign)) { // Child wants to receive touch within its bounds. mLastTouchDownTime = ev.getDownTime(); if (preorderedList != null ) { // childIndex points into presorted list, find original index for (int j = 0; j < childrenCount; j++) { if (children[childIndex] == mChildren[j]) { mLastTouchDownIndex = j; break ; } } } else { mLastTouchDownIndex = childIndex; } mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); //添加新的 touchtarget newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true ; break ; } ev.setTargetAccessibilityFocus(false ); } if (preorderedList != null ) preorderedList.clear(); } if (newTouchTarget == null && mFirstTouchTarget != null ) { newTouchTarget = mFirstTouchTarget; while (newTouchTarget.next != null ) { newTouchTarget = newTouchTarget.next; } newTouchTarget.pointerIdBits |= idBitsToAssign; } } } // mFirstTouchTarget赋值是在通过addTouchTarget方法获取的; // 只有处理ACTION_DOWN事件,才会进入addTouchTarget方法。 // 这也正是当View没有消费ACTION_DOWN事件,则不会接收其他MOVE,UP等事件的原因 if (mFirstTouchTarget == null ) { // ViewGroup处理事件 当无人可以响应触摸事件 handled = dispatchTransformedTouchEvent(ev, canceled, null , TouchTarget.ALL_POINTER_IDS); } else { //如果View消费ACTION_DOWN事件,那么MOVE,UP等事件相继开始执行 TouchTarget predecessor = null ; TouchTarget target = mFirstTouchTarget; while (target != null ) { final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true ; } else { final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted; //子View/ViewGroup 处理触摸事件 if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true ; } if (cancelChild) { if (predecessor == null ) { mFirstTouchTarget = next; } else { predecessor.next = next; } target.recycle(); target = next; continue ; } } predecessor = target; target = next; } } ... } return handled; }
onInterceptTouchEvent() 1 2 3 4 5 6 7 8 9 public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.isFromSource(InputDevice.SOURCE_MOUSE) && ev.getAction() == MotionEvent.ACTION_DOWN && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY) && isOnScrollbarThumb(ev.getX(), ev.getY())) { return true ; } return false ; }
可以通过重写该方法,进行事件分发的拦截。
返回true,事件被拦截,执行当前View的onTouchEvent()
返回false,事件继续向下分发
buildTouchDispatchChildList() 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 public ArrayList<View> buildTouchDispatchChildList() { return buildOrderedChildList(); } ArrayList<View> buildOrderedChildList() { final int childrenCount = mChildrenCount; if (childrenCount <= 1 || !hasChildWithZ()) return null ; //z final boolean customOrder = isChildrenDrawingOrderEnabled(); for (int i = 0; i < childrenCount; i++) { // add next child (in child order) to end of list final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View nextChild = mChildren[childIndex]; final float currentZ = nextChild.getZ(); // 按z轴,从小到大排序所有的子视图,即z轴大的View先响应事件 int insertIndex = i; while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) { insertIndex--; } mPreSortedChildren.add(insertIndex, nextChild); } return mPreSortedChildren; } //View.java public float getZ() { return getElevation() + getTranslationZ(); }
默认的事件分发顺序与绘制顺序一致,按照view.getZ()
从大到小排序,Z值大的先绘制且先响应事件。
当然,这个事件分发的顺序也可以修改,只需要实现两个方法:
setChildrenDrawingOrderEnabled(true)
:允许自定义顺序。isChildrenDrawingOrderEnabled()返回true
getChildDrawingOrder()
:自定义当前View的顺序
也可以通过setElevation()
、setTranslationZ()
或者setZ()
去修改Z轴的坐标值。
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 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; //发生取消事件后,不再执行后续的任何操作 final int oldAction = event.getAction(); if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); if (child == null ) { handled = super .dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; } final MotionEvent transformedEvent; if (newPointerIdBits == oldPointerIdBits) { if (child == null || child.hasIdentityMatrix()) { if (child == null ) { //不存在子视图,调用View.dispatchTouchEvent() handled = super .dispatchTouchEvent(event); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; event.offsetLocation(offsetX, offsetY); //调用子View/ViewGroup的 dispatchTouchEvent() handled = child.dispatchTouchEvent(event); event.offsetLocation(-offsetX, -offsetY); } return handled; } transformedEvent = MotionEvent.obtain(event); } else { transformedEvent = event.split(newPointerIdBits); } // Done. transformedEvent.recycle(); return handled; }
dispatchTransformedTouchEvent()
分为两套处理方式:
child==null
:发生的情况:事件被拦截
或真的没有可执行触摸事件的子View
。执行View.dispatchTouchEvent()
child!=null
:向下执行子View/ViewGroup的dispatchTouchEvent()
addTouchTarget() 1 2 3 4 5 6 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) { final TouchTarget target = TouchTarget.obtain(child, pointerIdBits); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target; }
TouchTarget
结构如下:
1 2 3 4 5 6 7 8 9 10 private static final class TouchTarget { // The touched child view. public View child; // The combined bit mask of pointer ids for all pointers captured by the target. public int pointerIdBits; // The next target in the target list. public TouchTarget next; }
TouchTarget
是一个单链表结构,记录的是事件分发链 。每一个元素表示真正对事件消费的View
。
根据上述流程图,总结一下:
点击事件从上层传递到ViewGroup,先调用ViewGroup.dispatchTouchEvent()
判断ViewGroup.onInterceptTouchEvent()
是否拦截点击事件
默认不拦截,则将事件继续向子View传递,然后调用View.dispatchTouchEvent()
被拦截返回true
,调用super.dispatchTouchEvent()
返给父布局处理,并且ViewGroup自身也处理事件,比如onTouch(),onClick(),onTouchEvent()
等事件
通常情况下ViewGroup的onInterceptTouchEvent()
返回false,不会拦截用户操作。
不过要注意的是 拦截的是 一个用户的操作序列:从用户手指按下到手指抬起为止。
拦截了Down事件,后续的事件都会交由ViewGroup.onTouchEvent()
处理
拦截了其他事件,会给之前序列头部的ACTION_DOWN
事件发送一个ACTION_CANCEL
类型事件,通知子View无法执行后续事件,回归初始状态。(例如点击ListView中的一个Item的Button,再滑动ListView,Button就会恢复初始状态。 )
View事件分发
ViewGroup事件分发完毕后,由子View继续执行事件分发
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 //View.java public boolean dispatchTouchEvent(MotionEvent event) { boolean result = false ; if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true ; } //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null //View设置了touch事件 && (mViewFlags & ENABLED_MASK) == ENABLED //View是可以操作的 && li.mOnTouchListener.onTouch(this , event)) { //View.onTouch返回true result = true ; } //上述任一条件不满足,就会执行 onTouchEvent() if (!result && onTouchEvent(event)) { result = true ; } } return result; }
dispatchTouchEvent()
按照如下顺序执行:
onTouchListener.ouTouch()
开始执行,返回true
表示当前事件已被消费,不需要向上执行。否则继续向下执行
onTouchEvent()
返回true
表示消费事件。
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 //View.java public boolean onTouchEvent(MotionEvent event) { final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE //有点击事件 调用setOnClickListener() || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) //有长按事件 调用setOnLongClickListener() || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; if ((viewFlags & ENABLED_MASK) == DISABLED) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false ); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; //当View不可用时 直接消费事件 return clickable; } if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { case MotionEvent.ACTION_UP: if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { // This is a tap, so remove the longpress check removeLongPressCallback(); if (!focusTaken) { if (mPerformClick == null ) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { //调用View.onClckListener performClickInternal(); } } } } } } private boolean performClickInternal() { return performClick(); } public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null ) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this ); result = true ; } else { result = false ; } return result; }
根据上述流程图,总结一下:
点击事件从ViewGroup传递到View,调用View.dispatchTouchEvent()
判断当前View是否设置OnTouchListener
,并且设置了onTouch()
返回值,默认返回false
返回true
,代表事件被onTouch()
消费,不会继续往下传递
返回false
,事件继续向下传递,调用View.onTouchEvent()
,后续若设置点击事件,则继续调用performClick()
,最后执行onClick()
事件
拓展:
如果有一个控件是DISABLED
,注册的onTouch()
事件不会被执行。若要监听点击事件,只能实现它的onTouchEvent()
点击事件优先级: onTouch()
> onTouchEvent()
> performClick()
> onClick()
总结 根据前几节分析得出完整的事件分发顺序:
IMS -> WindowInputREceiver(ViewRootImpl) -> DecorView -> Activity -> DecorView -> viewGroup -> View
事件分发核心方法
boolean dispatchTouchEvent()
用来进行事件的分发。
返回true
:事件被当前View所消费,不会向下传递
返回false
:交由上一层的View的onTouchEvent()
处理
返回super.dispatchTouchEvent()
:继续向下分发事件
boolean onInterceptTouchEvent()
用来进行事件的拦截,在dispatchOnTouchEvent()
中调用。只有ViewGroup才可以调用
返回true
:拦截当前事件,并交由onTouchEvent()
去处理
返回false
:不拦截当前事件,继续向下传递
返回super.onInterceptTouchEvent()
:调用父类的onInterceptTouchEvent()
,大部分情况下是false
。
如果点击了子View区域,可以继续分发到child.dispatchTouchEvent()
没有子View可以响应事件,执行onTouchEvent()
boolean onTouchEvent()
用来处理点击事件,在dispatchOnTouchEvent()
中调用。
返回true
:当前View处理当前事件
返回false
:当前View无法处理事件,交由上一层View的onTouchEvent()
处理
返回super.onTouchEvent()
当前View设置了clickable/longclickable
,等价于返回true,当前View处理事件
当前View未设置clickable/longclickable
,等价于返回false,交由上一层的onTouchEvent()
处理。
上述三个核心方法,可以用如下伪代码代替
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean dispatchTouchEvent() { boolean res = false ; // 是否不允许拦截事件 // 如果设置了 FLAG_DISALLOW_INTERCEPT,不会拦截事件,所以在 child 里可以通过 requestDisallowInterceptTouchEvent 控制父 View 是否来拦截事件 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept && onInterceptTouchEvent()) { // View 不调用这里,直接执行下面的 touchlistener 判断 if (touchlistener && touchlistener.onTouch()) { return true ; } res = onTouchEvent(); // 里面会处理点击事件 -> performClick() -> clicklistener.onClick() } else if (DOWN) { // 如果是 DOWN 事件,则遍历子 View 进行事件分发 // 循环子 View 处理事件 for (childs) { res = child.dispatchTouchEvent(); } } else { // 事件分发给 target 去处理,这里的 target 就是上一步处理 DOWN 事件的 View target.child.dispatchTouchEvent(); } return res; }
点击事件传递从dispatchTouchEvent()
开始,在不修改默认返回值时,事件会按照嵌套层次由外向内传递,到达最内层View时,由最内层View.onTouchEvent()
处理
View的点击事件触发顺序为 onTouch()
> onTouchEvent()
> performClick()
> onClick()
Touch事件的后续(例如ACTION_MOVE
,ACTION_UP
)层级传递
若dispatchTouchEvent()
返回true,那么能收到ACTION_DOWN
的函数也可以收到后续事件
若onTouchEvent()
返回true,那么其他事件不再往下传递,而是直接传给自己的onTouchEvent()
并结束本次事件传递
事件分发核心在于ViewGroup.dispatchTouchEvent()
的ACTION_DOWN
过程中找到mFirstTouchTarget
是否为空。
通过遍历子View寻找view.disptachTouchEvent()
返回true
,就设置mFirstTouchTarget
为该子View。
如果mFirstTarget
不为空,ACTION_MOVE
和ACTION_UP
才会向子View传递,如果中途被ViewGroup
拦截了事件,子View就会收到ACTION_CANCEL
,并且mFirstTouchTarget
为null,后续的事件只会走到ViewGroup
。
事件分发特殊情况
ACTIOIN_CANCEL
产生场景
子View处理了Down事件,按照设定Move与Up的事件也会交给他处理。若此时,父View拦截了事件,此时子View就会收到一个Cancel事件,并且无法接收到后续的Move与Up事件。
常见场景:ListView有一个Item带有Button,此时点击按钮(触发ACTION_DOWN),再进行上下滑动,ListView就会拦截掉后续的Move事件,此时Button就会收到ACTION_CANCEL
子View收到ACTION_DOWN,但是上一个事件还没有结束(因为APP切换、ANR导致后续事件丢失),此时也会执行ACTION_CANCEL
子View拦截父View事件 子View通过使用requestDisallowInterceptTouchEvent(true)
命令指定ViewGroup不再针对事件序列进行拦截 ,将事件交由子View去处理。
设置requestDisallowInterceptTouchEvent(true)
后,父类会在每次ACTION_DOWN
的时候进行重置,避免影响其他子View的事件处理。
上述方法也是解决滑动冲突
的一种方法:
内部拦截法
:通过在子类中调用parent.requestDisallowInterceptTouchEvent()
来控制父类是否拦截事件。
还有一个是
外部拦截法
:通过重写父类的onInterceptTouchEvent()
拦截冲突的事件。
长按事件原理 在onTouchEvent()
收到ACTION_DOWN
事件时,发送一个延时消息mPendingCheckForLongPress()
,延迟400ms
后执行。内部执行performLongClick()
,再然后一步步调用到performLongClickInternal()
内部执行到mOnLongClickListener.onLongClick()
onLongClick()
返回true
就会屏蔽onClick()
执行。
事件分发完成 事件分发完毕后,执行到finishInputEvent()
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 //ViewRootImpl.java protected void onDeliverToNext(QueuedInputEvent q) { if (DEBUG_INPUT_STAGES) { Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); } if (mNext != null ) { //有任务继续执行 mNext.deliver(q); } else { //无任务时 通知结束 finishInputEvent(q); } } private void finishInputEvent(QueuedInputEvent q) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", q.mEvent.getSequenceNumber()); if (q.mReceiver != null ) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; q.mReceiver.finishInputEvent(q.mEvent, handled); } else { q.mEvent.recycleIfNeededAfterDispatch(); } recycleQueuedInputEvent(q); }
1 2 3 4 5 6 //InputEventReceiver.java public final void finishInputEvent(InputEvent event, boolean handled) { ... nativeFinishInputEvent(mReceiverPtr, seq, handled); ... }
nativeFinishInputEvent()
通知事件结束到Native层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 //frameworks/base/core/jni/android_view_InputEventReceiver.cppstatic void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr, jint seq, jboolean handled) { sp<NativeInputEventReceiver> receiver = reinterpret_cast <NativeInputEventReceiver*>(receiverPtr); ... status_t status = receiver->finishInputEvent(seq, handled); } status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) { ... status_t status = mInputConsumer.sendFinishedSignal(seq, handled); if (status) { if (status == WOULD_BLOCK) { ... if (mFinishQueue.size() == 1) { setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT); } return OK; } } return status; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //frameworks/native/libs/input/InputTransport.cpp status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { ... // Send finished signals for the batch sequence chain first. size_t seqChainCount = mSeqChains.size(); if (seqChainCount) { ... status_t status = OK; while (!status && chainIndex > 0) { chainIndex--; status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); } } // Send finished signal for the last message in the batch. return sendUnchainedFinishedSignal(seq, handled); }
1 2 3 4 5 6 7 8 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; //通过 InputChannel.sendMessage()发送消息通知 return mChannel->sendMessage(&msg); }
InputChannel.sendMessage()
之后,InputDispatcher
线程被唤醒,回调到handleReceiveCallback()
。执行到上面的InputDispatcheThread
相关代码。
相关示例 参考链接 InputReaderThread
Android相关源码
一次触摸,Android 到底干了啥
反思|Android 事件分发机制的设计与实现
深入理解Android卷-III