Android 输入系统之InputDispatcher2ViewRootImpl篇----终

来源:互联网 发布:windows10怎么下载软件 编辑:程序博客网 时间:2024/05/16 09:35

本来没打算写这一篇的,因为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<InputChannel> serverChannel;    sp<InputChannel> 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<InputChannel>& outServerChannel, sp<InputChannel>& 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而言这两端是完全对等的,因为前面已经说过,在任何一端写入数据,另外一端都能读到。
native成生成一对InputChannel后返回给Java了。

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<NativeInputManager*>(ptr);    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,            inputChannelObj);    if (inputChannel == NULL) {        throwInputChannelNotInitialized(env);        return;    }    sp<InputWindowHandle> 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>& inputChannel,        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {    return mInputManager->getDispatcher()->registerInputChannel(            inputChannel, inputWindowHandle, monitor);}
最终是调用InputDispatcher的同名函数:
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,        const sp<InputWindowHandle>& 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> 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);</span>
直接调用InputManagerService.java的nativeSetInputWindows(mPtr, windowHandles);</span>
nativeSetInputWindows(mPtr, windowHandles);实现:
static void nativeSetInputWindows(JNIEnv* env, jclass clazz,        jint ptr, jobjectArray windowHandleObjArray) {    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);    im->setInputWindows(env, windowHandleObjArray);}
顺便提一下传进来的mPtr,大家可以自行去看其实如何初始化的,它保存在Java层,大家可以认为代表的native层NativeInputManager对象,通过reinterpret_cast方式,<pre name="code" class="java">后面很多分析都有XXXPtr的,原理都是一模一样,<span style="font-family: Arial, Helvetica, sans-serif;">貌似这玩意比较厉害,什么东西都可以转化为int形式保存,看起来比Java层的序列化还要厉害,各位知道其原理的可以留言告诉我。</span>
和前面很类似im->setInputWindows(env, windowHandleObjArray);核心也是调用InputDispatcher的同名函数:
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {#if DEBUG_FOCUS    ALOGD("setInputWindows");#endif    { // acquire lock        AutoMutex _l(mLock);        Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;        mWindowHandles = inputWindowHandles;        sp<InputWindowHandle> newFocusedWindowHandle;        bool foundHoveredWindow = false;        for (size_t i = 0; i < mWindowHandles.size(); i++) {            const sp<InputWindowHandle>& 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<InputChannel> 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<InputChannel> 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<InputWindowHandle>& 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>& 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<KeyEntry*>(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<MotionEntry*>(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<InputEventReceiver>(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> inputChannel = android_view_InputChannel_getInputChannel(env,            inputChannelObj);    if (inputChannel == NULL) {        jniThrowRuntimeException(env, "InputChannel is not initialized.");        return 0;    }    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);    if (messageQueue == NULL) {        jniThrowRuntimeException(env, "MessageQueue is not initialized.");        return 0;    }    sp<NativeInputEventReceiver> 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<jint>(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中,其中的道路不可谓不曲折。。。。。。










0 0
原创粉丝点击