欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

android framework层input事件接收和派发

程序员文章站 2022-03-03 22:22:14
input序列图前面是启动activity时,view的添加过程。在view添加过程中会注册inputchannel,而inputchannel是input事件处理的核心通道。在本篇里所有的介绍都是围绕inputchannel的创建和读取展开的,前面的view添加是窗口管理部分不是本篇关注的内容就不介绍了。本篇从inputchannel的创建开始介绍。1.openInputChannel在Windowstate.java文件里面,来看看这个代码实现......

input序列图

android framework层input事件接收和派发

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

 

1.openInputChannel

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

android framework层input事件接收和派发

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

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<InputChannel> serverChannel;
    sp<InputChannel> 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<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

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

android framework层input事件接收和派发

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<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }

    sp<InputWindowHandle> 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<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

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

6.nativeInit

android framework层input事件接收和派发

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数据放到队列的尾部,然后从队列头部开始处理和派发事件

android framework层input事件接收和派发

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

android framework层input事件接收和派发

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

android framework层input事件接收和派发

这里是各种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的处理 :

android framework层input事件接收和派发

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

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

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