Android输入管理2:应用进程处理Input消息过程

355 阅读10分钟

在上一篇文章Android输入管理1:输入信息分发中,我们讲述了信息从获取到分发过InputChannel的过程。接下来我们再介绍一下InputChannel的创建以及如何通过InputChannel将消息分发到应用中去。

InputChannel的创建

首先生成应用进程中的InputChannel对象,看看ViewRootImpl类的setView方法

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	...
    if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
        mInputChannel = new InputChannel();
     }
     mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
     try {
     	mOrigWindowType = mWindowAttributes.type;
     	mAttachInfo.mRecomputeGlobalAttributes = true;
     	collectViewAttributes();
     	res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
     	setFrame(mTmpFrame);
     } catch (RemoteException e) {
     	mAdded = false;
        mView = null;
        mAttachInfo.mRootView = null;
        mInputChannel = null;
        mFallbackEventHandler.setView(null);
        unscheduleTraversals();
        setAccessibilityFocus(null, null);
        throw new RuntimeException("Adding window failed", e);
     } finally {
     	if (restore) {
        	attrs.restore();
        }
     }
	...
}

在setView方法中如果mWindowAttributes.inputFeatures变量中没有WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL标记,表示能接收输入,则创建java层InputChannel对象,并赋值给类变量mInputChannel,在接下来调用mWindowSession.addToDisplay方法时,作为参数传入其中,然后传递到WindowManagerService中,调用它的addWindow方法。如下:

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 boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
    if  (openInputChannels) {
		//win是WindowState类的对象
    	win.openInputChannel(outInputChannel);
    }

	...
}

// WindowState 的win.openInputChannel 方法
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.token = mClient.asBinder();
    if (outInputChannel != null) {
        mClientChannel.transferTo(outInputChannel);
        mClientChannel.dispose();
        mClientChannel = null;
    } else {
        // If the window died visible, we setup a dummy input channel, so that taps
        // can still detected by input monitor channel, and we can relaunch the app.
        // Create dummy event receiver that simply reports all events as handled.
        mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
    }
    mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
}

addWindow方法调用WindowState类的openInputChannel方法。在openInputChannel方法中: 1.先通过InputChannel.openInputChannelPair(name)创建一个InputChannel数组对象,其中包含2个InputChannel对象。

2.inputChannels[1]赋值给mClientChannel变量,并转换成和客户端传递过来的outInputChannel对象。

3.inputChannels[0]赋值给mInputChannel变量,调用mWmService.mInputManager.registerInputChannel方法注册InputChannel对象。这个registerInputChannel方法在上篇文章《Android输入管理1:输入信息分发》中消息分发一节已经有描述,在该方法中把InputChannel对象和新创建的Connection绑定,这样就可以通过Connection找到对应的InputChannel对象来分发消息。

下面看看InputChannel.openInputChannelPair方法创建InputChannel[]数组的过程

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

//nativeOpenInputChannelPair 本地方法代码
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();

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

openInputChannelPair方法调用了本地方法nativeOpenInputChannelPair。在本地方法nativeOpenInputChannelPair中: 1.调用native方法InputChannel::openInputChannelPair创建出本地InputChannel对象serverChannel和clientChannel。 2.将serverChannel和clientChannel作为参数,调用android_view_InputChannel_createInputChannel函数创建java层的InputChannel对象 3.将创建的java层InputChannel类的对象serverChannelObj和clientChannelObj设置到数组channelPair中并返回。

在来看看InputChannel::openInputChannelPair方法是如何创建InputChannel对象的。

status_t InputChannel::openInputChannelPair(const std::string& 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.c_str(), 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));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

InputChannel::openInputChannelPair首先创建一对socket,sockets[0]和sockets[1]。再new InputChannel对象,并将socket对象传入其中。sockets[0]对应outServerChannel,sockets[1]对应outClientChannel。这样InputChannel对象就和socket对应起来。后续通过InputChannel类的sendMessage函数发送消息,事实上是通过socket发送数据出去,这个后面我们再分析。 生成完native层的InputChannel对象后,再来看看android_view_InputChannel_createInputChannel函数,如何创建java层InputChannel对象。

