Android入门之在WmS中注册InputChannel

        上文描述了InputChannel的创建过程,在WmS的addWindow中,创建InputChannel后紧接着的是注册InputChannel:

if (outInputChannel != null) {
	String name = win.makeInputChannelName();
	InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
	win.mInputChannel = inputChannels[0];
	inputChannels[1].transferToBinderOutParameter(outInputChannel);
	
	mInputManager.registerInputChannel(win.mInputChannel);
}

        InputManager.java中的registerInputChannel方法调用了nativeRegisterInputChannel,也就是com_android_server_InputChannel.cpp的registerInputChannel方法:

// InputManager.java
/**
 * Registers an input channel so that it can be used as an input event target.
 * @param inputChannel The input channel to register.
 */
public void registerInputChannel(InputChannel inputChannel) {
	if (inputChannel == null) {
		throw new IllegalArgumentException("inputChannel must not be null.");
	}
	
	nativeRegisterInputChannel(inputChannel, false);
}

// com_android_server_InputChannel.cpp
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp& inputChannel, jobject inputChannelObj, bool monitor) {
    jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj);
    if (! inputChannelObjWeak) {
        LOGE("Could not create weak reference for input channel.");
        LOGE_EX(env);
        return NO_MEMORY;
    }

    status_t status;
    {
        AutoMutex _l(mInputChannelRegistryLock);

        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
        if (index >= 0) {
            LOGE("Input channel object '%s' has already been registered",
                    inputChannel->getName().string());
            status = INVALID_OPERATION;
            goto DeleteWeakRef;
        }

        mInputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak);
    }

    status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor);
    if (! status) {
        // Success.
        return OK;
    }

    // Failed!
    {
        AutoMutex _l(mInputChannelRegistryLock);
        mInputChannelObjWeakTable.removeItem(inputChannel.get());
    }

DeleteWeakRef:
    env->DeleteWeakGlobalRef(inputChannelObjWeak);
    return status;
}

        再进入InputDispatcher.cpp的registerInputChannel函数:

status_t InputDispatcher::registerInputChannel(const sp& inputChannel, bool monitor) {
#if DEBUG_REGISTRATION
    LOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
            toString(monitor));
#endif

    { // acquire lock
        AutoMutex _l(mLock);

        if (getConnectionIndexLocked(inputChannel) >= 0) {
            LOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }

        sp connection = new Connection(inputChannel);
        status_t status = connection->initialize();
        if (status) {
            LOGE("Failed to initialize input publisher for input channel '%s', status=%d",
                    inputChannel->getName().string(), status);
            return status;
        }

        int32_t receiveFd = inputChannel->getReceivePipeFd();
        mConnectionsByReceiveFd.add(receiveFd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }

        mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);

        runCommandsLockedInterruptible();
    } // release lock
    return OK;
}

        注册的主要实现在InputDispatcher中:

        (1) 创建一个Connection对象,把创建的InputChannel给Connection的内部对象,并初始化Connection;

        (2) 获得该InputChannel的receivePipeFd,代码定义在frameworks/base/included/ui/InputTransport.h中:

inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
        receivePipeFd对应的是reverse[0]描述符。
        (3) 把创建的Connection对象加入到InputDispatcher的mConnectionByReceiverFd列表中,换句话说,InputDispatcher和每一个serverChannel并不直接打交道,而是先把serverChannel转换为一个Connection对象,然后再操作这个Connection对象。

        (4) 调用mLooper.addFd()把receiverFd添加到Looper内部的接收描述符列表中。

        native环境中的Looper类可以监控管道文件描述符,当该管道收到数据时会提到一个通知,所以无论是InputReader线程发往InputDispatcher的消息,还是客户窗口发送到InputDispatcher的消息,Looper类都可以监控到,从而InputReader可以接收到消息。

你可能感兴趣的:(Android)