本来没打算写这一篇的,因为input event从InputDispatcher到ViewRootImpl涉及到activity的启动流程,这个过程的复杂度不会比input流程简单,但是不分析事件是如何被送到ViewRootImpl实在是不完整。OK,废话不多说,开始分析。
activity的启动流程没准备分析了,这个不是这个系列文章的重点,以这篇文章的分析作为参考:http://www.tuicool.com/articles/yQRrUv
我们注意到这一段:
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
这里创建的mInputChannel就是作为一个参数罢了,后面会被另外一个InputChannel覆盖,后面会说到。
很明显,如果没有设置INPUT_FEATURE_NO_INPUT_CHANNEL属性则会创建一个InputChannel,然后调用mWindowSession.addToDisplay()
我们注意到这个方法实现在Session.java中,他直接调用WindowManagerService的addWindow()函数。
addWindow()内容比较长,我们只贴我们需要的代码:
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
/** M: [ALPS00044207] @{ */
try {
String name = win.makeInputChannelName();
//如果没有设置INPUT_FEATURE_NO_INPUT_CHANNEL和INPUT_FEATURE_NO_INPUT_CHANNEL属性,则会创建一对InputChannel,为什么是一对呢,其实InputChannel内部就是Linux的socketpair,再说通俗点,就是一对全双工的管道,在任何一端写,另外一端都可以读到,当然和INotify一样,也是需要主动读的。Linux中跨进程通信这个还是比较好用的
//setup 1
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
//setup 2
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
} catch (RuntimeException e) {
Slog.w(TAG,"handle Input channel erorr", e);
return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
}
/** @} */
}
.............
.............
//setup 3
mInputMonitor.updateInputWindowsLw(false /*force*/);
setup 1,2,3是我们需要关注的。
先看看openInputChannelPair()实现:
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(name),看看其实现:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp serverChannel;
sp 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,
new NativeInputChannel(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
继续看看
InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
status_t InputChannel::openInputChannelPair(const String8& name,
sp& outServerChannel, sp& 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.string(), 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));
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
到这里就印证了之前的说法,InputChannel对其实就是一对
socketpair,用来跨进程通信的,后面还设置了socketpair的缓冲区大小,然后将socketpair两端的
sockets[2]分别封装成两个
InputChannel,一个server,一个client,对于socketpair而言这两端是完全对等的,因为前面已经说过,在任何一端写入数据,另外一端都能读到。
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
然后一端给到WindowState,另外一端给到app端,覆盖之前app传过来的mInputChannel。
现在看setup 2:
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
其实现在InputManagerService.java:
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
把服务端的InputChannel传入
nativeRegisterInputChannel()中,我们看看其实现:
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast(ptr);
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
throwInputChannelNotInitialized(env);
return;
}
sp inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
String8 message;
message.appendFormat("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.string());
return;
}
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
我们只要关注
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);就行了,其他部分都是对象在Java层和native层都相互转化和错误处理,不影响我们分析。
im是NativeInputManager:
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
最终是调用InputDispatcher的同名函数:
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
toString(monitor));
#endif
{ // acquire lock
AutoMutex _l(mLock);
//如果该inputchannel已经被保存,则返回
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
//将inputchannel封装成Connection,其中保存了InputChannel,InputPublisher(用来往InputChannel中写数据的),inputWondwHandle(用来保存窗口信息,比如说是否有焦点)看到这里,大家可能已经开始迷糊了,封装太多了,如果看到这里忘记了前面的内容,很简单,再返回去看就好了,多看几遍就明白了,跟着别人的思路走就容易迷失自己的思路,看别人的代码分析一定要一边看一边想,形成自己的思路
sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
//其实InputChannel中最重要的东西也就是这个fd了,要传送数据直接写它就行了。
int fd = inputChannel->getFd();
//添加到mConnectionsByFd中
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
//将server端的fd加入looper中监听,一旦client端有写入数据,handleReceiveCallback就会被回调,关于addFd后面会经常用到,第四个参数是用来传回调函数的,大家注意一下
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
//说明窗口情况有变化,需要唤醒InputDispatcher马上工作
mLooper->wake();
return OK;
}
走完setup 2,服务端的管道已经成功的传递到InputDispatcher中了,InputDispatcher只要向对应的fd中写东西,app端的InputChannel就可以成功读取到数据,跨进程通信已经搭建好了。
继续看setup 3:mInputMonitor.updateInputWindowsLw(false /*force*/);
final int numDisplays = mService.mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState child = windows.get(winNdx);
final InputChannel inputChannel = child.mInputChannel;
final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
// Skip this window because it cannot possibly receive input.
continue;
}
final int flags = child.mAttrs.flags;
final int privateFlags = child.mAttrs.privateFlags;
final int type = child.mAttrs.type;
final boolean hasFocus = (child == mInputFocus);
final boolean isVisible = child.isVisibleLw();
final boolean hasWallpaper = (child == mService.mWallpaperTarget)
&& (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
if (inDrag && isVisible && onDefaultDisplay) {
mService.mDragState.sendDragStartedIfNeededLw(child);
}
if (universeBackground != null && !addedUniverse
&& child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) {
final WindowState u = universeBackground.mWin;
if (u.mInputChannel != null && u.mInputWindowHandle != null) {
addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags,
u.mAttrs.privateFlags, u.mAttrs.type,
true, u == mInputFocus, false);
}
addedUniverse = true;
}
if (child.mWinAnimator != universeBackground) {
addInputWindowHandleLw(inputWindowHandle, child, flags, privateFlags, type,
isVisible, hasFocus, hasWallpaper);
}
}
}
// Send windows to native code.
mService.mInputManager.setInputWindows(mInputWindowHandles);
// Clear the list in preparation for the next round.
clearInputWindowHandlesLw();
这里做的工作也比较简单,将所有的窗口的
InputWindowHandle添加到
mInputWindowHandles中,然后调用
mService.mInputManager.setInputWindows(mInputWindowHandles);
继续关注>mService.mInputManager.setInputWindows(mInputWindowHandles);
直接调用InputManagerService.java的nativeSetInputWindows(mPtr, windowHandles);
nativeSetInputWindows(mPtr, windowHandles);实现:
static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
jint ptr, jobjectArray windowHandleObjArray) {
NativeInputManager* im = reinterpret_cast(ptr);
im->setInputWindows(env, windowHandleObjArray);
}
顺便提一下传进来的mPtr,大家可以自行去看其实如何初始化的,它保存在Java层,大家可以认为代表的native层NativeInputManager对象,通过reinterpret_cast方式,后面很多分析都有XXXPtr的,原理都是一模一样,貌似这玩意比较厉害,什么东西都可以转化为int形式保存,看起来比Java层的序列化还要厉害,各位知道其原理的可以留言告诉我。
和前面很类似im->setInputWindows(env, windowHandleObjArray);核心也是调用InputDispatcher的同名函数:
void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) {
#if DEBUG_FOCUS
ALOGD("setInputWindows");
#endif
{ // acquire lock
AutoMutex _l(mLock);
Vector > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp& windowHandle = mWindowHandles.itemAt(i);
if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
if (windowHandle->getInfo()->hasFocus) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
foundHoveredWindow = true;
}
}
if (!foundHoveredWindow) {
mLastHoverWindowHandle = NULL;
}
if (mFocusedWindowHandle != newFocusedWindowHandle) {
if (mFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
ALOGD("Focus left window: %s",
mFocusedWindowHandle->getName().string());
#endif
sp focusedInputChannel = mFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
}
if (newFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
ALOGD("Focus entered window: %s",
newFocusedWindowHandle->getName().string());
#endif
}
mFocusedWindowHandle = newFocusedWindowHandle;
}
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
ALOGD("Touched window was removed: %s",
touchedWindow.windowHandle->getName().string());
#endif
sp touchedInputChannel =
touchedWindow.windowHandle->getInputChannel();
if (touchedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(
touchedInputChannel, options);
}
mTouchState.windows.removeAt(i--);
}
}
// Release information for windows that are no longer present.
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
for (size_t i = 0; i < oldWindowHandles.size(); i++) {
const sp& oldWindowHandle = oldWindowHandles.itemAt(i);
if (!hasWindowHandleLocked(oldWindowHandle)) {
#if DEBUG_FOCUS
ALOGD("Window went away: %s", oldWindowHandle->getName().string());
#endif
oldWindowHandle->releaseInfo();
}
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
这段函数主要工作就是需找焦点窗口,保存在mFocusedWindowHandle中,这里为后面InputDispatcher寻找焦点窗口提供了依据。
不过这里我有点不明白,最后为什么还要去遍历oldWindowHandles,删除其中更新掉的元素,同样有知道的留言告诉我。
OK,经过这三个步骤,一切准备就绪了,我们接着看上一篇最后的函数。dispatchEventLocked()
分析了这么多,我不想再一步步分析下去,代码模式都差不多,最终dispatchEventLocked实现,最终其会调用:
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp& connection) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
connection->getInputChannelName());
#endif
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast(eventEntry);
// Publish the key event.
//通过inputPublisher.publishKeyEvent将key event发送出去,其最终调用mChannel->sendMessage(&msg),其又调用nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);看到这里应该很明白了,就是向fd中写数据了,这些就是socketpair的工作了,大家看到这里,很多流程可以自己分析了,中间我省略了很多细节部分,大家感兴趣的自己去了解细节部分。
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;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// Set the X and Y offset depending on the input source.
float xOffset, yOffset, scaleFactor;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
scaleFactor = dispatchEntry->scaleFactor;
xOffset = dispatchEntry->xOffset * scaleFactor;
yOffset = dispatchEntry->yOffset * scaleFactor;
if (scaleFactor != 1.0f) {
for (size_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
scaledCoords[i].scale(scaleFactor);
}
usingCoords = scaledCoords;
}
} else {
xOffset = 0.0f;
yOffset = 0.0f;
scaleFactor = 1.0f;
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (size_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i].clear();
}
usingCoords = scaledCoords;
}
}
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset,
motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
default:
ALOG_ASSERT(false);
return;
}
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
if (connection->waitQueue.isEmpty()) {
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
"event to it, status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
"waiting for the application to catch up",
connection->getInputChannelName());
#endif
connection->inputPublisherBlocked = true;
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
"status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
return;
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}
向
socketpair的server端写数据后,我们说过app层会收到这个数据,我们看看app是如何收到的,其实也就是找找client端的fd谁在监听
大家搜索一下ViewRootImpl的setView函数会发现有:mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
client端的InputChannel被传入到WindowInputEventReceiver构造函数中,我们看看其实现。
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
/** M: record current key event and motion event to dump input event info for ANR analysis. @{ */
if (event instanceof KeyEvent) {
mCurrentKeyEvent = (KeyEvent) event;
mKeyEventStartTime = System.currentTimeMillis();
mKeyEventStatus = INPUT_DISPATCH_STATE_STARTED;
} else {
mCurrentMotion = (MotionEvent) event;
mMotionEventStartTime = System.currentTimeMillis();
mMotionEventStatus = INPUT_DISPATCH_STATE_STARTED;
}
/** @} */
//这里没细看,但是我猜测应该是ViewRootImpl准备对输入事件进行分发了,关于Android事件分发机制基本上是Android软件工程师必考的面试题了,我app写的很少,对这个至今没很明白。。。。。。。。
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (DEBUG_INPUT || DEBUG_KEY || DEBUG_MOTION) {
Xlog.v(TAG, "onBatchedInputEventPending: this = " + this);
}
/// M : do not wait for vsync for move event to improve response time
if (MOVE_RESPONSE_ENHANCE) {
scheduleConsumeBatchedInputByHandler();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
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(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
client端的InputChannel被传递到
nativeInit中(
mReceiverPtr 和前面分析的ptr一样,Java层用来保存native层对应对象的引用
)
看看nativeInit():
static jint 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());
}
这些代码和前面的思路基本上一模一样了,我们只关注initialize():
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);
}
}
}
到这里就应该非常清楚了吧,client端的fd也被加入到looper中监听,一旦server端有数据过来,
便会调用回调函数,值得一提的是对应的回调函数handleEvent,至于为什么大家需要看看
addFd()的实现。
handleEvent会最终调用前面提到的
WindowInputEventReceiver中的
onInputEvent(),然后ViewRootImpl便会开始分发数据了
OK,到这里整个input流程都完结了,从按下按键到最终分发到app中,其中的道路不可谓不曲折。。。。。。