天天看点

06.输入系统:第10课第14节_输入系统_APP获得并处理输入事件流程

从之前小节我们知道Dispatcher线程是如何分发事件给APP的,该小节我们讲解APP如何获取,并且处理这些输入事件。在前面的小节中,提到APP在得到一个fd之后,会把他封装成一个InputChannel,然后再封装成windowInputEvenReceiver,最终把fd注册到Looper中,使用epoll进行查询等待,该小节我们详细的分析fd注册到Looper的过程,APP调用总的详细框图如下:

06.输入系统:第10课第14节_输入系统_APP获得并处理输入事件流程

fd事件注册

在应用程序中,对于文件句柄fd,InputChannel的注册是从框图中ViewRootImpl.java文件,的setView方法中的WindowInputEventReceiver开始,其ViewRootImpl.java文件的调用过程如下:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
 	public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
 		/*从调用.addToDisplay方法获取mInputChannel*/	
 		res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);
 			/*注册fd,或者说InputChannel,因为fd被包含在InputChannel中*/
        	mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper(); 			
           

现在我们从WindowInputEventReceiver(mInputChannel,Looper.myLooper()开始分析,先查看

WindowInputEventReceiver这个类包含了什么

final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

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

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }

           

从上面我们可以看到,WindowInputEventReceiver继承于InputEventReceiver,然后重写了onInputEvent(InputEvent event),onBatchedInputEventPending(),dispose()三个方法。当接收到事件的时候,onInputEvent方法会被调用。

既然WindowInputEventReceiver继承于InputEventReceiver,那么当创建WindowInputEventReceiver实例化对象的时候,InputEventReceiver的构造方法肯定会被调用。我们可以看到InputEventReceiver中包含如下函数:

private void dispatchInputEvent(int seq, InputEvent event) {
	onInputEvent(event);
           

从上分析,子类WindowInputEventReceiver中的onInputEvent方法,应该是被父类InputEventReceiver的dispatchInputEvent方法调用的,

再来看看InputEventReceiver的构造函数,

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

该处的nativeInit会调用android_view_InputEventReceiver.cpp中的:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,jobject inputChannelObj, jobject messageQueueObj) {
	sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);	
           

这样就从java到cpp文件了,在android_view_InputEventReceiver.cpp文件中,存在函数:

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
	/*最终调用java中的dispatchInputEvent方法*/
	env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
           

我们再次回到android_view_InputEventReceiver.cpp的 nativeInit函数:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobjectreceiverWeak,jobject inputChannelObj, jobject messageQueueObj) {
	/*获取一个NativeInputEventReceiver类型的实例化对象*/
	sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);
		/*通过其实例化对象,调用initialize()函数*/
	 	status_t status = receiver->initialize();
	 		/*该处就是把InputChannel的fd注册到Looper*/
	 		setFdEvents(ALOOPER_EVENT_INPUT);
	 			/*InputChannel从获取fd*/
	 			int fd = mInputConsumer.getChannel()->getFd();
	 			/*添加到Looper,注意该处的第3个参数是this,表示当前这个实例化对象,即
	 			receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);	*/
	 			mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
           

现在我们打开SDK/system/core/libutils/looper.cpp文件,在其类可以找打两个Looper::addFd函数:

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

根据两个函数倒数第二个参数,前面的为一个函数指针,第二个为一个实LooperCallback例化对象,但是我们之前通过receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue)并非LooperCallback例化对象,那么可以猜测到NativeInputEventReceiver为LooperCallback的一个派生类。

在android_view_InputEventReceiver.cpp可以看到如下:

这样就证明了我们的猜测,那么他调用的就是第二个int Looper::addFd,

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
	/*构建一个Reques*/
	Request request;
	request.fd = fd;
	/*调用该函数,添加到epoll_ctl之中*/
	int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
	
           

这样,就可以使用epoll,对输入事件进行监测了。

我们来看看LooperCallback包含呢那些东西:

该 handleEvent会调用派生类中的consumeEvents,这样注册部分就讲解完成,下面我们来看看APP获取事件的流程。

