InputManagerService 十分钟让你了解Android触摸事件原理( 四 )

这里socketpair的创建与访问其实是还是借助文件描述符 , WMS需要借助Binder通信向APP端回传文件描述符fd , 这部分只是可以参考Binder知识 , 主要是在内核层面实现两个进程fd的转换 , 窗口添加成功后 , socketpair被创建 , 被传递到了APP端 , 但是信道并未完全建立 , 因为还需要一个主动的监听 , 毕竟消息到来是需要通知的 , 先看一下信道模型

InputManagerService 十分钟让你了解Android触摸事件原理

文章插图
 
APP端的监听消息的手段是:将socket添加到Looper线程的epoll数组中去 , 一有消息到来Looper线程就会被唤醒 , 并获取事件内容 , 从代码上来看 , 通信信道的打开是伴随WindowInputEventReceiver的创建来完成的 。
InputManagerService 十分钟让你了解Android触摸事件原理

文章插图
 
信息到来 , Looper根据fd找到对应的监听器:NativeInputEventReceiver , 并调用handleEvent处理对应事件
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; } ...之后会进一步读取事件 , 并封装成JAVA层对象 , 传递给Java层 , 进行相应的回调处理:
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {... for (;;) {uint32_t seq;InputEvent* inputEvent;<!--获取事件--> status_t status = mInputConsumer.consume(&mInputEventFactory,consumeBatches, frameTime, &seq, &inputEvent);... <!--处理touch事件--> case AINPUT_EVENT_TYPE_MOTION: { MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent); if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { *outConsumedBatch = true; } inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); break; }<!--回调处理函数--> if (inputEventObj) { env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); env->DeleteLocalRef(inputEventObj); }所以最后就是触摸事件被封装成了inputEvent , 并通过InputEventReceiver的dispatchInputEvent(WindowInputEventReceiver)进行处理 , 这里就返回到我们常见的Java世界了 。
目标窗口中的事件处理最后简单看一下事件的处理流程 , Activity或者Dialog等是如何获得Touch事件的呢?如何处理的呢?直白的说就是将监听事件交给ViewRootImpl中的rootView , 让它自己去负责完成事件的消费 , 究竟最后被哪个View消费了要看具体实现了 , 而对于Activity与Dialog中的DecorView重写了View的事件分配函数dispatchTouchEvent , 将事件处理交给了CallBack对象处理 , 至于View及ViewGroup的消费 , 算View自身的逻辑了 。
InputManagerService 十分钟让你了解Android触摸事件原理

文章插图
 
总结现在把所有的流程跟模块串联起来 , 流程大致如下:
点击屏幕
InputManagerService的Read线程捕获事件 , 预处理后发送给Dispatcher线程
Dispatcher找到目标窗口
通过Socket将事件发送到目标窗口
APP端被唤醒
找到目标窗口处理事件
如果你看到了这 , 点个赞 , 收下我双膝 。如果文章有误 , 帮忙指正 , 谢谢大佬们 。




推荐阅读