这篇博客我们接上面一篇博客,回答上篇博客中,最后的connection对象是如何来的。
一、InputManagerService的registerInputChannel方法
我们先从InputManagerService的registerInputChannel方法分析:
- public void registerInputChannel(InputChannel inputChannel,
- InputWindowHandle inputWindowHandle) {
- if (inputChannel == null) {
- throw new IllegalArgumentException("inputChannel must not be null.");
- }
-
- nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
- }
再来看看nativeRegisterInputChannel函数
- static void nativeRegisterInputChannel(JNIEnv* env, jclass ,
- jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
- NativeInputManager* im = reinterpret_cast(ptr);
-
- ......
- sp inputWindowHandle =
- android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
-
- status_t status = im->registerInputChannel(
- env, inputChannel, inputWindowHandle, monitor);
- ......
- }
最后调用了NativeInputManager的registerInputChannel函数
- status_t NativeInputManager::registerInputChannel(JNIEnv* ,
- const sp& inputChannel,
- const sp& inputWindowHandle, bool monitor) {
- return mInputManager->getDispatcher()->registerInputChannel(
- inputChannel, inputWindowHandle, monitor);
- }
而这个函数,最终是调用了InputDispatcher的registerInputChannel函数:
- status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
- const sp& inputWindowHandle, bool monitor) {
-
- {
- AutoMutex _l(mLock);
-
- if (getConnectionIndexLocked(inputChannel) >= 0) {
- ALOGW("Attempted to register already registered input channel '%s'",
- inputChannel->getName().string());
- return BAD_VALUE;
- }
-
- sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
-
- int fd = inputChannel->getFd();
- mConnectionsByFd.add(fd, connection);
-
- if (monitor) {
- mMonitoringChannels.push(inputChannel);
- }
-
- mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
- }
-
-
- mLooper->wake();
- return OK;
- }
在这个函数中创建了一个Connection对象,并把这个对象加入列表中。如果有多个Connection,那么分发的消息是发给那个Connection呢,前面dispatchKeyLocked函数会调用函数findFocusedWindowTargetsLocked得到当前拥有焦点的窗口的InputChannel信息,然后再调用getConnectionIndexLocked函数得到mConnectionsByFd列表中和InputChannel关联的Connection对象的index。
- ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) {
- ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
- if (connectionIndex >= 0) {
- sp connection = mConnectionsByFd.valueAt(connectionIndex);
- if (connection->inputChannel.get() == inputChannel.get()) {
- return connectionIndex;
- }
- }
-
- return -1;
- }
有了这个index也就得到了conection对象了,现在我们知道了上篇博客最后startDispatchCycleLocked函数中使用的Connection对象其实是和当前有焦点的窗口关联的对象。
下面我们继续分析它的inputPublisher成员的publishKeyEvent函数:
- status_t InputPublisher::publishKeyEvent(
-
- ......
- InputMessage msg;
- msg.header.type = InputMessage::TYPE_KEY;
- ......
- return mChannel->sendMessage(&msg);
- }
publishKeyEvent函数调用了mChannel的sendMessage函数,这个mChannel是创建Connection对象时的参数InputChannel。
这边的InputChannel是前面nativeRegisterInputChannel中的android_view_InputChannel_getInputChannel函数中获取。
- static void nativeRegisterInputChannel(JNIEnv* env, jclass ,
- jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
- NativeInputManager* im = reinterpret_cast(ptr);
-
- sp inputChannel = android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- if (inputChannel == NULL) {
- throwInputChannelNotInitialized(env);
- return;
- }
-
- sp inputWindowHandle =
- android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
-
- status_t status = im->registerInputChannel(
- env, inputChannel, inputWindowHandle, monitor);
- if (status) {
- String8 message;
- message.appendFormat("Failed to register input channel. status=%d", status);
- jniThrowRuntimeException(env, message.string());
- return;
- }
-
- if (! monitor) {
- android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
- handleInputChannelDisposed, im);
- }
- }
我们再来看下android_view_InputChannel_getInputChannel方法
- sp android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
- NativeInputChannel* nativeInputChannel =
- android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
- return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
- }
- static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
- jobject inputChannelObj) {
- jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
- return reinterpret_cast(longPtr);
- }
最后NativeInputChannel对象的指针保存在Java层的InputChannel对象的mPtr中。
于是我们知道最后InputDispatcher发送按键消息到应用进程的对象,是java层的InputChannel对象对应的native层的NativeInputChannel对象的sendMessage函数发送消息。
二、InputChannel的从创建
接下来我们再来看看java层的InputChannel是什么时候创建的呢?
ViewRootImpl的setView中有这段代码:
- if ((mWindowAttributes.inputFeatures
- & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
- mInputChannel = new InputChannel();
- }
- try {
- mOrigWindowType = mWindowAttributes.type;
- mAttachInfo.mRecomputeGlobalAttributes = true;
- collectViewAttributes();
- res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(),
- mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mInputChannel);
- }
setView方法中如果Window的属性能接受输入,而且还没有创建InputChannel,则会新创建一个InputChannel对象。这个对象会通过mWindowSession的addToDisplay方法传递到WindowManagerService中,最后再会调用WMS的addWindow方法,addWindow有下面这段代码:
- if (outInputChannel != null && (attrs.inputFeatures
- & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
- String name = win.makeInputChannelName();
- InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
- win.setInputChannel(inputChannels[0]);
- inputChannels[1].transferTo(outInputChannel);
-
- mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
- }
阿灾addWIndow方法中先调用了InputChannel的openInputChannelPair来返回一个InputChannel对象的数组,然后将inputChannel[0]设置到win中去。接着inputChannel[1]转换成和客户端传递过来的outInputChannel对象,最后调用了InputManagerService中的registerInputChannel方法。现在整个脉络都清晰了。
先来看下openInputChannelPair函数
- public static InputChannel[] openInputChannelPair(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name must not be null");
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Opening input channel pair '" + name + "'");
- }
- return nativeOpenInputChannelPair(name);
- }
调用了nativeOpenInputChannelPair函数:
- 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;
- 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;
- }
-
- jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
- if (env->ExceptionCheck()) {
- return NULL;
- }
-
- jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(serverChannel));
- if (env->ExceptionCheck()) {
- return NULL;
- }
-
- jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(clientChannel));
- if (env->ExceptionCheck()) {
- return NULL;
- }
-
- env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
- env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
- return channelPair;
- }
上面函数现在InputChannel::openInputChannelPair创建了socketpair,我们来看下:
- 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;
- }
-
- 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)");
- outServerChannel = new InputChannel(serverChannelName, sockets[0]);
-
- String8 clientChannelName = name;
- clientChannelName.append(" (client)");
- outClientChannel = new InputChannel(clientChannelName, sockets[1]);
- return OK;
- }
然后又调用了android_view_InputChannel_createInputChannel(env, new NativeInputChannel(serverChannel));
- static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
- NativeInputChannel* nativeInputChannel) {
- jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
- gInputChannelClassInfo.ctor);
- if (inputChannelObj) {
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
- }
- return inputChannelObj;
- }
android_view_InputChannel_setNativeInputChannel函数
- static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
- NativeInputChannel* nativeInputChannel) {
- env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
- reinterpret_cast(nativeInputChannel));
- }
android_view_InputChannel_setNativeInputChannel函数包native层的NativeInputChannel对象指针保存到了java层的InputChannel对象的mPtr成员变量中。
前面我们还看到WMS的addWindow方法会调用InputChannel[1]的transferTo方法:
- public void transferTo(InputChannel outParameter) {
- if (outParameter == null) {
- throw new IllegalArgumentException("outParameter must not be null");
- }
-
- nativeTransferTo(outParameter);
- }
android_view_InputChannel_nativeTransferTo函数的功能就是将调用对象的mPtr的值放到参数对象的mPtr中,并将调用对象的mPtr设置为NULL。
- static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
- jobject otherObj) {
- if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Other object already has a native input channel.");
- return;
- }
-
- NativeInputChannel* nativeInputChannel =
- android_view_InputChannel_getNativeInputChannel(env, obj);
- android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
- android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
- }
这样最后WMS调用addWindow后,outChannel中的值就是sockpair的客户端。
三、应用进程接受按键消息
前面最后会调用InputChannel的sendMessage函数,最后实际是调用了sockpair的一个fd的send函数,这样另外一个fd也就是应用端的进程会有响应。
前面ViewRootImpl的setView函数调用了addToDisplay得到InputChannel对象后,创建了WindowInputEventReceiver对象。
- mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
- Looper.myLooper());
我们先来看下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");
- }
-
- mInputChannel = inputChannel;
- mMessageQueue = looper.getQueue();
- mReceiverPtr = nativeInit(new WeakReference(this),
- inputChannel, mMessageQueue);
-
- mCloseGuard.open("dispose");
- }
nativeInit中新建了NativeInputEventReceiver对象,然后调用了initialize函数:
- static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
- jobject inputChannelObj, jobject messageQueueObj) {
- sp inputChannel = android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- if (inputChannel == NULL) {
- jniThrowRuntimeException(env, "InputChannel is not initialized.");
- return 0;
- }
-
- sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
- if (messageQueue == NULL) {
- jniThrowRuntimeException(env, "MessageQueue is not initialized.");
- return 0;
- }
-
- sp receiver = new NativeInputEventReceiver(env,
- receiverWeak, inputChannel, messageQueue);
- status_t status = receiver->initialize();
- if (status) {
- String8 message;
- message.appendFormat("Failed to initialize input event receiver. status=%d", status);
- jniThrowRuntimeException(env, message.string());
- return 0;
- }
-
- receiver->incStrong(gInputEventReceiverClassInfo.clazz);
- return reinterpret_cast(receiver.get());
- }
NativeInputEventReceiver::initialize函数
- status_t NativeInputEventReceiver::initialize() {
- setFdEvents(ALOOPER_EVENT_INPUT);
- return OK;
- }
setFdEvents函数又调用的addFd函数,这个之前分析过就不分析了,是将这个fd加入到线程的epoll中,并且把this作为回调。
- 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);
- }
- }
- }
因此handleEvent是作为回调函数被epoll回调
- int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
- if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
-
-
-
- if (kDebugDispatchCycle) {
- ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
- "events=0x%x", getInputChannelName(), events);
- }
- return 0;
- }
-
- if (events & ALOOPER_EVENT_INPUT) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- status_t status = consumeEvents(env, false , -1, NULL);
- mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
- return status == OK || status == NO_MEMORY ? 1 : 0;
- }
然后这个函数中调用了consumeEvents函数,有如下一段代码:
- if (inputEventObj) {
- if (kDebugDispatchCycle) {
- ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
- }
- env->CallVoidMethod(receiverObj.get(),
- gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
- if (env->ExceptionCheck()) {
- ALOGE("Exception dispatching input event.");
- skipCallbacks = true;
- }
这函数中又调用了java层的WindowInputEventReceiver的dispatchInputEvent函数,因为WindowInputEventReceiver没有dispatchInputEvent函数就调用了父类的dispatchInputEvent函数
- @SuppressWarnings("unused")
- private void dispatchInputEvent(int seq, InputEvent event) {
- mSeqMap.put(event.getSequenceNumber(), seq);
- onInputEvent(event);
- }
最后调用了ViewRootImpl中的WindowInputEventReceiver 的onInputEvent函数:
- final class WindowInputEventReceiver extends InputEventReceiver {
- public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
-
- @Override
- public void onInputEvent(InputEvent event) {
- enqueueInputEvent(event, this, 0, true);
- }
-
- @Override
- public void onBatchedInputEventPending() {
- if (mUnbufferedInputDispatch) {
- super.onBatchedInputEventPending();
- } else {
- scheduleConsumeBatchedInput();
- }
- }
-
- @Override
- public void dispose() {
- unscheduleConsumeBatchedInput();
- super.dispose();
- }
- }
这样到应用进程的流程分析结束了,下面就是将上层应用进程是如何处理这按键消息的,这个要后续分析了。
转载地址
http://blog.csdn.net/kc58236582/article/details/50611522