美文网首页
Android IMS原理解析之InputChannel

Android IMS原理解析之InputChannel

作者: 雷涛赛文 | 来源:发表于2021-08-27 11:14 被阅读0次

           接着上篇文章Android IMS原理解析之InputDispatcher的分析,本文主要分析Input事件如何发送到对应窗口,事件发送及处理反馈主要是通过InputChannel来进行的,结合Connection、InputPublisher、InputConsumer等,接下来一起分析一下:

    Input事件发送到窗口

           上面讲到,InputDispatcher在事件派发时最终会通过Connection调用到InputPublisher内部的publishMotionEvent()方法,先看一下Connection这个类,该类定义在InputDispatcher.h中:

    1.Connection
    InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
            status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
            monitor(monitor),
            inputPublisher(inputChannel), inputPublisherBlocked(false) {
    }
    
    class Connection : public RefBase {
        protected:
            virtual ~Connection();
    
        public:
            enum Status {
                // Everything is peachy.
                STATUS_NORMAL,
                // An unrecoverable communication error has occurred.
                STATUS_BROKEN,
                // The input channel has been unregistered.
                STATUS_ZOMBIE
            };
    
            Status status;
            sp<InputChannel> inputChannel; // never null
            sp<InputWindowHandle> inputWindowHandle; // may be null
            bool monitor;
            InputPublisher inputPublisher;
            InputState inputState;
    
            bool inputPublisherBlocked;
    
            // Queue of events that need to be published to the connection.
            Queue<DispatchEntry> outboundQueue;
    
            Queue<DispatchEntry> waitQueue;
    
            explicit Connection(const sp<InputChannel>& inputChannel,
                    const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
    
            inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
    
            const char* getWindowName() const;
            const char* getStatusLabel() const;
    
            DispatchEntry* findWaitQueueEntry(uint32_t seq);
    }
    

           可以看到,该类内部定义了InputChannel、InputWindowHandle、InputPublisher等变量,是对以上对象的封装,Connection是事件发送的入口,主要的发送逻辑是由封装的类对象执行的;

    2.InputPublisher

           该类的实现路径为:frameworks/native/libs/input/InputTransport.cpp,看一下publishMotionEvent()的实现:

    //创建InputPublisher实例时传入InputChannel
    InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
            mChannel(channel) {
    }
    
    status_t InputPublisher::publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source,int32_t displayId, 
            int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags,int32_t metaState,
            int32_t buttonState,float xOffset,float yOffset,float xPrecision,float yPrecision,nsecs_t downTime,
            nsecs_t eventTime,uint32_t pointerCount,const PointerProperties* pointerProperties,
            const PointerCoords* pointerCoords) {
        .....
        ......
        InputMessage msg;
        msg.header.type = InputMessage::TYPE_MOTION;
        msg.body.motion.seq = seq;
        msg.body.motion.deviceId = deviceId;
        msg.body.motion.source = source;
        msg.body.motion.displayId = displayId;
        msg.body.motion.action = action;
        msg.body.motion.actionButton = actionButton;
        msg.body.motion.flags = flags;
        msg.body.motion.edgeFlags = edgeFlags;
        msg.body.motion.metaState = metaState;
        msg.body.motion.buttonState = buttonState;
        msg.body.motion.xOffset = xOffset;
        msg.body.motion.yOffset = yOffset;
        msg.body.motion.xPrecision = xPrecision;
        msg.body.motion.yPrecision = yPrecision;
        msg.body.motion.downTime = downTime;
        msg.body.motion.eventTime = eventTime;
        msg.body.motion.pointerCount = pointerCount;
        for (uint32_t i = 0; i < pointerCount; i++) {
            msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
            msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
        }
        return mChannel->sendMessage(&msg);
    }
    

           在publishMotionEvent()内部,最终是将MotionEvent封装成InputMessage,然后调用mChannel->sendMessage(&msg),mChannel是InputChannel实例;

    3.InputChannel

           该类的实现路径为:frameworks/native/libs/input/InputTransport.cpp

    status_t InputChannel::sendMessage(const InputMessage* msg) {
        const size_t msgLength = msg->size();
        InputMessage cleanMsg;
        msg->getSanitizedCopy(&cleanMsg);
        ssize_t nWrite;
        do {
            nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
        } while (nWrite == -1 && errno == EINTR);
    
        if (nWrite < 0) {
            int error = errno;
            if (error == EAGAIN || error == EWOULDBLOCK) {
                return WOULD_BLOCK;
            }
            if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
                return DEAD_OBJECT;
            }
            return -error;
        }
    
        if (size_t(nWrite) != msgLength) {
            return DEAD_OBJECT;
        }
    
        return OK;
    }
    
    status_t InputChannel::receiveMessage(InputMessage* msg) {
        ssize_t nRead;
        do {
            nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
        } while (nRead == -1 && errno == EINTR);
    
        if (nRead < 0) {
            int error = errno;
            if (error == EAGAIN || error == EWOULDBLOCK) {
                return WOULD_BLOCK;
            }
            if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
                return DEAD_OBJECT;
            }
            return -error;
        }
    
        if (nRead == 0) { // check for EOF
            return DEAD_OBJECT;
        }
    
        if (!msg->isValid(nRead)) {
            return BAD_VALUE;
        }
        return OK;
    }
    

           可以看到,sendMessage()和receiveMessage()内部分别对应send()和recv(),从方法名可以看到,是通过socket进行传输的,接下来通过以下几个方面来对InputChannel进行分析:
           3.1.InputChannel是什么
           InputChannel本质是一对SocketPair(非网络套接字)。SocketPair用来实现在本机内进行进程间的通信。一对SocketPair通过socketpair()函数创建,其使用者可以因此而得到两个相互连接的文件描述符。这两个描述符可以通过套接字接口send()和recv()进行写入和读取,并且向其中一个文件描述符写入的数据,可以从另一个描述符中读取。同pipe()所创建的管道不同,SocketPair的两个文件描述符是双通的,因此非常适合用来进行进程间的交互式通信;
           3.2.创建InputChannel
           我们知道当一个Window需要显示时,最终都会调用到WMS的addWindow()方法:

    //WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int   viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,InsetsState outInsetsState) {
        ......
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
                        appOp[0], seq, attrs, viewVisibility, session.mUid,
                        session.mCanAddInternalSystemWindow);
        //仅当窗口的inputFeatures未指定INPUT_FEATURE_NO_INPUT_CHANNEL选项时才会为此窗口创建InputChannel对
        final boolean openInputChannels = (outInputChannel != null&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
        if  (openInputChannels) {
            win.openInputChannel(outInputChannel);
        }
        ......
    
        return res;
    }
    

           在内部创建WindowState代表具体的窗口,然后执行openInputChannel()方法:

    //WindowState.java
    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        if (outInputChannel != null) {
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        }
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }
    

           在openInputChannel()内部执行了三项工作:
           1.调用InputChannel的openInputChannelPair()来返回InputChannel[]数组,数组大小为2;
           2.将mInputChannel及mInputWindowHandle.inputChannel赋值为inputChannels[0],将mClientChannel赋值为inputChannels[1],然后执行transferTo转换为outInputChannel;
           3.执行registerInputChannel();
           先看openInputChannelPair()方法:

    //InputChannel.java
    public static InputChannel[] openInputChannelPair(String name) {
        .......
        return nativeOpenInputChannelPair(name);
    }
    

           该方法会调用nativeOpenInputChannelPair(),即native方法,路径位于frameworks/base/core/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;
    }
    

           可以看到,会调用 InputChannel::openInputChannelPair来创建serverChannel, clientChannel,然后创建数组channelPair,将serverChannel, clientChannel处理后存入数组,返回给java层,该逻辑实现代码路径为:frameworks/native/libs/input/InputTransport.cpp,一起看一下方法实现:

    status_t InputChannel::openInputChannelPair(const String8& name,
            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
        int sockets[2];
        //通过socketpair()函数创建一对无名的相互连接的socket,并保存在sockets数组中
        if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
            status_t result = -errno;
            ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                    name.string(), errno);
            outServerChannel.clear();
            outClientChannel.clear();
            return result;
        }
    
        //配置两个套接字的读写缓冲区尺寸。可以发送,可以接收
        int bufferSize = SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    
        //创建server端的InputChannel对象
        String8 serverChannelName = name;
        serverChannelName.append(" (server)");
        outServerChannel = new InputChannel(serverChannelName, sockets[0]);
    
        //创建client端的InputChannel对象
        String8 clientChannelName = name;
        clientChannelName.append(" (client)");
        outClientChannel = new InputChannel(clientChannelName, sockets[1]);
        return OK;
    }
    

           用一张流程图总结一下创建InputChannel过程:

    openInputChannel.png
           3.3.连接到InputDispatcher
           前面讲到,在WindowState的openInputChannel()方法中最后会执行mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle)来进行连接,一起看一下调用流程:
    //InputManagerService.java
    public void registerInputChannel(InputChannel inputChannel,
                InputWindowHandle inputWindowHandle) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null.");
        }
    
        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
    }
    

           在registerInputChannel()方法内部会调用nativeRegisterInputChannel(),会调用到native层,代码路径为:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp:

    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 (! monitor) {
            android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                    handleInputChannelDisposed, im);
        }
    }
    

           可以看到,在nativeRegisterInputChannel()方法内部会调用到NativeInputManager的registerInputChannel()方法:

    status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
            const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
        ATRACE_CALL();
        return mInputManager->getDispatcher()->registerInputChannel(
                inputChannel, inputWindowHandle, monitor);
    }
    

           通过InputManager最终调用到InputDispatcher的registerInputChannel()方法:

    status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) 
    
        {
            sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
    
            int fd = inputChannel->getFd();
            mConnectionsByFd.add(fd, connection);
    
            if (monitor) {
                mMonitoringChannels.push(inputChannel);
            }
    
            mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
        } 
    
        // Wake the looper because some connections have changed.
        mLooper->wake();
        return OK;
    }
    

           可以看到,在InputDispatcher的registerInputChannel()内部会执行四项工作:
           1.根据传入的inputChannel、inputWindowHandle等参数创建Connection实例;
           2.获取inputChannel的Fd,然后以键值对形式将fd及connection存入mConnectionsByFd中,后续在进行窗口事件派发时,会从该mConnectionsByFd里面查找到对应的Connection;
           3.执行mLooper->addFd,后续fd有数据收到时,会回调handleReceiveCallback方法;
           4.调用mLooper->wake();
           在前面InputDispatcher的事件派发中代码讲到,会根据目标窗口找到对应的InputWindowHandle,然后根据以下方式来找到对应的Connection,即从mConnectionsByFd中根据fd来匹配到对应的Connection,先注册后发送,前后对应起来了;

    ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
    if (connectionIndex >= 0) {
         sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
         prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
    }
    

           registerInputChannel()为InputChannel创建了一个Connection,并监听了InputChannel的可读事件,使得InputDispatcher拥有了将事件发送给InputChannel并接受反馈的能力。
           用一张流程图总结一下连接InputDispatcher过程:

    连接到Dispatcher.png
           3.4.连接到窗口
           前面分析到,在openInputChannelPair()时会创建一对InputChannel,一个是在addWindow()时通过registerInputChannel()时传入到InputDispatcher,另外一个是用来接收InputDispatcher传来的事件,是在窗口端,接下来一起看一下:
           窗口添加的入口是在ViewRootImpl,相关执行流程可以参考Android View 显示原理分析,看一下setView()方法:
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ......
        ......
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                       getHostVisibility(), mDisplay.getDisplayId(),
                       mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                       mAttachInfo.mOutsets, mInputChannel);
        ......
        ......
        if (mInputChannel != null) {
            ........
            mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
        }
        ......
    }
    

           当窗口端通过addWindow()函数获取InputChannel后,便会使用它创建一个InputEventReceiver对象。InputEventReceiver对象可以接收来自InputChannel的输入事件,并触发其onInputEvent()回调,看一下WindowInputEventReceiver的实现:

    final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
    
        @Override
        public void onInputEvent(InputEvent event, int displayId) {
            enqueueInputEvent(event, this, 0, true);
        }
    
        .......
    }
    

           WindowInputEventReceiver继承InputEventReceiver,在创建对象时调用了父类的构造方法,接下来看一下InputEventReceiver:

    private static native long nativeInit(WeakReference<InputEventReceiver> receiver,
                InputChannel inputChannel, MessageQueue messageQueue);
    
    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        ........
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                    inputChannel, mMessageQueue);
    
        mCloseGuard.open("dispose");
    }
    

           可以看到,在构造方法内部会执行nativeInit(),将inputChannel及messageQueue传入,返回NativeInputEventReceiver对象引用mReceivePtr,后续在事件处理完后调用finishInputEvent()发送完成消息时会用到,nativeInit()是native方法,会调用到native层,对应的实现代码路径为:frameworks/base/core/jni/android_view_InputEventReceiver.cpp

    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
            jobject inputChannelObj, jobject messageQueueObj) {
        sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);
        ......
    
        sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        ......
        sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
                receiverWeak, inputChannel, messageQueue);
        status_t status = receiver->initialize();
        ......
    
        receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
        return reinterpret_cast<jlong>(receiver.get());
    }
    

           创建了NativeInputEventReceiver对象携带inputChannel,然后执行initialize()方法,先看一下NativeInputEventReceiver构造方法:

    class NativeInputEventReceiver : public LooperCallback {
        .......
    }
    
    NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
            jobject receiverWeak, const sp<InputChannel>& inputChannel,
            const sp<MessageQueue>& messageQueue) :
            mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
            mInputConsumer(inputChannel), mMessageQueue(messageQueue),
            mBatchedInputEventPending(false), mFdEvents(0) {
    }
    

           NativeInputEventReceiver的构造函数很简单,它保存了java层InputEventReceiver对象的引用,并创建了一个InputConsumer类型的对象对InputChannel进行封装。
           InputConsumer与InputPublisher一样,它也封装了InputChannel,负责对其进行写入和读取操作,同时也负责InputMessage的封装与解析。不过它们的功能正好相反,InputConsumer接收的是输入事件,发送的则是反馈。
           接下来看一下initialize()方法:

    status_t NativeInputEventReceiver::initialize() {
        setFdEvents(ALOOPER_EVENT_INPUT);
        return OK;
    }
    
    void NativeInputEventReceiver::setFdEvents(int events) {
        if (mFdEvents != events) {
            mFdEvents = events;
            int fd = mInputConsumer.getChannel()->getFd();
            if (events) {
                mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
            } else {
                mMessageQueue->getLooper()->removeFd(fd);
            }
        }
    }
    

           在initialize()内部执行了setFdEvents(),然后在setFdEvents()内部获取到InputChannel的fd,然后通过Looper->addFd()对InputChannel的可读性事件进行监听,此时就已经连接到窗口了;
           用一张流程图总结一下连接窗口过程:


    连接到窗口.png

           当有InputMessage可读时,NativeInputEventReceiver的handleEvent()函数会被Looper调用,此时便可以通过InputConsumer从InputChannel中读取事件,然后回调到java层的onInputEvent()函数,在java层完成事件的处理后,便可通过InputConsumer发送处理完毕的反馈给InputDispatcher。
           接下来看一下handleEvent()是如何将事件传给java层的onInputEvent()方法:

    int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
        .......
        if (events & ALOOPER_EVENT_INPUT) {
            JNIEnv* env = AndroidRuntime::getJNIEnv(); 
            status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
            mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
            return status == OK || status == NO_MEMORY ? 1 : 0;
        }
        .....
    }
    

           在handleEvent()内部会调用到consumeEvents():

    status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
            bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
        ......
        for (;;) {
            ......
    
            InputEvent* inputEvent;
            int32_t displayId;
            status_t status = mInputConsumer.consume(&mInputEventFactory,
                    consumeBatches, frameTime, &seq, &inputEvent, &displayId,
                    &motionEventType, &touchMoveNum, &flag);
    
            .......
    
            case AINPUT_EVENT_TYPE_MOTION: {
                MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
                if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
                    *outConsumedBatch = true;
                }
                inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
                break;
            }
    
            if (inputEventObj) {
                .....
                env->CallVoidMethod(receiverObj.get(),
                         gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj,
                         displayId);
                    .......
                    env->DeleteLocalRef(inputEventObj);
                }
        ......
    }
    

           在consumeEvents()内部主要做了三项工作:
           1.调用InputConsumer的consume()从InputChannel中读取一条InputMessage,解析为InputEvent后通过inputEvent参数传出;InputConsumer的实现也是在InputTransport.cpp中,跟InputPublisher对应;
           2.根据事件的类型分别创建KeyEvent与MotionEvent类型的java对象;
           3.通过JNI回调java层的InputEventReceiver的dispatchInputEvent()函数;

    4.InputConsumer

           前面第一项工作中涉及到InputConsumer,该类的实现路径为:frameworks/native/libs/input/InputTransport.cpp,该类是和InputPublisher对应的,一个来发送,一个来消费处理,处理完毕后发送finish signal;

           接着上面进行分析,再看一下Java层的处理:

    private void dispatchInputEvent(int seq, InputEvent event, int displayId) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event, displayId);
    }
    

           dispatchInputEvent函数首先在字典中保存来自InputDispatcher的事件序列号,以满足发送反馈之需。之后便调用onInputEvent()函数,交由子类进行输入事件的实际处理工作。onInputEvent()函数可由使用者重写,从而实现各种各样的工作,Android控件根ViewRootImpl在收到事件后会将其派发给特定的控件。

    5.简单总结

           1.事件发送主要是通过InputChannel来完成;
           2.在wms 执行addView()时,调用openInputChannel来从native层获取inputchannels数组,一个通过ims registerInputChannel来连接InputDispatcher,另外一个通过InputEventReceiver来连接窗口;
           3.InputDispatcher经过Connection最终通过InputPublisher将事件发送到目标窗口;
           4.NativeInputEventListener监听到事件到来时通过InputConsumer处理InputMessage后回调Java层接口;

           到这里事件就已经发送到对应的窗口了,接下来看一下事件的处理Android IMS原理解析之processEvent

    相关文章

      网友评论

          本文标题:Android IMS原理解析之InputChannel

          本文链接:https://www.haomeiwen.com/subject/rueuiltx.html