static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
        std::unique_ptr<NativeInputChannel> nativeInputChannel) {
    jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
            gInputChannelClassInfo.ctor);
    if (inputChannelObj) {
        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
                 nativeInputChannel.release());
    }
    return inputChannelObj;
}

//android_view_InputChannel_setNativeInputChannel函数
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
        NativeInputChannel* nativeInputChannel) {
    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
             reinterpret_cast<jlong>(nativeInputChannel));
}

上面代码,通过env->NewObject函数生成inputChannelObj对象,并且在android_view_InputChannel_setNativeInputChannel函数中,将传入的NativeInputChannel对象,设置inputChannelObj对象的mPtr变量中。NativeInputChannel对象在调用android_view_InputChannel_createInputChannel函数时以参数的形式传入。而NativeInputChannel对象则是根据生成的InputChannel对象,调用make_unique来构建的。 所以这时各个类的关系就很清晰了。java层的inputChannelObj对象的mPtr变量引用了native层的NativeInputChannel对象,NativeInputChannel对象则通过变量mInputChannel引用native层的InputChannel对象,而native层的InputChannel对象又通过变量mFd引用socket对象。

以上即是InputChannel的生成过程。

总结图如下:

InputChannel 创建.jpg

应用程序与输入管理服务建立通信过程

应用程序如何和输入管理服务建立通信的?上面创建过程用到了一个函数socketpair,该函数用于创建一对无名的、相互连接的套接字。也就是说通过socketpair函数,创建sockets[0]和sockets[1]之后,这对socket就可以双向通信了。sockets[0]作为服务端,随着创建的InputChannel的对象,被注册到InputManager中,用于在接收到输入消息后,找到合适的InputChannel发送信息。 sockets[1]做为客户端是如何给到应用程序的?

WindowState的win.openInputChannel方法中会调用inputChannels[1]的transferTo方法,而且以客户端传递的 outlnputChannel 作为参数。代码如下:

public void transferTo(InputChannel outParameter) {
	if (outParameter == null) {
		throw new IllegalArgumentException("outParameter must not be null");
	}
	nativeTransferTo(outParameter);
}
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
        return;
    }

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

函数功能:把调用对象的mPtr中的值放到参数对象的mPtr中,并将调用对象的mPtr设置为NULL。transferTo执行后,outlnputChannel的mPtr指针保存的就是native层创建的InputChannel对象的指针。这样客户端传递的outlnputChannel对象就间接引用了socket[1]。outInputChannel是一个返回参数,我们看一下它的readFromParcel实现

public void readFromParcel(Parcel in) {
	if (in == null) {
		throw new IllegalArgumentException("in must not be null");
	}
	nativeReadFromParcel(in);
}
static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
        jobject parcelObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "This object already has a native input channel.");
        return;
    }

    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel) {
        bool isInitialized = parcel->readInt32();
        if (isInitialized) {
            InputChannel* inputChannel = new InputChannel();
            inputChannel->read(*parcel);

            NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);

            android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
        }
    }
}
	
//InputChannel的read函数
status_t InputChannel::read(const Parcel& from) {
    mName = from.readString8();
    mToken = from.readStrongBinder();

    int rawFd = from.readFileDescriptor();
    setFd(::dup(rawFd));

    if (mFd < 0) {
        return BAD_VALUE;
    }

    return OK;
}

//InputChannel的setFd函数
void InputChannel::setFd(int fd) {
    if (mFd > 0) {
        ::close(mFd);
    }
    mFd = fd;
    if (mFd > 0) {
        int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
        LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
            "non-blocking.  errno=%d", mName.c_str(), errno);
    }
}

应用程序客户端调用outInputChannel的readFromParcel函数。其作用:

1.获取服务端传递过来的保存数据的parcel对象

2.创建客户端InputChannel对象,并且通过Parcel数据读取socket的句柄rawFd,在将rawFd复制一个设置到InputChannel对象的mFd变量中。

3.生成NativeInputChannel对象并将该对象引用设置到客户端的InputChannel对象的mPtr中。

通过上面的操作,应用客户端就获取到了来着服务端的soket句柄,而这个soket句柄即是之前在服务端设置的socket[1]。这样应用端和服务器端就建立了socket通信链接。

然后就可以通过服务端发送输入消息给应用程序客户端。

