InputManagerService分析(2)

這篇文章補充了之前文章中沒有的view初始化的流程分析。本文詳細的分析了input event是通過何種方式傳遞到activity以及從驅動中讀取到event後,jni是如何對按鍵進行上報的過程。通過本文的分析,能夠基本上了解按鍵的整個傳遞過程。

View的初始化

在啓動一個activity時將會調用ViewRootImpl.setView()函數。下面將這個函數中的主要部分給出:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	····
	if ((mWindowAttributes.inputFeatures
			& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
		//這個對應client端,將InputEvent傳遞給view
		mInputChannel = new InputChannel();
	}
	try {
		mOrigWindowType = mWindowAttributes.type;
		mAttachInfo.mRecomputeGlobalAttributes = true;
		collectViewAttributes();
		res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
				getHostVisibility(), mDisplay.getDisplayId(),
				mAttachInfo.mContentInsets, mInputChannel);
	} catch (RemoteException e) {}
	···
	if (mInputChannel != null) {
		if (mInputQueueCallback != null) {
			mInputQueue = new InputQueue();
			mInputQueueCallback.onInputQueueCreated(mInputQueue);
		}
	//mInputChannel註冊到native層
	mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
			Looper.myLooper());
	}
	···
}

上面段代碼中主要進行了三個動作:
1.創建一個Java層的InputChannel,這個InputChannel後面用來創建兩個socket,一個是client端,app使用它接收按鍵信息;一個是server端,底層將按鍵信息寫入server端
2.調用WindowSession.addToDisplay,向系統中添加session
3.註冊WindowInputEventReceiver,當client端有消息時,通知view來消息。

下面看一下WindowSession.addToDisplay的實現

@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
		int viewVisibility, int displayId, Rect outContentInsets,
		InputChannel outInputChannel) {
	return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
			outContentInsets, outInputChannel);
}

這裏面的mService實際上就是WindowManagerService

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

		if (outInputChannel != null && (attrs.inputFeatures
				& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
			String name = win.makeInputChannelName();//這個就是創建一個關於這個view的字符串
			InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);//調用InputChannel創建兩個socket
			win.setInputChannel(inputChannels[0]);//server channel
			inputChannels[1].transferTo(outInputChannel);//client channel 將Native層的對象轉換成Java層的對象

			mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);//將server socket註冊到底層
		}
		
}

Server端socket註冊

下面看一下這個registerInputChannel函數的實現。

InputManangerService.java

public void registerInputChannel(InputChannel inputChannel,
		InputWindowHandle inputWindowHandle) {
	if (inputChannel == null) {
		throw new IllegalArgumentException("inputChannel must not be null.");
	}

	nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

com_android_server_iinput_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
        jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
		NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);//獲取native層的InputManager
		···
		status_t status = im->registerInputChannel(	env, inputChannel, inputWindowHandle, monitor);
		···
}

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
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {

    { // acquire lock
        AutoMutex _l(mLock);
		//檢查這個channel是否存在
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }

        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
		//將這個fd註冊到looper中。用來接收來自framework層的消息,並且調用handleReceiveCallback進行處理
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

至此就已經將Server端的socket註冊到了Looper中了。至於addFd函數的實現,請參考Native層的Looper.cpp。

Client端socket註冊

Client端socket註冊實在創建WindowInputEventReceiver對象時註冊的。
下面看一下 WindowInputEventReceiver類

ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {}
InputEventReceiver.java
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");
}

在初始化函數時就會調用nativeInit JNI函數。

android_view_InputEventReceiver.cpp
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
	//將java層的對象轉換成c中的對象
	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();
}
android_view_InputEventReceiver.cpp
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) {
}

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

上面就是將mInputConsumer的中Channel的fd註冊到looper中。其中Channel就是傳遞下來的client端的socket。至此client端的socket也已經註冊完畢。後面就是利用Server/Client socket進行通訊,實現按鍵信息的傳遞。

按鍵傳遞過程

接收按鍵的傳遞流程

EventHub用來讀取驅動中的event。InputReader負責將EventHub中的消息讀取出來,之後InputDispatcher將event發送出來。
具體代碼如下

InputReader.cpp
void InputReader::loopOnce() {
	···
	size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//讀取event
	···
	processEventsLocked(mEventBuffer, count);//處理event事件
	···
}

這裏處理的event事件有以下四種情況:
1.DEVICE_ADDED添加輸入設備
2.DEVICE_REMOVED移除輸入設備
3.FINISHED_DEVICE_SCAN輸入設備掃描完成
4.普通按鍵
這裏我們只對普通按鍵過程進行分析

InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
	···
	processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
	···
}

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//查找event對應的設備

    InputDevice* device = mDevices.valueAt(deviceIndex);//獲取deviceid對應的設備

    device->process(rawEvents, count);//調用設備的處理函數
}

這裏我們以KeyboardInputMapper爲例

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
	switch (rawEvent->type) {
		case EV_KEY: {
			if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)){}//獲取按鍵的keycode
			processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
			break;
		···
		}
	}
}

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
        int32_t scanCode, uint32_t policyFlags) {
	···
		NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
		down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
		AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
		getListener()->notifyKey(&args);//這個call InputDispatcher.notifyKey
	···
}

這個裏面會調用InputDispatcher裏面的notifyKey函數。

InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
	···
    event.initialize(args->deviceId, args->source, args->action,
            flags, args->keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);
	//這裏面要先call PhoneWindowManager中的interceptKeyBeforeQueueing
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
	···
	KeyEntry* newEntry = new KeyEntry(args->eventTime,
		args->deviceId, args->source, policyFlags,
		args->action, flags, args->keyCode, args->scanCode,
		metaState, repeatCount, args->downTime);
	//然後將這個keyevent放到list中
	needWake = enqueueInboundEventLocked(newEntry);//將這個event放入到隊列中,供後面進行處理(1)
	if (needWake) {//這個會喚醒dispatcher loop.也就是會調dispatchOnce
		mLooper->wake();
    }
}

這裏需要注意,PhoneWindowManager裏面的interceptKeyBeforeQueueing實在這個階段調用的。這時候還沒加入到queue中。
將Event加入到Queue中之後還要對queue進行處理。後面調用mLooper->wake()的目的就是開始後續的處理。

void InputDispatcher::dispatchOnce() {
	if (!haveCommandsLocked()) {
		ALOGE("no commands");
		dispatchOnceInnerLocked(&nextWakeupTime);//將從driver中收到的event &command封裝到一個結構中。並且放到command隊列中
	}
	//此時應該已經將要執行的command放入到了queue中。下面就是將上面放入的event使用command進行事件的處理
	// Run all pending commands if there are any.
	// If any commands were run then force the next poll to wake up immediately.
	if (runCommandsLockedInterruptible()) {
		nextWakeupTime = LONG_LONG_MIN;
	}    
	nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

這個函數比較有意思,下面詳細分析一下
先看haveCommandsLocked函數

bool InputDispatcher::haveCommandsLocked() const {
    return !mCommandQueue.isEmpty();
}

這個函數看是否已經存才command,第一次執行會返回false。
下面看dispatchOnceInnerLocked

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
	···
	    case EventEntry::TYPE_KEY: {
			···
			done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
			···
		}
	···
}

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
		//KeyEntry初始化INTERCEPT_KEY_RESULT_UNKNOWN
	if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {//當有event 第一次到達時就會走這裏
			//這裏註冊的command將會再dispatchOnce函數裏面的runCommandsLockedInterruptible進行處理
            CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);//
            if (mFocusedWindowHandle != NULL) {
                commandEntry->inputWindowHandle = mFocusedWindowHandle;
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
            return false; // wait for the command to run
        } else {
           ···
        }
    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
		···
    }
	···
	int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);//這個函數用來查找有哪些對象已經建立了connection。event將會發送給所有的註冊進來的對象。也就是activity。
	···
	dispatchEventLocked(currentTime, entry, inputTargets);
	···
}

postCommandLocked函數就是向mCommandQueue中添加command的實現如下:

InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
    CommandEntry* commandEntry = new CommandEntry(command);
    mCommandQueue.enqueueAtTail(commandEntry);
    return commandEntry;
}

執行完這個函數只有command queue中已經存在command,但是還沒執行。

下面繼續分析

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {


    pokeUserActivityLocked(eventEntry);//用來決定是否要喚醒設備或者點亮屏幕,最終調用的是PowerManagerService。
	//下面將會通知所有註冊進來的channen,有event發生了。
    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);

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

下面的調用順序爲:prepareDispatchCycleLocked-> enqueueDispatchEntriesLocked &startDispatchCycleLocked
這裏面有個小的細節說明一下:enqueueDispatchEntriesLocked函數會調用enqueueDispatchEntryLocked函數。

void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) {
	···
	DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
	inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
	inputTarget->scaleFactor);
	···
	connection->outboundQueue.enqueueAtTail(dispatchEntry);
	···
}

