美文网首页
Android之input app通信篇(一)服务端业务梳理

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

作者: 锄禾豆 | 来源:发表于2022-01-27 08:17 被阅读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,从而实现客户端和服务端的通信
    

    相关文章

      网友评论

          本文标题:Android之input app通信篇(一)服务端业务梳理

          本文链接:https://www.haomeiwen.com/subject/wwfwhrtx.html