获取事件

再次打开Looper.cpp,在其了存在:

int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
	result = pollOnce(timeoutMillis, outFd, outEvents, outData);
		result = pollInner(timeoutMillis);
			/*等待fd动作*/
			eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
				/*根据返回结果,取出若干个事件*/
				for (int i = 0; i < eventCount; i++) {
       				 int fd = eventItems[i].data.fd;
       			/*通过fd取出在注册时构建的requestIndex*/
				ssize_t requestIndex = mRequests.indexOfKey(fd);
				/*存放在某个缓存中*/
				pushResponse(events, mRequests.valueAt(requestIndex));
			/*从缓存逐个取出esponse,逐个处理*/
    		for (size_t i = 0; i < mResponses.size(); i++) {
    			/*Response中包含呢request*/
        		Response& response = mResponses.editItemAt(i);
        		/*此处的callback指向的是之前的receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);
        		该处的andleEvent,即为LooperCallback中的virtual int handleEvent(int fd, int events, void* data) = 0*/
				int callbackResult = response.request.callback->handleEvent(fd, events, data);				
           

我们查看android_view_InputEventReceiver.cpp中实现的handleEvent:

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
	 status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
	 	/*调用InputEventReceiver.java中的dispatchInputEvent*/
	 	env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
           

然后在InputEventReceiver.java中的dispatchInputEvent:

private void dispatchInputEvent(int seq, InputEvent event) {
	/*该具体方法,为派生类实现的*/
	onInputEvent(event);
           

现在我们来查看ViewRootImpl.java中实现的onInputEvent:

public void onInputEvent(InputEvent event) {
	enqueueInputEvent(event, this, 0, true);//放入队列
		void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {
			 doProcessInputEvents();//处理众多的事件
			 	deliverInputEvent(q);//传输事件
			 		/*把事件分为多个阶段*/
			 		InputStage stage;
           

其上事件的阶段处理详细阶梯图如下:

06.输入系统:第10课第14节_输入系统_APP获得并处理输入事件流程

现在我们对这个阶梯图进行讲解,在最开始提到WindowInputEventReceiver是java层面对输入事件处理的总入口,他会调用onInputEvent,在根据之前分析从onInputEvent到deliverInputEvent,deliverInputEvent会把输入事件分为多个阶段,

1.NativePrelme与ViewPrelme为输入法之前,对输入事件的处理。

2.lme对输入法的处理

3.EarlyPostime到viewPostime为输入法之后做的处理

4.Synthetic为对事件综合的处理

如果你的应用程序不使用输入法,他会从3开始处理,如果使用输入法,从1开始处理。

应用程序可能是C++编写,也可能是java编写,

c++:使用Native Activity处理

java:使用View-onKeyDown()处理

在框图右边的部分,都处于一个链表,我们看看这个链表是如何创建出来的:

在ViewRootImpl.java可以找:

CharSequence counterSuffix = attrs.getTitle();
	mSyntheticInputStage = new SyntheticInputStage();
	InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
	InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
	        "aq:native-post-ime:" + counterSuffix);
	InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
	InputStage imeStage = new ImeInputStage(earlyPostImeStage,
	        "aq:ime:" + counterSuffix);
	InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
	InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
	        "aq:native-pre-ime:" + counterSuffix);
           

该处我们可以看待先创建Synthetic,然后他当做参数传入ViewPostImeInputStage…依此递推,就创建一个链表出来。

知道链表怎么创建之后,我们再回到deliverInputEvent:

private void deliverInputEvent(QueuedInputEvent q) {
	if (q.shouldSendToSynthesizer()) {
		/*判断是否能够忽略输入法,从图示对应位置开始执行*/
		stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
		stage.deliver(q);//为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));//没有结束,也不能抛弃,这执行该函数
 	        } 
           

从上可知,每个阶段进行处理的时候,只有3个结果

1.如果已经完成,进入下一阶段

2.设置标志位为finish,传递给下一阶段

3.调用onProcess函数处理,处理完成传递给下一个stage

下一小节再继续详细分析

继续阅读