之前分析了inputChannel注册流程和 inputDispatcher分发事件的流程,这篇看下事件从inputDispatcher分发到app的流程。上一篇inputDispatcher分发juejin.cn/post/712600… 的最后会通过socket写入数据,那么socket的另一端会被回调并读取数据,关于inputChannel的注册建立,可以参考juejin.cn/post/712122… ,最后部分可以看到app端的inputChannel被注册,并在有数据的时候回调handleEvent()
先上流程图:
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
// Allowed return values of this function as documented in LooperCallback::handleEvent
constexpr int REMOVE_CALLBACK = 0;
constexpr int KEEP_CALLBACK = 1;
......
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
// 1.1 consumeEvents
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
}
......
return KEEP_CALLBACK;
}
1.1 consumeEvents
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
getInputChannelName().c_str(), toString(consumeBatches), frameTime);
}
if (consumeBatches) {
mBatchedInputEventPending = false;
}
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, nullptr);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 1.2 mInputConsumer.consume 读取事件 赋值到inputEvent
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
......
if (!skipCallbacks) {
if (!receiverObj.get()) {
// mReceiverWeakGlobal指向的是java层传入的WindowInputEventReceiver,参考https://juejin.cn/post/7121222990636777509 里面的app端inputChannel注册过程
receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
}
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
// 2.1 创建java层的事件对象
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
......
}
if (inputEventObj) {
// 2.2 调用java层的方法dispatchInputEvent
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
env->DeleteLocalRef(inputEventObj);
} else {
skipCallbacks = true;
}
}
if (skipCallbacks) {
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
读取事件并保存到inputEvent,然后创建java层的android/view/KeyEvent对象,调用java层的android/view/InputEventReceiver的dispatchInputEvent方法
/native/libs/input/InputTransport.cpp
1.2 mInputConsumer.consume 读取事件
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
*outSeq = 0;
*outEvent = nullptr;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 读取事件 保存到mMsg对象
status_t result = mChannel->receiveMessage(&mMsg);
......
}
switch (mMsg.header.type) {
case InputMessage::Type::KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;
// 初始化KeyEvent对象
// 1.3 initializeKeyEvent
initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.header.seq;
*outEvent = keyEvent;
break;
}
......
}
}
return OK;
}
/native/libs/input/InputTransport.cpp
1.3 initializeKeyEvent
void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source,
msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action,
msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode,
msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime,
msg->body.key.eventTime);
}
2.1 创建java层的事件对象
base/core/jni/android_view_KeyEvent.cpp
jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
jobject eventObj =
env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
event->getId(),
nanoseconds_to_milliseconds(event->getDownTime()),
nanoseconds_to_milliseconds(event->getEventTime()),
event->getAction(), event->getKeyCode(),
event->getRepeatCount(), event->getMetaState(),
event->getDeviceId(), event->getScanCode(),
event->getFlags(), event->getSource(),
event->getDisplayId(), hmac.get(), nullptr);
return eventObj;
}
gKeyEventClassInfo是jni注册的结构体,里面保存了java层的类和方法。 注册的信息可以参考
int register_android_view_KeyEvent(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, "android/view/KeyEvent");
gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gKeyEventClassInfo.obtain =
GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, "obtain",
"(IJJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;");
gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz,
"recycle", "()V");
gKeyEventClassInfo.mId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mId", "I");
gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I");
gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I");
gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId",
"I");
gKeyEventClassInfo.mHmac = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mHmac", "[B");
gKeyEventClassInfo.mMetaState = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mMetaState",
"I");
gKeyEventClassInfo.mAction = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mAction", "I");
gKeyEventClassInfo.mKeyCode = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mKeyCode", "I");
gKeyEventClassInfo.mScanCode = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mScanCode", "I");
gKeyEventClassInfo.mRepeatCount = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mRepeatCount",
"I");
gKeyEventClassInfo.mFlags = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mFlags", "I");
gKeyEventClassInfo.mDownTime = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDownTime", "J");
gKeyEventClassInfo.mEventTime = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mEventTime",
"J");
gKeyEventClassInfo.mCharacters = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mCharacters",
"Ljava/lang/String;");
return RegisterMethodsOrDie(env, "android/view/KeyEvent", g_methods, NELEM(g_methods));
}
2.2 调用java层的方法dispatchInputEvent
调用gInputEventReceiverClassInfo.dispatchInputEvent java层的android/view/InputEventReceiver类的dispatchInputEvent方法。
gInputEventReceiverClassInfo是jni中注册的与java层对象的映射关系 base/core/jni/android_view_InputEventReceiver.cpp
int register_android_view_InputEventReceiver(JNIEnv* env) {
int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver",
gMethods, NELEM(gMethods));
jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver");
gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env,
gInputEventReceiverClassInfo.clazz,
"dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
gInputEventReceiverClassInfo.onFocusEvent =
GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onFocusEvent", "(ZZ)V");
gInputEventReceiverClassInfo.onPointerCaptureEvent =
GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onPointerCaptureEvent",
"(Z)V");
gInputEventReceiverClassInfo.onDragEvent =
GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onDragEvent", "(ZFF)V");
gInputEventReceiverClassInfo.onBatchedInputEventPending =
GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onBatchedInputEventPending",
"(I)V");
return res;
}
下面分析一下java层的代码
/base/core/java/android/view/InputEventReceiver.java
// Called from native code.
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
// 3.1 回调java层
onInputEvent(event);
}
onInputEvent方法是子类实现的,这边的子类是ViewRootImpl中的WindowInputEventReceiver对象,看下WindowInputEventReceiver的onInputEvents()
3.1 回调java层
android.view.ViewRootImpl.WindowInputEventReceiver
public void onInputEvent(InputEvent event) {
List<InputEvent> processedEvents;
try {
processedEvents =
mInputCompatProcessor.processInputEventForCompatibility(event);
}
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);
}
}
都要调用到enqueueInputEvent()方法
3.2 enqueueInputEvent()
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
// Always enqueue the input event in order, regardless of its time stamp.
// We do this because the application or the IME may inject key events
// in response to touch events and we want to ensure that the injected keys
// are processed in the order they were received and we cannot trust that
// the time stamp of injected events are monotonic.
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
// processImmediately == true
if (processImmediately) {
// 3.3 doProcessInputEvents将事件插入pending队列
doProcessInputEvents();
}
}
3.3 doProcessInputEvents
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;
mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
// 3.4 处理事件
deliverInputEvent(q);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
3.4 处理事件
private void deliverInputEvent(QueuedInputEvent q) {
try {
// 责任链stage,处理事件
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
.....
if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
}
InputStage链是ViewRootImpl的setView方法中初始化的,参考juejin.cn/post/712122… 中setView的方法。到这里事件会经过stage一个一个的处理。最后还会调用finishInputEvent(q); 通知inputDispatcher处理后面的事件。下次再分析