android事件队列,android framework层input事件接收和派发

input序列图

7abdf69792bc8e5da5cf4d6aad1a4813.png

前面是启动activity时,view的添加过程。在view添加过程中会注册inputchannel,而inputchannel是input事件处理的核心通道。在本篇里所有的介绍都是围绕inputchannel的创建和读取展开的,前面的view添加是窗口管理部分不是本篇关注的内容就不介绍了。本篇从inputchannel的创建开始介绍。

1.openInputChannel

在Windowstate.java文件里面,来看看这个代码实现

1db58c6d914e2ca748da3e07c891b38c.png

从上面的截图可以看出,这个函数主要做了两件事。

1.调用接口生成能够相互读写的socket

2.将其中的一个socket注册到inputflinger HAL层

2.openInputChannelPair

这个函数主要是调用native的JNI方法,生成socket并返回。

public static InputChannel[] openInputChannelPair(String name) {

if (name == null) {

throw new IllegalArgumentException("name must not be null");

}

if (DEBUG) {

Slog.d(TAG, "Opening input channel pair '" + name + "'");

}

return nativeOpenInputChannelPair(name);

}

其JNI的实现在,android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,

jclass clazz, jstring nameObj) {

const char* nameChars = env->GetStringUTFChars(nameObj, NULL);

String8 name(nameChars);

env->ReleaseStringUTFChars(nameObj, nameChars);

spserverChannel;

spclientChannel;

status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

if (result) {

String8 message;

message.appendFormat("Could not open input channel pair. status=%d", result);

jniThrowRuntimeException(env, message.string());

return NULL;

}

jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);

if (env->ExceptionCheck()) {

return NULL;

}

jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,

std::make_unique(serverChannel));

if (env->ExceptionCheck()) {

return NULL;

}

jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,

std::make_unique(clientChannel));

if (env->ExceptionCheck()) {

return NULL;

}

env->SetObjectArrayElement(channelPair, 0, serverChannelObj);

env->SetObjectArrayElement(channelPair, 1, clientChannelObj);

return channelPair;

}

其核心就是调用InputTransport.cpp 源文件的openInputChannelPair来最终生成socket,实现截图如下:

e3828627b99dab4eea73eb65d481fe3c.png

3-4 registerInputChannel

在上两步中,生成了一对能相互读写的socket,接下来就是将serversocket注册到inputflinger中,从而inputflinger向这个socket写事件,而HAL则在clientsocket中读事件,然后通知framework.其JNI层向inputflinger注册channel的代码如下:

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,

jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {

NativeInputManager* im = reinterpret_cast(ptr);

spinputChannel = android_view_InputChannel_getInputChannel(env,

inputChannelObj);

if (inputChannel == NULL) {

throwInputChannelNotInitialized(env);

return;

}

spinputWindowHandle =

android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

status_t status = im->registerInputChannel(

env, inputChannel, inputWindowHandle, monitor);

if (status) {

String8 message;

message.appendFormat("Failed to register input channel. status=%d", status);

jniThrowRuntimeException(env, message.string());

return;

}

if (! monitor) {

android_view_InputChannel_setDisposeCallback(env, inputChannelObj,

handleInputChannelDisposed, im);

}

最终是调inputDispatch.cpp文件中的registerInputChannel接口,将这个socket注册进去

5.WindowInputEventReceiver

这个类定义在ViewRootImpl.java文件里面,它是InputEventReceiver类的最终子类,是JAVA层Input事件处理的起始和数据的最初来源

首先来看下InputEventReceiver的构造函数:

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");

}

这个构造函数的核心就是调用native方法,把clientsocket和消息队列传递给JNI

6.nativeInit

d63cfd473f37b481a0a3d5b2a93e4cf1.png

7.NativeInputEventReceiver

class NativeInputEventReceiver : public LooperCallback

首先NativeInputEventReceiver是LooperCallback的一个子类,LooperCallback

关于Looper的机制,可以参考

https://blog.csdn.net/xiaosayidao/article/details/73992078?ops_request_misc=&request_id=&biz_id=102&utm_term=LooperCallback&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-73992078

这篇文章,这里就不仔细说了。Looper类处理事件的入口函数为handleEvent

可以根据序列图的调用顺序跟踪代码流程。

8.dispatchInputEvent

这个函数是JNI反调的,是JAVA层input数据的入口和来源,来看看这个函数的实现

@SuppressWarnings("unused")

private void dispatchInputEvent(int seq, InputEvent event, int displayId) {

mSeqMap.put(event.getSequenceNumber(), seq);

onInputEvent(event, displayId);

}

如图,这个函数很简单,主要就是调接口onInputEvent处理数据,而WindowInputEventReceiver子类重写了这个接口,看其实现如下:

@Override

public void onInputEvent(InputEvent event, int displayId) {

enqueueInputEvent(event, this, 0, true);

}

9.java层input事件派发

如8的第二幅图所示,数据会通过enqueueInputEvent接口将InputEvent数据放到队列的尾部,然后从队列头部开始处理和派发事件

b3e8fd78712ebc65de326eb30fcc84f9.png

具体的doProcessInputEvents处理过程,可以自己跟踪代码了解下。这里需要说明的是deliverInputEvent是inputevent事件派发到View的最后一步调用,上面的序列图上没有体现出来。这里再来幅序列图,看看这个inputevent是如何从ViewRootImpl到View的:

e568f655edf6801dc71549e847da1d48.png

这里需要注意的是,事件会被InputStage类进行拦截处理。如果本类处理不了,会交由下个InputStage类处理

aeb8872ebd727dc3aca504fa51206222.png

这里是各种inputstage的层次关系,它们都是InputStage的子类。通过构造函数,将其赋值给类成员变量next.如果本类无法处理,则会调用next类的deliver函数来处理,来看看deliver的实现:

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));

}

}

我们View处理key和touch事件是在ViewPostImeInputStage这个stage里面,这里来看看这个类的process对input event的处理 :

c43dbc38e2bc9797e07c9f1851a068bc.png

后续可以根据序列图,自行跟踪代码的处理流程。本篇是介绍framework inputevent的处理流和,inputflinger的 inputevent 的处理流程可以参考我上篇对inputflinger的介绍。

本篇到此完结,如有问题敬请指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值