Android输入系统之InputChannel

本文详细解析了Android系统的输入事件处理流程,包括事件的读取、处理与分发过程。重点介绍了InputChannel的作用及其实现原理,以及如何通过Unix Socket进行跨进程通信,确保应用程序能够正确接收并响应用户输入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

已经分析了输入事件的读取,处理,分发。我们知道事件的传递是以window为单位传递的,即server只负责将事件传递给某一个或者多个window,window然后再将事件传递给某一个具体的view。一个activity或者dialog对应一个window,但是事件只传递给合适的window,比如对于按键事件,就必须是获得焦点的window,也就是说只能传递给一个window,通常是最上面的程序。找到了合适的window,然后就是将事件添加到window的Connection的事件队列上。其实,到这为止输入事件还只是在server端,即system_server这个进程里,要想让程序获取到事件,肯定必须将事件信息传递到程序端的进程里。这个就是Connection的实现问题了,这个connection的真正逻辑是InputChannel, InputChannel其实就是Linux unix socket的一种封装, unixsocket是linux的一种跨进程通信方式。系统创建InputChannel对即unix socket对,系统server端和程序client各只有其中一个,这样通过unix socket就可以给对方发送消息,而这里的事件就是通过这种方式从系统进程传递到程序进程的。

Server端 InputChannel的创建,首先在window创建一个ViewRootImpl,然后调用ViewRootImpl.java中setView函数

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
       mInputChannel = new InputChannel(); 
       res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(),mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
     mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); 
}

创建一个InputChannel,并没有初始化。然后传给mWindowSession.addToDisplay函数。addToDisplay函数最终调用了WindowManagerService.java中addWindow函数

public int addWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int viewVisibility, int displayId,Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
         win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

    String name = win.makeInputChannelName();
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    win.setInputChannel(inputChannels[0]);
    inputChannels[1].transferTo(outInputChannel);
    mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}            

在ViewRootImpl中创建一个WindowState,用于存放InputChannel,便于以后调用InputChannel与InputDispatcher线程的InputChannel通信。
接下来InputChannel.openInputChannelPair函数:

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

调用 (JNI)android_view_InputChannel.cpp中android_view_InputChannel_nativeOpenInputChannelPair函数

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

在android_view_InputChannel_nativeOpenInputChannelPair函数中调用InputChannel::openInputChannelPair函数:

status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    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));

    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

创建一对sockets,用于进程间通信。并创建一个outServerChannel,另一个outClientChannel。分别把sockets放入outServerChannel和outClientChannel中。然后返回去给serverChannel和clientChannel。

 jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);  
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

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

接着创建一个java用的InputChannel二维数组,分别用于存放java层创建出来的serverChannelObj和clientChannelObj。返回到addWindow后,InputChanne[0]先存入WindowState中,然后把InputChanne[1]传给java层的ViewRootImpl中。

 public void transferTo(InputChannel outParameter) {
        nativeTransferTo(outParameter);
    }

调用(JNI)android_view_InputChannel.cpp中android_view_InputChannel_nativeTransferTo:

static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {

    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}

把nativeInputChannel地址放入outInputChannel类中的成员变量mPtr中。其中nativeInputChannel中包含有sockets。所以nativeInputChannel中InputChannel传给了java层ViewRootImpl中的mInputChannel中。
看看mInputManager.registerInputChannel函数

public void registerInputChannel(InputChannel inputChannel,
            InputWindowHandle inputWindowHandle) {
        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
    }

调用 (JNI)com_android_server_input_InputManagerService.cpp中
nativeRegisterInputChannel函数:

static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
}

调用 了NativeInputManager中registerInputChannel函数:

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

调用了InputDispatcher.cpp中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);   
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    mLooper->wake();
    return OK;
}

创建一个Connection,放入mConnectionsByFd队例中。前面《Android 5.0输入系统分析之InputDispatcher线程分析》中有从mConnectionsByFd中取出Connection,所以这Connection就是在这里放入mConnectionsByFd队例。从inputChannel中取出fd,然后调用 mLooper->addFd函数:

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {

    int epollEvents = 0;
    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;

    { // acquire lock
        AutoMutex _l(mLock);

        Request request;
        request.fd = fd;
        request.ident = ident;
        request.callback = callback;
        request.data = data;

        struct epoll_event eventItem;
        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
        eventItem.events = epollEvents;
        eventItem.data.fd = fd;

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
                return -1;
            }
            mRequests.add(fd, request);
        } else {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
            if (epollResult < 0) {
                ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
                return -1;
            }
            mRequests.replaceValueAt(requestIndex, request);
        }
    } // release lock
    return 1;
}