应用接收Input消息

回到InputManagerService中,输入消息会传递到InputChannel的sendMessage中(具体传递过程可以查看在上篇文章<<Android输入管理1:输入信息分发>>)

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

	...

    return OK;
}

sendMessage通过系统调用send函数发送输入消息,这样输入消息通过socket就传递到用户进程中。而用户进程如何接收socket传过来的消息? 回到ViewRootImpl的setView函数在调用addToDisplay函数后,创建WindowInputEventReceiver对象

if (mInputChannel != null) {
	if (mInputQueueCallback != null) {
		mInputQueue = new InputQueue();
		mInputQueueCallback.onInputQueueCreated(mInputQueue);
	}
	mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
}

WindowInputEventReceiver继承了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");
}

在这个构造方法中,将传进来的客户端inputChannel设置给mInputChannel变量。再通过当前线程的looper对象获取其消息队列。然后将它们作为参数传给nativeInit方法。nativeInit方法生成了native层的NativeInputEventReceiver对象的引用保存到mReceiverPtr变量中。

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        jniThrowRuntimeException(env, "InputChannel is not initialized.");
        return 0;
    }

    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize input event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }

    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

nativeInit函数通过获取本地inputChannel 和 本地消息队列messageQueue,做为参数传递给生成的NativeInputEventReceiver。然后调用NativeInputEventReceiver的initialize函数,如下:

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

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

setFdEvents函数获取inputChannel对象的fd,然后调用addFd设置到消息队列对应的loop中。下面看看loop代码

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

    { // acquire lock
        AutoMutex _l(mLock);

        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.seq = mNextRequestSeq++;
        request.callback = callback;
        request.data = data;
        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1

        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            mRequests.add(fd, request);
        } else {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {
                    // Tolerate ENOENT because it means that an older file descriptor was
                    // closed before its callback was unregistered and meanwhile a new
                    // file descriptor with the same number has been created and is now
                    // being registered for the first time.  This error may occur naturally
                    // when a callback has the side-effect of closing the file descriptor
                    // before returning and unregistering itself.  Callback sequence number
                    // checks further ensure that the race is benign.
                    //
                    // Unfortunately due to kernel limitations we need to rebuild the epoll
                    // set from scratch because it may contain an old file handle that we are
                    // now unable to remove since its file descriptor is no longer valid.
                    // No such problem would have occurred if we were using the poll system
                    // call instead, but that approach carries others disadvantages.
#if DEBUG_CALLBACKS
                    ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
                            "being recycled, falling back on EPOLL_CTL_ADD: %s",
                            this, strerror(errno));
#endif
                    epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
                    if (epollResult < 0) {
                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                fd, strerror(errno));
                        return -1;
                    }
                    scheduleEpollRebuildLocked();
                } else {
                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
                    return -1;
                }
            }
            mRequests.replaceValueAt(requestIndex, request);
        }
    } // release lock
    return 1;
}

通过Loop的addFd函数可以看到,参数fd加入到Looper对象的epoll监控中,在mRequests队列中加入Request对象。这个对象的events成员带有EPOLLIN标记,它的callback成员变量指向NativeInputEventReceiver对象,而NativeInputEventReceiver继承自LooperCallback。这就监听了接收端的socket,有消息进来就会调用对应的callback。当有消息时,线程处理消息循环会调用Looper的pollOnce()函数,pollOnce()调用pollInner()函数。


int Looper::pollInner(int timeoutMillis) {
	
	...

    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    // We are about to idle.
    mPolling = true;
	
	 //等待事件到来 
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // No longer idling.
    mPolling = false;

    // Acquire lock.
    mLock.lock();

	...

    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd.get()) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
			//获得有消息的 fd 在 mRequests 中的 index
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;

				//插入到 mResponses 列表中 
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }

	...

    // Release lock.
    mLock.unlock();
	//处理 mResponses 列表中所有元素 
    // Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                    this, response.request.callback.get(), fd, events, data);
#endif
            // Invoke the callback.  Note that the file descriptor may be closed by
            // the callback (and potentially even reused) before the function returns so
            // we need to be a little careful when removing the file descriptor afterwards.

			//调用 callback 指针的 handleEvent

            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }

            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

