Android入门之在客户进程中注册InputChannel

本文详细解析了 Android 系统中 InputChannel 的注册过程,包括 server 和 client 端的注册机制,并介绍了 ViewRoot 如何通过 InputQueue.registerInputChannel 方法完成客户端 InputChannel 的注册。

        上文说到,在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);
}

        注意到被注册的是win.mInputChannel,也就是inputChannels[0],inputChannels[0]是什么?再看创建InputChannel的过程,发现以下代码:

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<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        LOGE("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, "Could not open input channel pair.");
        return NULL;
    }

    // TODO more robust error checking
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(serverChannel));
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));

    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

        倒数第三行表明,inputChannels[0]是serverChannel,也就是说,在WmS中注册的仅仅是serverChannel,那么clientChannel需要注册吗?什么时候注册的?

        我们一直在说,应用程序创建窗口时,通过ViewRoot调用WmS的session的addWindow方法创建窗口,来看ViewRoot的代码,在frameworks/base/core/java/android.view.ViewRoot.java的第497行,发现如下代码:

res = sWindowSession.add(mWindow, mWindowAttributes,
		getHostVisibility(), mAttachInfo.mContentInsets,
		mInputChannel);

        判断此代码即是使用session添加Window的方法,接着往下看,发现以下代码:

if (mInputQueueCallback != null) {
	mInputQueue = new InputQueue(mInputChannel);
	mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
	InputQueue.registerInputChannel(mInputChannel, mInputHandler,
			Looper.myQueue());
}

        InputQueue.registerInputChannel即为客户端注册InputChannel的方法,也就是说,在ViewRoot中IPC调用addWindow()返回后,接下来就需要把该InputChannel注册到本线程中,而ViewRoot通过InputQueue.registerInputChannel注册InputChannel。

        InputQueue.registerInputChannel方法如下所示:

/**
 * Registers an input channel and handler.
 * @param inputChannel The input channel to register.
 * @param inputHandler The input handler to input events send to the target.
 * @param messageQueue The message queue on whose thread the handler should be invoked.
 * @hide
 */
public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,
		MessageQueue messageQueue) {
	if (inputChannel == null) {
		throw new IllegalArgumentException("inputChannel must not be null");
	}
	if (inputHandler == null) {
		throw new IllegalArgumentException("inputHandler must not be null");
	}
	if (messageQueue == null) {
		throw new IllegalArgumentException("messageQueue must not be null");
	}
	
	synchronized (sLock) {
		if (DEBUG) {
			Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
		}
		
		nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
	}
}

        你会发现它其实主要调用了nativeRegisterInputChannel,也就是android_view_InputQueue的registerInputChannel方法来完成注册,该方法如下 所示:

status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,
        jobject inputHandlerObj, jobject messageQueueObj) {
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        LOGW("Input channel is not initialized.");
        return BAD_VALUE;
    }

#if DEBUG_REGISTRATION
    LOGD("channel '%s' - Registered", inputChannel->getName().string());
#endif

    sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);

    { // acquire lock
        AutoMutex _l(mLock);

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

        uint16_t connectionId = mNextConnectionId++;
        sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
        status_t result = connection->inputConsumer.initialize();
        if (result) {
            LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
                    inputChannel->getName().string(), result);
            return result;
        }

        connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);

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

        looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, this);
    return OK;
}

        这段代码与serverChannel的区别不大,不再细述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值