上一个章节,我们讲解了App如何使用InputChannel通道与input系统服务建立通信的桥梁的过程,本章我们讲述App如何从input系统服务中获取上报的输入事件,也就是我们本章讲述的InputEventReceiver。
frameworks/base/core/java/android/view/InputChannel.java
frameworks/base/core/java/android/view/ViewRootImpl.java
frameworks/base/core/jni/android_view_InputChannel.cpp
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
frameworks/base/core/jni/com_android_server_input_InputManagerService.cpp
frameworks/base/services/core/java/com/android/server/wm/Session.java
frameworks/base/core/java/android/view/WindowState.java
上一章节,我们讲述了当App初始化完成InputChannel后,会创建一个事件接收器,如下所示:
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
其中 WindowInputEventReceiver是InputEventReceiver的子类,实现如下所示:
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();
}
}
从中我们可以知道,核心实现是InputEventReceiver,因此接下来我们重点讲述InputEventReceiver的实现。
InputEventReceiver的类,我们主要讲述核心方法的实现,如下所示:
public abstract class InputEventReceiver {
......
private long mReceiverPtr;
private InputChannel mInputChannel;
private MessageQueue mMessageQueue;
// Map from InputEvent sequence numbers to dispatcher sequence numbers.
private final SparseIntArray mSeqMap = new SparseIntArray();
private static native long nativeInit(WeakReference receiver,
InputChannel inputChannel, MessageQueue messageQueue);
private static native void nativeDispose(long receiverPtr);
private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
long frameTimeNanos);
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
......
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference(this),
inputChannel, mMessageQueue);
}
public void onInputEvent(InputEvent event) {
finishInputEvent(event, false);
}
public final void finishInputEvent(InputEvent event, boolean handled) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to finish an input event but the input event "
+ "receiver has already been disposed.");
} else {
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();
}
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
// Called from native code.
@SuppressWarnings("unused")
private void dispatchBatchedInputEventPending() {
onBatchedInputEventPending();
}
public static interface Factory {
public InputEventReceiver createInputEventReceiver(
InputChannel inputChannel, Looper looper);
}
}
InputEventReceiver的构造方法实现,如下:
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
......
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference(this),
inputChannel, mMessageQueue);
}
该方法的初始化使用了App自己的inputChannel通道和App的Looper消息队列,然后调用JNI方法完成最终的初始化,如下所示:
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
sp 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(receiver.get());
}
nativeInit方法主要完成如下的逻辑:
1、找到java层的InputChannel对象对应的Native层的C++对象inputChannel;
2、找到java层的messageQueue对象对应的Native层的C++对象messageQueue;
3、调用NativeInputEventReceiver的initialize完成初始化;
我们继续讲解NativeInputEventReceiver的实现,如下所示:
class NativeInputEventReceiver : public LooperCallback {
public:
NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp& inputChannel,
const sp& messageQueue);
status_t initialize();
......
virtual int handleEvent(int receiveFd, int events, void* data);
};
NativeInputEventReceiver继承LooperCallback, 并重载实现了handleEvent。我们这里重点提及到LooperCallback,是因为App获取Input输入事件是通过监控inputChannel通道,并通过LooperCallback实现输入事件的获取,监控代码如下所示:
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);
}
}
}
该接口的实现,我加入了对ALOOPER_EVENT_INPUT事件类型的监控,InputDispatcher上报的输入事件会触发ALOOPER_EVENT_INPUT事件,并最终调用到NativeInputEventReceiver中的handleEvent方法。关于Looper的实现,我们这里不详细展开,感兴趣的同学可以,自行去阅读AOSP源码。
当InputDispatcher上报事件时,将输入事件写入InputChannel后,最终会触发NativeInputEventReceiver中的handleEvent执行,如下所示:
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;
}
......
return 1;
}
我们只保留了InputDispatcher上报事件时的触发回调代码,然后继续调用consumeEvents接口,如下所示:
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
......
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
......
if (!skipCallbacks) {
......
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
}
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION: {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
}
MotionEvent* motionEvent = static_cast(inputEvent);
if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
*outConsumedBatch = true;
}
inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
}
default:
assert(false); // InputConsumer should prevent this from ever happening
inputEventObj = NULL;
}
if (inputEventObj) {
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
skipCallbacks = true;
}
}
......
}
}
consumeEvents实现比较复杂,涉及到的逻辑比较多,为了简化描述,我们只保留首次上报输入事件的处理,主要实现逻辑如下所示:
1、mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);获取事件;
2、根据不同的事件类型,封装为一个inputEventObj对象;
3、调用InputEventReceiver的java方法env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);正式开始向App上报输入事件;
调用InputEventReceiver的dispatchInputEvent如下所示:
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
最终调用到了 WindowInputEventReceiver子类的onInputEvent方法,如下所示:
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);
}
......
}
继续调用enqueueInputEvent,如下所示:
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(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;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
1、将上报的输入事件加入到处理队列中;
2、调用doProcessInputEvents立即开始App对输入事件的处理,我们在后续文章进行讲解。这里不再叙述。
本文讲述了App通过注册输入事件接收器的方式,当InputDispacther上报输入事件时,通过Looper的回调机制App获取到了事件,并通过doProcessInputEvents接口,正式开启App对input事件的处理。