input序列图

7d67cee56197b9c896e01109212ada7c.png

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

1.openInputChannel

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

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

sp serverChannel;

sp clientChannel;

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,实现截图如下:

78186f85e61402cbdabf124a4e5eb4d3.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);

sp inputChannel = android_view_InputChannel_getInputChannel(env,

inputChannelObj);

if (inputChannel == NULL) {

throwInputChannelNotInitialized(env);

return;

}

sp inputWindowHandle =

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

88f95eb6037cde68461152a93773a633.png

7.NativeInputEventReceiver

class NativeInputEventReceiver : public LooperCallback

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

关于Looper的机制,可以参考

这篇文章,这里就不仔细说了。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数据放到队列的尾部,然后从队列头部开始处理和派发事件

b8939f40da555b93fd9d69a9d8883e2c.png

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

2f5e524bdadc4bbe75d89bfd00cd0629.png

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

e601761dccdb1ffe2d70e1e3d718c550.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的处理 :

0da83ba4f5983cb9935aff716008e91b.png

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

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

本文地址:https://blog.csdn.net/bruk_spp/article/details/107122157

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