pollInner函数做了一下处理:

1.调用epoll_wait等待事件到来

2.循环处理到来的消息事件,在mRequests中根据fd得到它所属的Reuest对象的index.

3.调用pushResponse把events和根据index获取的Reuest对象加入mResponses列表中

4.处理mResponses中所有的item,并调用他们的callback对象的handleEvent函数处理消息。

callback->handleEvent中的callback即为之前传入的NativeInputEventReceiver对象,它的handleEvent函数代码如下:

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
        // This error typically occurs when the publisher has closed the input channel
        // as part of removing a window or finishing an IME session, in which case
        // the consumer will soon be disposed as well.
        if (kDebugDispatchCycle) {
            ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                    "events=0x%x", getInputChannelName().c_str(), events);
        }
        return 0; // remove the callback
    }

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

	...
   
    return 1;
}


// consumeEvents 函数

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
		
	...

    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;

		//从 InputChannel 的 socket 中读取消息 

        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
		....

            if (inputEventObj) {
                if (kDebugDispatchCycle) {
                    ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
                }

				//调用 WindowInputEventReceiver 的 dispatchInputEvent 方法 
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching input event.");
                    skipCallbacks = true;
                }
                env->DeleteLocalRef(inputEventObj);
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.",
                        getInputChannelName().c_str());
                skipCallbacks = true;
            }
        }

	....

}

handleEvent函数在参数 events 中带有标记 ALOOPER_EVENT_INPUT 时,调用 consumeEvents ()函数继续处理, consumeEvents中做了一下处理:

1.consumeEvents会循环调用mInputConsumer.consume函数。mInputConsumer包含了前面创建的InputChannel对象。 2.mInputConsumer.consume中调用InputChannel的receiveMessage函数,从InputChannel的socket中读取输入信息。 3.得到获取的信息后,调用java层的 WindowInputEventReceiver 的 dispatchInputEvent 方法。这个方法最终调用onInputEvent方法

	
//InputEventReceiver类的dispatchInputEvent 方法
// Called from native code.
@SuppressWarnings("unused")
@UnsupportedAppUsage
private void dispatchInputEvent(int seq, InputEvent event) {
	mSeqMap.put(event.getSequenceNumber(), seq);
	onInputEvent(event);
}


//WindowInputEventReceiver类的onInputEvent方法
@Override
public void onInputEvent(InputEvent event) {
	Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
	List<InputEvent> processedEvents;
	try {
		processedEvents = mInputCompatProcessor.processInputEventForCompatibility(event);
	} finally {
		Trace.traceEnd(Trace.TRACE_TAG_VIEW);
	}
	if (processedEvents != null) {
		if (processedEvents.isEmpty()) {
			// InputEvent consumed by mInputCompatProcessor
			finishInputEvent(event, true);
		} else {
			for (int i = 0; i < processedEvents.size(); i++) {
				enqueueInputEvent(processedEvents.get(i), this,
                                QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
			}
		}
    } else {
    	enqueueInputEvent(event, this, 0, true);
   	}
}
	

onInputEvent调用了ViewRootImpl的enqueueInputEvent方法保存消息。这样Event消息终于到达应用中拥有焦点的Activity的ViewRootImpl对象。至此来自服务的输入消息被发送到了应用程序。后续的处理就开始了应用程序的消息分发过程,限于本文篇幅就不再详述了。

总结主要过程:

应用进程处理Input消息过程.jpg

源码路径:

源码基于android 10.0

InputChannel(java):frameworks/base/core/java/android/view/InputChannel.java

NativeInputChannel(c++):在android_view_InputChannel.cpp中定义

android_view_InputChannel.cpp:frameworks/base/core/jni/android_view_InputChannel.cpp

InputChannel (c++):在InputTransport.cpp中定义

InputConsumer:在InputTransport中定义

InputTransport:frameworks/native/libs/input/InputTransport.cpp

InputEventReceiver:frameworks/base/core/java/android/view/InputEventReceiver.java

NativeInputEventReceiver: 在android_view_InputEventReceiver中定义

android_view_InputEventReceiver: frameworks/base/core/jni/android_view_InputEventReceiver.cpp

上一篇:# Android输入管理1:输入信息分发