這裏會封裝DispatchEntry,之後放到connection,也就是server socket的封裝對象的outboundQueue中。那麼在後面發送的時候就會從這裏面取event。
繼續後面的分析

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
	···
	 case EventEntry::TYPE_KEY: {
		KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

		// Publish the key event.
		// call InputTransport.cpp
		status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
				keyEntry->deviceId, keyEntry->source,
				dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
				keyEntry->keyCode, keyEntry->scanCode,
				keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
				keyEntry->eventTime);
		break;
	}
	···
}

這裏會調用InputTransport中的publishKeyEvent

status_t InputPublisher::publishKeyEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t action,
        int32_t flags,
        int32_t keyCode,
        int32_t scanCode,
        int32_t metaState,
        int32_t repeatCount,
        nsecs_t downTime,
        nsecs_t eventTime) {

    InputMessage msg;
    msg.header.type = InputMessage::TYPE_KEY;
    msg.body.key.seq = seq;
    msg.body.key.deviceId = deviceId;
    msg.body.key.source = source;
    msg.body.key.action = action;
    msg.body.key.flags = flags;
    msg.body.key.keyCode = keyCode;
    msg.body.key.scanCode = scanCode;
    msg.body.key.metaState = metaState;
    msg.body.key.repeatCount = repeatCount;
    msg.body.key.downTime = downTime;
    msg.body.key.eventTime = eventTime;
    return mChannel->sendMessage(&msg);
}

status_t InputChannel::sendMessage(const InputMessage* msg) {
	···
	do {
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
	···
}

也就是調用socket的send函數。這裏的mFd對應的是Server端的socket。
由於Server/client的socket是通過socketpair的方式打開的,所以向Server端socket寫入數據時,client端的socket就能讀取數據。
根據之前的分析可知client端的socket加入到了epoll中ALOOPER_EVENT_INPUT。所以它將會從epoll中返回。
處理代碼

android_view_InputEventReceiver.cpp
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;
    }
	···
	env->CallVoidMethod(receiverObj.get(),
		gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);//調用InputManagerService.dispatchInputEvent
	···
···
}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
		···
		for (;;) {
			status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);
		}
		···
		}
InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
		    while (!*outEvent) {
				status_t result = mChannel->receiveMessage(&mMsg);
			}
			···
			switch (mMsg.header.type) {
			case InputMessage::TYPE_KEY: {
				KeyEvent* keyEvent = factory->createKeyEvent();
				if (!keyEvent) return NO_MEMORY;

				initializeKeyEvent(keyEvent, &mMsg);
				*outSeq = mMsg.body.key.seq;
				*outEvent = keyEvent;
				break;
			}
			···
			env->CallVoidMethod(receiverObj.get(),
		gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);//調用InputManagerService.dispatchInputEvent
		···
		}

看到在獲取完event之後就調用了dispatchInputEvent。由前面的分析可以知道,在新的view生成之後,註冊client socket時創建了WindowInputEventReceiver,這個類是繼承自InputEventReceiver。所以這裏面調用的dispatchInputEvent就是WindowInputEventReceiver。根據類的繼承關係,在dispatchInputEvent中會調用onInputEvent。
接下來的就是在ViewRootImpl中對event進行處理。

ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
	···
	@Override
	public void onInputEvent(InputEvent event) {
		enqueueInputEvent(event, this, 0, true);
	}
	···
}

void enqueueInputEvent(InputEvent event,
		InputEventReceiver receiver, int flags, boolean processImmediately) {
	//將event加入到隊列中
	QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
	QueuedInputEvent last = mPendingInputEventTail;
	if (last == null) {
		mPendingInputEventHead = q;
		mPendingInputEventTail = q;
	} else {
		last.mNext = q;
		mPendingInputEventTail = q;
	}
	mPendingInputEventCount += 1;
	//處理event
	if (processImmediately) {
		doProcessInputEvents();//處理event
	} else {
		scheduleProcessInputEvents();
	}
}

void doProcessInputEvents() {
	// Deliver all pending input events in the queue.
	while (mPendingInputEventHead != null) {
		QueuedInputEvent q = mPendingInputEventHead;
		mPendingInputEventHead = q.mNext;
		if (mPendingInputEventHead == null) {
			mPendingInputEventTail = null;
		}
		q.mNext = null;

		mPendingInputEventCount -= 1;
		Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
				mPendingInputEventCount);

		deliverInputEvent(q);
	}
	···
}
//決定應該是傳遞給那個stage,之後調用stage.deliver()開始處理input event。
private void deliverInputEvent(QueuedInputEvent q) {

		InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
		if (stage != null) {
			stage.deliver(q);
		} else {
			finishInputEvent(q);
		}
	} finally {
		Trace.traceEnd(Trace.TRACE_TAG_VIEW);
	}
}

