Android之input app通信篇(一)服务端业务梳理

2022-01-27  本文已影响0人  锄禾豆

简介

只要带窗口的应用,都离不开ViewRootImpl的使用。关于触摸或按键事件的交互,关注ViewRootImpl的协调。
提示:
不管是Activity还是其他都可以从WindowManager.addView入手分析

分析
1.ViewRootImpl.setView

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                ···
                //初始化InputChannel
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                ···
                try {
                    ···
                    //将InputChannel发送给wms
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    ···
                } finally {
                    ···
                }
                ···
                //创建InputChannel的客户端
                if (mInputChannel != null) {
                    ···
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ···
                //初始化InputChannel客户端回调数据涉及的业务处理对象
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                ···
            }
        }
    }

(1)创建InputChannel对象,并初始化InputChannel客户端的接收器WindowInputEventReceiver
(2)将InputChannel对象发送给wms
这里我们知道了客户端的创建及监听,接下来我们分析服务端的创建及监听

2.mWindowSession.addToDisplay

mWindowSession为Binder对象,实现类为Session
com.android.server.wm.Session
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        //mService为WMS
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }
    从Session转入WindowManagerService分析

com.android.server.wm.WindowManagerService
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        ···
        final boolean openInputChannels = (outInputChannel != null
                && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
        if  (openInputChannels) {
            win.openInputChannel(outInputChannel);
        }        
        ···
    }
    从WindowManagerService转入WindowState分析

com.android.server.wm.WindowState
    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = makeInputChannelName();
        //创建InputChannel数组
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        //获取InputChannel服务端
        mInputChannel = inputChannels[0];
        //获取InputChannel客户端
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        if (outInputChannel != null) {
            //把app的inputChannel切换成客户端
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        //把服务端注册到InputManagerService中
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }

(1)WindowManagerService创建了用于InputChannel通信的数组
(2)将app的InputChannel设置成客户端
(3)将InputManagerService的设置成服务端

3.关注InputChannel服务端的数据来源

mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);

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

        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
    }
    将InputChannel注册到native层


com_android_server_input_InputManagerService.cpp
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}
     mInputManager->getDispatcher()即InputDispatcher,把InputChannel注册到InputDispatcher


InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    ···
    { // acquire lock
        AutoMutex _l(mLock);
        ···
        //将inputChannel跟Connection绑定起来
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();

        //将connection加入容器mConnectionsByFd
        mConnectionsByFd.add(fd, connection);
        ···
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    //唤醒InputDispatcher线程
    mLooper->wake();
    return OK;
}
(1)需要进一步分析Connection和InputChannel怎么结合
(2)容器mConnectionsByFd用来做什么

先看容器mConnectionsByFd的目的,我们知道触摸或者按键最终来到InputDispatcher.dispatchEventLocked
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
    ···
    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);

        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            //从容器mConnectionsByFd获取connection,从而分发处理
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
            ···
        }
    }
}

(1)InputManagerService.registerInputChannel将服务端InputChannel传递到InputDispatcher
实现方式:将InputChannel包裹成Connection插入到容器mConnectionsByFd
(2)InputReader从EventHub读取的数据分发给InputDispatcher
(3)InputDispatcher分发数据的时候,从容器mConnectionsByFd获取InputChannel进行业务处理

4.分析Connection

InputDispatcher.cpp
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
        status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
        monitor(monitor),
        inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
将Connection将inputChannel赋值给InputPublisher

InputTransport.cpp
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
        mChannel(channel) {
}

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;
    ···
    return mChannel->sendMessage(&msg);
}

status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t action,
        int32_t actionButton,
        int32_t flags,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
    ···
    InputMessage msg;
    ···
    return mChannel->sendMessage(&msg);
}
InputPublisher承载的InputChannel的目的就是调用mChannel->sendMessage(&msg)


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

    ···
    return OK;
}
这就是真正意义上的通信源头

5.分析InputDispatcher.prepareDispatchCycleLocked

这里只做流程分析

prepareDispatchCycleLocked --> enqueueDispatchEntriesLocked --> startDispatchCycleLocked

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
    ···
    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        ···
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
            ···
            // Publish the key event.
            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: {
            ···
            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    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;
        }
        ···
    }
}

InputDispatcher分发后来到了InputPublisher

总结

InputChannel服务端的业务处理,可通过如下注册:
InputManagerService.registerInputChannel
即将服务端InputChannel传递到InputDispatcher,从而实现客户端和服务端的通信
上一篇下一篇

猜你喜欢

热点阅读