Android应用与Input子系统建立连接

基于Android 7.0源码分析

Android应用与Input子系统建立连接_第1张图片

通常,Android应用启动时,在Activity的生命周期onResume()执行结束后,会将Activity的窗口注册到WindowManagerService,由WindowManagerService创建好InputChannel后,通过Binder IPC回传给应用。下面我们从WindowManagerGlobaladdView()开始分析。

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
            ......
        synchronized (mLock) {
            ......
            // 创建ViewRootImpl对象    
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            // 调用ViewRootImpl的setView
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }
  • ViewRootImpl 顶层View层级,实现了View和WindowManager之间的交互协议

下面看ViewRootImplSetView()的实现

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                ......
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    // 创建空的InputChannel,内部状态在Binder IPC addToDisplay返回时创建(细节请查看IWindowSession.java)
                    mInputChannel = new InputChannel();
                }
                ......
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    // 窗口注册到WindowManagerService
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
                ......
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    // 创建WindowInputEventReceiver对象,负责接收输入事件
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ......
                // Set up the input pipeline.
                // 创建InputState链处理输入事件,采用职责链模式
                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;
            }
        }
    }

mWindowSession是一个IWindowSession.Stub.Proxy类型的代理对象,它是在ViewRootImpl的构造方法中创建的,对应的服务对象是Session对象,下面看SessionaddToDisplay()的实现。

    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        // mService是WindowManagerService对象
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }
  • Session 表示一个激活的客户端会话,通常,WindowManagerService为每个与其交互的客户进程创建一个Session

下面看WindowManagerServiceaddWindow()的实现

    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) {
            ......
            // 创建WindowState用于描述一个窗口
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            ......
            if  (openInputChannels) {
                // 创建InputChannel, 注册InputChannel到InputManager
                win.openInputChannel(outInputChannel);
            }
            ......
        }
        ......
    }

下面看WindowStateopenInputChannel()的实现

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        // 输入通道名字
        String name = makeInputChannelName();
        // 创建一对输入通道
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        // 用于服务端发布输入事件
        mInputChannel = inputChannels[0];
        // 用于客户端消耗输入事件
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        if (outInputChannel != null) {
            // mClientChannel的内部状态设置到outInputChannel
            // 最终outInputChannel通过Binder IPC返回给客户端
            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注册输入通道(观察者模式)
        // mInputWindowHandle为InputWindowHandle对象,用于Native层的Input Dispathcer获取窗口状态
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }

下面首先看输入通道的创建openInputChannelPair(), 它是一个Native方法,对应的实现在android_view_InputChannel.cpp中。

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;
    // 创建socket pair
    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;
    }
    // 创建Java层的InputChannel数组对象
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }
    // 创建Java层服务端InputChannel对象,NativeInputChannel相当于中介者
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
        new NativeInputChannel(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }
    // 创建Java层客户端InputChannel对象
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }
    // 设置Java层InputChannel数组中的对象
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

下面看openInputChannelPair()的实现

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;
    }
    // 设置socket发送、接收缓冲区
    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)");
    // 创建服务端InputChannel
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    // 创建客户端InputChannel
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

至此,InputChannel的创建已经完成,下面看InputChannel的注册,下面从InputManagerServiceregisterInputChannel开始分析

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast(ptr);
    // 获取inputChannelObj关联的Native层的InputChannel
    sp inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }
    // 获取inputWindowHandleObj关联的Native层InputWindowHandle
    sp inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
    // 注册输入通道
    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
    ......
    }

NativeInputManagerregisterInputChannel()最终调用InputDispatcherregisterInputChannel().

status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
        const sp& inputWindowHandle, bool monitor) {
    ......
    { // acquire lock
        AutoMutex _l(mLock);
        // 检查是否已经注册过
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }
        // 创建Connection,用于管理关联的InputChannel的事件分发状态
        sp connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        // 添加到mConnectionsByFd容器中
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
        // 监听fd上的I/O操作,当有I/O操作时,回调handleReceiveCallback处理
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    // 唤醒InputDispatcherThread
    mLooper->wake();
    return OK;
}

至此,系统进程的工作已经完成,下面分析应用处理Biner IPC返回的InputChannel, 回到ViewRootImplsetView()

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                ......
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    // 窗口注册到WindowManagerService
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
                ......
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    // 创建WindowInputEventReceiver对象,负责接收输入事件
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ......
    }

我们知道,ViewRootImpl创建的mInputChannel是个空的InputChannel,其内部状态在addToDisplay()返回时才构造完成(原理是跨进程传递文件描述符)。 InputChannel构造完成后,创建WindowInputEventReceiver(继承自InputEventReceiver)用于接收输入事件。下面直接看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");
        }
        // 关联的InputChannel
        mInputChannel = inputChannel;
        // UI线程的消息队列
        mMessageQueue = looper.getQueue();
        // 调用nativeInit
        mReceiverPtr = nativeInit(new WeakReference(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

下面看nativeInit()的实现

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    // 获取Native层的InputChannel
    sp inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        jniThrowRuntimeException(env, "InputChannel is not initialized.");
        return 0;
    }
    // 获取Native层的NativeMessageQueue
    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    // 创建NativeInputEventReceiver对象
    sp receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    // 监听InputChannel
    status_t status = receiver->initialize();
    ......
    }

下面看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) {
            // 监听套接字fd,当收到输入事件时,回调NativeInputEventReceiver的handleEvent
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

你可能感兴趣的:(Android应用与Input子系统建立连接)