Android系统MotionEvent处理Receiver端基本原理总结

来源:互联网 发布:anaconda python 安装 编辑:程序博客网 时间:2024/06/03 07:20

Android系统MotionEvent处理Receiver端基本原理总结

InputEventReceiver

Android系统中activity是接收用户触屏事件的基本单位, 一个activity对应一个window, 对应一个view root. activity初始化的时候, 每一个activity实例都会创建一个用于接收事件的socket通讯通道, system server进程通过对windows的管理, 找到当前需要接收事件的activity, 通过socket直接将事件数据发送给 activity, activity内以root view为起点, 对事件进行分发处理.
每一个viewrootimpl都有一个InputEventReceiver对象, WindowInputEventReceiver在viewrootimpl:: setView时, new InputEventReceiver构造时调用nativeInit,创建NativeInputEventReceiver,将自己的指针传给NativeInputEventReceiver,同时保留NativeInputEventReceiver的指针。
所以,每一个ViewRootImpl对应一个NativeInputEventReceiver。NativeInputEventReceiver的handleEvent会调用到相应的ViewRootImpl。
NativeInputEventReceiver是一个LooperCallback
LooperCallback定义在system/core/include/utils/Looper.h中,作为Looper::addFd的回调
NativeInputEventReceiver的构造函数会接收Java层传递的main looper的MessageQueue指针, 初始化过程中, 调用main looper的addFd将改ViewRootImpl的InputChannel的接收端的fd添加到main loope的轮循中,同时将NativeInputEventReceiver注册为回调.
每次receiver端的socket中的事件到达触发NativeInputEventReceiver的函数handleEvent调用.
WindowInputEventReceiver extends InputEventReceiver
WindowInputEventReceiver:: onInputEvent , onBatchedInputEventPending 在NativeInputEventReceiver::handleEvent中被调用

NativeInputEventReceiver

android_view_InputEventReceiver.cpp
handleEvent – > consumeEvents – > InputConsumer::consume
handleEvent调用consumeEvents, consumeEvents调用consumer的consume函数, consumeEvents主要逻辑如图示.

这里写图片描述

InputConsumer

定义在 InputTransport.cpp
封装receiver 端接收事件的核心逻辑, 从对应的InputChannel的fd中读取事件数据,并转化成App进程端需要的Event数据格式.
事件转化的主要逻辑如图示.

这里写图片描述

consumeSamples

将一个batch中的sample全部取出, 构造一个MotionEvent, 所有的sample全部添加进该MotionEvent.

consumeBatch

如果frameTime < 0,consume掉当前batch里的所有的samples, return.
sampleTime = frameTime, 如果支持Resample,sampleTime -= RESAMPLE_LATENCY
找到当前batch中,从第一个开始,直到event time < = sampleTime的最后一个event为止。这些sample为当前需要consume的一组sample.
如果支持resample, 对当前的这组sample进行resample, 否则consume掉.

InputChannel

定义在 InputTransport.cpp
call InputChannel :: receiveMessage, after getting the input message, create a event, and assign the event to passed parameter InputEvent** outEvent.
当main looper 轮循到InputChannel的fd有数据到达时, InputConsumer使用InputChannel的receiveMessage来从fd中读取数据.

do {    nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);} while (nRead == -1 && errno == EINTR);

如果中断发生,反复进行读取.

   if (nRead < 0) {        int error = errno;#if DEBUG_CHANNEL_MESSAGES        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);#endif        if (error == EAGAIN || error == EWOULDBLOCK) {            return WOULD_BLOCK;        }        if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {            return DEAD_OBJECT;        }        return -error;    }

读取返回错误, 如果是 EAGAIN 或者 EWOULDBLOCK, 返回该错误值, 返回到input receiver后, 需要针对该情况做相应处理.
数据传输连接出现问题, 返回 dead_object, 目前看, input receiver没有对dead_object做针对性处理.

    if (nRead == 0) { // check for EOF#if DEBUG_CHANNEL_MESSAGES        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());#endif        return DEAD_OBJECT;    }

读取返回值为0, socket断开.

    if (!msg->isValid(nRead)) {#if DEBUG_CHANNEL_MESSAGES        ALOGD("channel '%s' ~ received invalid message", mName.string());#endif        return BAD_VALUE;    }

检查如果没有读取到完整的数据, 返回bad_value

最后, 读取正常, return OK;
错误值 DEAD_OBJECT 等定义在system/core/include/utils/Errors.h
DEAD_OBJECT相当于-EPIPE

InputMessage

System server发送的事件数据的基本数据单元. socket每次读取一个InputMessage.
The body of the InputMessage could be Key or Motion. If it is Motion, there is a pointerCount, and an array of Pointer.
InputMessage定义在 InputTransport.cpp

Sample

一个sample就是一个 InputMessage
receiver通过socket拿到InputMessage后, 先把数据缓存成sample列表, 用一个Vector保存在Batch中.

MotionEvent

一个MotionEvent如果是滑动事件, 包含若干个sample.

Batch

Batch定义在InputConsumer中

struct Batch {
Vector samples;
};
Vector mBatches;

if motion.deviceId and motion.source are both same, it is combined as one batch.
一个设备对应一个Batch
一个Batch是一个InputMessage的数组
Batch在InputConsumer的consume中被创建, 只有当读取到滑动事件的时候才会创建Batch.
所以, down/up事件没有Batch的概念.