通過上面的分析可以發現,jni層獲取到消息之後,會傳遞給framework層的InputEventReceiver。之後交給ViewRootImpl中的stage進行按鍵的處理。下面對stage進行一下分析

ViewRootImpl中stage順序

這裏面的Stage是一個邏輯結構,類似於StateMachine。當有InputEvent之後將會傳遞到這個結構中進行處理。處理完成之後,會調用finishInputEvent函數來通知jni層,這個event已經處理完成。
各個Stage之間的關係如下圖所示:

graph TD;
NativePreImeInputStage-->ViewPreImeInputStage;
ViewPreImeInputStage-->ImeInputStage;
ImeInputStage-->EarlyPostImeInputStage;
EarlyPostImeInputStage-->NativePostImeInputStage;
NativePostImeInputStage-->ViewPostImeInputStage;
ViewPostImeInputStage-->SyntheticInputStage;

指定的初始化stage

mFirstInputStage = nativePreImeStage;//按鍵處理的第一個stage
mFirstPostImeInputStage = earlyPostImeStage;

根據打印的log看,當接收到遙控器按鍵時將會調用mView.dispatchKeyEvent(),而這裏的mView就是在創建Activity是通過setView設置進來的。當這個InputEvent事件處理完成之後,會調用finishInputEvent函數。

ViewRootImpl.java
private void finishInputEvent(QueuedInputEvent q) {
	if (q.mReceiver != null) {
		boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
		q.mReceiver.finishInputEvent(q.mEvent, handled);
	} else {
		q.mEvent.recycleIfNeededAfterDispatch();
	}

	recycleQueuedInputEvent(q);
}
public final void finishInputEvent(InputEvent event, boolean handled) {

	int index = mSeqMap.indexOfKey(event.getSequenceNumber());
	if (index < 0) {
		Log.w(TAG, "Attempted to finish an input event that is not in progress.");
	} else {
		int seq = mSeqMap.valueAt(index);
		mSeqMap.removeAt(index);
		nativeFinishInputEvent(mReceiverPtr, seq, handled);
	}
	
	event.recycleIfNeededAfterDispatch();
}

看到,會調用nativeFinishInputEvent進行處理,也就是會調用NativeInputEventReceiver.finishInputEvent()處理。

android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
	···
	status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
	···
}

這裏面的mInputConsumer與之前發送InputEvent是一樣的,

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
	···
	return sendUnchainedFinishedSignal(seq, handled);
}

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
    InputMessage msg;
    msg.header.type = InputMessage::TYPE_FINISHED;
    msg.body.finished.seq = seq;
    msg.body.finished.handled = handled;
    return mChannel->sendMessage(&msg);
}

通過這部分代碼,可以看出最後是通過client端的socket,將finish事件發送給jni層中的server端的。前面的分析可以知道,在註冊server端的socket時,將socket註冊到epoll中,並且指定有event時的處理函數爲handleReceiveCallback。

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
	//根據fd查找到對應的connection
	ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
	sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
	···
	//開始下一輪的dispatch
	status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
	d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
	
	if (gotOne) {
		d->runCommandsLockedInterruptible();
		if (status == WOULD_BLOCK) {
			return 1;
		}
	}
	
	···
	d->unregisterInputChannelLocked(connection->inputChannel, notify);
	
}

至此,InputEvent的整個處理過程已經完全結束。

總結

Input event事件的處理,大概流程如下:
1.EventHub從驅動中獲取InputEvent
2.InputReader從EventHub中讀取數據發送給InputDispatcher
3.InputDispatcher發送給InputTransport,
4.InputTransport將消息發送給framework層的ViewRootImpl
5.ViewRootImpl對事件進行處理,完成之後發送finish給native層,用來啓動下一輪的dispatch
事件是通過註冊到epoll中的Server/Client sockets進行傳遞的。
發送event時會發送到所有的channel中的。
這裏有個地方需要注意一下:
1.收到input event之後,先調用notifyKey->interceptKeyBeforeQueueing進行處理。這裏的意思時native層中還沒有加到command queue。
2.加入到隊列之後調用runCommandsLockedInterruptible->interceptKeyBeforeDispatching進行處理,此時event已經加入到了command queue中了。
3.之後就時通過註冊進來的InputChannel通知上層activity或者PhoneWindowManagerService

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章