触摸事件分发流程详解(一):建立InputChannel

触摸事件分发流程详解分三个部分分析

建立InputChannel

事件发送和接受

触摸事件分发

这里分析从ViewRootImpl开始:

ViewRootImpl的setView:

触摸事件java端的入口可以从ViewRootImpl的setView讲起,什么时候调用的setView可以查看window的界面显示机制。
对于输入事件分发机制来说,这个setView主要做了四件事:

  1. 在这里创建了客户端的InputChannel对象。
  2. 通过binder机制,调用WindowSession的addToDisplay方法,并将InputChannel传入进去。
  3. 创建WindowInputEventReveiver对象,用来启动inputStage的责任链机制。
  4. 创建7个InputStage责任链的节点。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
	    ........................
	    //这个requestLayout是开启的view的绘制流程
            requestLayout();
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1、这里直接创建了一个客户端的InputChannel;
                mInputChannel = new InputChannel();
            }
            mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                    & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
2、通过Binder调用,进入system进程的Session,同时将客户端的InputChannel作为参数传入。
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
            } catch (RemoteException e) {
                throw new RuntimeException("Adding window failed", e);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }
	    ........................
            if (view instanceof RootViewSurfaceTaker) {
                mInputQueueCallback =
                    ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
            }
            if (mInputChannel != null) {
                if (mInputQueueCallback != null) {
                    mInputQueue = new InputQueue();
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }
3、在这里创建了WindowInputEventReveiver对象。
                mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                        Looper.myLooper());
            }
            view.assignParent(this);
            mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
            mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
            if (mAccessibilityManager.isEnabled()) {
                mAccessibilityInteractionConnectionManager.ensureConnection();
            }
            if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
            }
4、在这里创建了7个InputStage的责任链,按顺序执行,ViewPostImeInputStage这个是关键。
            CharSequence counterSuffix = attrs.getTitle();
            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;
            mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
        }
    }
}

WindowsManagerService的addWindow:

第二步中的会调用mWindowSession.addToDisplay()方法,这是通过binder机制,最终是调用了WindowsManagerService中的addWindow方法。

public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        InputChannel outInputChannel) {
	....................

    synchronized(mWindowMap) {
        ...................
1、这里创建一个WindowState 是窗口对象
        WindowState win = new WindowState(this, session, client, token,
                attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent)
	final boolean openInputChannels = (outInputChannel != null
       		 && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
	if  (openInputChannels) {
2、然后通过win中的openInputChannel创建socket pair,注意这里跟老版本不同,之前是在这里直接创建的,现在都移到WindowState中去了
   	 	win.openInputChannel(outInputChannel);
	}
        ...................
    }
    return res;
}

WindowState中的openInputChannel:
这里通过openInputChannel方法创建了一对InputChannel,将服务端的InputChannel注册到InputDispatch中,将客户端的InputChannel返回给客户端应用,这样就是实现了客户端和服务端的通信。这里的InputChannel其实就是socket,也就是说输入事件的通信是通过socket实现的,当用户调用InputChannel.sendMessage也就是调用socket.send方法。

void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = makeInputChannelName();
1、创建socket pair用于通信,注意,这里的socket是成对创建的。
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
2、将服务端的socket赋给服务端的WindowState
    mInputChannel = inputChannels[0];
3、将客户端的socket赋给客户端的WindowState
    mClientChannel = inputChannels[1];
    mInputWindowHandle.inputChannel = inputChannels[0];
    if (outInputChannel != null) {
4、将客户端的socket放入outInputChannel,最终返回客户端应用进程
        mClientChannel.transferTo(outInputChannel);
        mClientChannel.dispose();
        mClientChannel = null;
    } else {
        mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
    }
5、最终将服务端的socket(win.mInputChannel)注册到inputDispatch中。这里的registerInputChannel是一个native方法,调用的就是底层的
    mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}

inputDispatch中的registerInputChannel:

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#endif
    { // acquire lock
        AutoMutex _l(mLock);
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }
1、这里会创建一个connection对象,并将inputChannel放进去,这个connection就是客户端和服务端的数据通道。每个connection都回对应一个服务端的InputChannel,每个connection都会对应一个socket Pair的fd;
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
        int fd = inputChannel->getFd();
2、同时,InputDispatch会将fd最为键,connection作为值,添加到mConnectionsByFd中
        mConnectionsByFd.add(fd, connection);
        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
3、然后,InputDispatch会将服务端的fd通过Looper的addFd方法,注册到Looper中去,这样,其中一端socket写内容的时候,looper就会知道,并且被唤醒,调用looper.wake()方法,最后在handleReceiveCallback回调函数中获取数据。那么客户端的socket什么时候注册呢?
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    }
    mLooper->wake();
    return OK;
}
4、在ViewRootImpl的setView中我们最后创建了WindowInputEventReceiver对象,这个对象继承InputEventReceiver,它的构造里,就调用了nativeInit方法,这个native方法是在NativeInputEventReceiver.cpp中实现的。
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
...............
    mInputChannel = inputChannel;
    mMessageQueue = looper.getQueue();
    mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
            inputChannel, mMessageQueue);
    mCloseGuard.open("dispose");
}
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) {
5、中这里将客户端的fd也注册到了Looper中去,这样就完成,两个socket都是通过Looper来监听的,一旦有动作就会被唤醒。
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值