android添加input事件,android framework层input事件接收和派发
input序列图前面是启动activity时,view的添加过程。在view添加过程中会注册inputchannel,而inputchannel是input事件处理的核心通道。在本篇里所有的介绍都是围绕inputchannel的创建和读取展开的,前面的view添加是窗口管理部分不是本篇关注的内容就不介绍了。本篇从inputchannel的创建开始介绍。1.openInputChannel在Wind
input序列图
前面是启动activity时,view的添加过程。在view添加过程中会注册inputchannel,而inputchannel是input事件处理的核心通道。在本篇里所有的介绍都是围绕inputchannel的创建和读取展开的,前面的view添加是窗口管理部分不是本篇关注的内容就不介绍了。本篇从inputchannel的创建开始介绍。
1.openInputChannel
在Windowstate.java文件里面,来看看这个代码实现
从上面的截图可以看出,这个函数主要做了两件事。
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,实现截图如下:
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
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数据放到队列的尾部,然后从队列头部开始处理和派发事件
具体的doProcessInputEvents处理过程,可以自己跟踪代码了解下。这里需要说明的是deliverInputEvent是inputevent事件派发到View的最后一步调用,上面的序列图上没有体现出来。这里再来幅序列图,看看这个inputevent是如何从ViewRootImpl到View的:
这里需要注意的是,事件会被InputStage类进行拦截处理。如果本类处理不了,会交由下个InputStage类处理
这里是各种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的处理 :
后续可以根据序列图,自行跟踪代码的处理流程。本篇是介绍framework inputevent的处理流和,inputflinger的 inputevent 的处理流程可以参考我上篇对inputflinger的介绍。
本篇到此完结,如有问题敬请指出。
本文地址:https://blog.csdn.net/bruk_spp/article/details/107122157
更多推荐
所有评论(0)