把fd,ident,callback等数据存入Request中。然后把fd加入epoll中监听。准备好后,用mLooper->wake()唤醒了InputDispatcher线程接收APP处理后返回来的信息,实际调用 pollOnce函数:

int Looper::pollInner(int timeoutMillis) {
      int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
      Response& response = mResponses.editItemAt(i);
       int callbackResult = response.request.callback->handleEvent(fd, events, data);
}

当接收到APP返回来的数据后,从mResponses中取出fd,ident,callback等数据,然后调用 callback函数,实际就是InputDispatcher.cpp中handleReceiveCallback函数:

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);
    { 
        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);

        bool notify;
        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);

            for (;;) {
                uint32_t seq;
                bool handled;
                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);

                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                gotOne = true;
            }      
        } 
        d->unregisterInputChannelLocked(connection->inputChannel, notify);
        return 0; // remove the callback
    } 
}

从mConnectionsByFd队例中取出Connection,然后调用 Connection里的inputPublisher.receiveFinishedSignal来接收APP返回来的数据

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
    InputMessage msg;
    status_t result = mChannel->receiveMessage(&msg);
    return OK;
}

调用 了InputTransport.cpp中receiveMessage函数:

status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    do {
        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);
    return OK;
}

用recv接收APP返回的数据存入InputMessage中。

status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
        bool notify) {
    ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
    mConnectionsByFd.removeItemsAt(connectionIndex);
    if (connection->monitor) {
        removeMonitorChannelLocked(inputChannel);
    }
    mLooper->removeFd(inputChannel->getFd());
     return OK;
}

完成后从mConnectionsByFd队例中删除Connection。可以知道 InputDispatcher线程做二件事,第一件事:从InputReader读到的数据分发给焦点窗口;第二件事:接收焦点窗口处理后返回的数据。那么焦点窗口是谁来接收,又由谁来处理,又怎么发给InputDispatcher线程?

继续向下分析ViewRootImpl.java中的setView函数。

  mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());

创建一个WindowInputEventReceiver,调用WindowInputEventReceiver构造函数:

 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

调用子InputEventReceiver的构造函数:

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

调用 (JNI)android_view_InputEventReceiver.cpp中nativeInit函数:

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();
    return reinterpret_cast<jlong>(receiver.get());
}

从java层获得一个InputChannel,上面有分析这个InputChannel。然后创建一个NativeInputEventReceiver,调用了NativeInputEventReceiver里的initialize函数:

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}

调用:

void NativeInputEventReceiver::setFdEvents(int events) {
      int fd = mInputConsumer.getChannel()->getFd();
       mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
}

从InputChannel中取出fd,传给mMessageQueue->getLooper()->addFd,这个实际就是调用了Looper.cpp中addFd函数,addFd函数与上面有分析过addFd过程一样,这就不再分析了。
APP层会调用 Looper.cpp中pollOnce函数,pollOnce函数也是与上面pollOnce函数的分析一样,也是调用 callback函数里handleEvent,这个callback函数实际就是android_view_InputEventReceiver.cpp中handleEvent函数:

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {   
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);

    return 1;
}

调用android_view_InputEventReceiver.cpp中consumeEvents函数:

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
        env->CallVoidMethod(receiverObj.get(),                      gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);  
 }

调用java层的InputEventReceiver.java中dispatchInputEvent函数:

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

最后调用WindowInputEventReceiver中onInputEvent函数:

 public void onInputEvent(InputEvent event) { //onInputEvent
            enqueueInputEvent(event, this, 0, true);
        }

直接调用 enqueueInputEvent函数:

void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }

最后调用了doProcessInputEvents函数:

 void doProcessInputEvents() {
     QueuedInputEvent q = mPendingInputEventHead;
      mPendingInputEventHead = q.mNext;
     deliverInputEvent(q);
 }

从队例头中取出数据,调用deliverInputEvent函数处理

 private void deliverInputEvent(QueuedInputEvent q) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                q.mEvent.getSequenceNumber());

        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }

从q.shouldSkipIme()检查是第一次的还是上一次的,如果InputStage存在,那么调用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));
            }
        }

检查是否处理了,如果处理了调用 forward函数,如果处理完成了调用finish函数,否则没处理,调用onProcess函数:

  protected int onProcess(QueuedInputEvent q) {
            return FORWARD;
        }

最终APP调用 了onProcess函数来处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值