Android Activity 接收按键原理分析(1)

之所以Activity能够接收到来自底层的Keyevent是因为在显示时创建了一个InputChannel。当底层有按键事件时就会通过这个InputChannel传递上来。

View的初始化

在启动一个activity时将会调用ViewRootImpl.setView()函数。下面将这个函数中的主要部分给出:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	····
	if ((mWindowAttributes.inputFeatures
			& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
		//这个对应client端,将InputEvent传递给view
		mInputChannel = new InputChannel();
	}
	try {
		mOrigWindowType = mWindowAttributes.type;
		mAttachInfo.mRecomputeGlobalAttributes = true;
		collectViewAttributes();
		res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
				getHostVisibility(), mDisplay.getDisplayId(),
				mAttachInfo.mContentInsets, mInputChannel);
	} catch (RemoteException e) {}
	···
	if (mInputChannel != null) {
		if (mInputQueueCallback != null) {
			mInputQueue = new InputQueue();
			mInputQueueCallback.onInputQueueCreated(mInputQueue);
		}
	//mInputChannel注册到native层
	mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
			Looper.myLooper());
	}
	···
}

上面段代码中主要进行了三个动作:
1.创建一个Java层的InputChannel,这个InputChannel后面用来创建两个socket,一个是client端,app使用它接收按键信息;一个是server端,底层将按键信息写入server端
2.调用WindowSession.addToDisplay,向系统中添加session
3.注册WindowInputEventReceiver,当client端有消息时,通知view来消息。

下面看一下WindowSession.addToDisplay的实现

@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
		int viewVisibility, int displayId, Rect outContentInsets,
		InputChannel outInputChannel) {
	return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
			outContentInsets, outInputChannel);
}

这里面的mService实际上就是WindowManagerService

public int addWindow(Session session, IWindow client, int seq,
		WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
		Rect outContentInsets, InputChannel outInputChannel) {
		
		win = new WindowState(this, session, client, token,	attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

		if (outInputChannel != null && (attrs.inputFeatures
				& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
			String name = win.makeInputChannelName();//这个就是创建一个关于这个view的字符串
			InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);//调用InputChannel创建两个socket
			win.setInputChannel(inputChannels[0]);//server channel
			inputChannels[1].transferTo(outInputChannel);//client channel 将Native层的对象转换成Java层的对象

			mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);//将server socket注册到底层
		}
		
}
Server端socket注册

下面看一下这个registerInputChannel函数的实现。

InputManangerService.java

public void registerInputChannel(InputChannel inputChannel,
		InputWindowHandle inputWindowHandle) {
	if (inputChannel == null) {
		throw new IllegalArgumentException("inputChannel must not be null.");
	}

	nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

com_android_server_iinput_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
        jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
		NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);//获取native层的InputManager
		···
		status_t status = im->registerInputChannel(	env, inputChannel, inputWindowHandle, monitor);
		···
}

status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {

    { // acquire lock
        AutoMutex _l(mLock);
		//检查这个channel是否存在
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }

        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
		//将这个fd注册到looper中。用来接收来自framework层的消息,并且调用handleReceiveCallback进行处理
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

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

至此就已经将Server端的socket注册到了Looper中了。至于addFd函数的实现,请参考Native层的Looper.cpp。

Client端socket注册

Client端socket注册实在创建WindowInputEventReceiver对象时注册的。
下面看一下 WindowInputEventReceiver类

ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {}
InputEventReceiver.java
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");
	}

	mInputChannel = inputChannel;
	mMessageQueue = looper.getQueue();
	mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
			inputChannel, mMessageQueue);

	mCloseGuard.open("dispose");
}

在初始化函数时就会调用nativeInit JNI函数。

android_view_InputEventReceiver.cpp
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
	//将java层的对象转换成c中的对象
	sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,	inputChannelObj);
	sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
	···
	sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
		receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
}
android_view_InputEventReceiver.cpp
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<InputChannel>& inputChannel,
        const sp<MessageQueue>& messageQueue) :
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mInputConsumer(inputChannel), mMessageQueue(messageQueue),
        mBatchedInputEventPending(false), mFdEvents(0) {
}

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) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

上面就是将mInputConsumer的中Channel的fd注册到looper中。其中Channel就是传递下来的client端的socket。至此client端的socket也已经注册完毕。后面就是利用Server/Client socket进行通讯,实现按键信息的传递。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值