Android6.0 按键流程 registerInputChannel函数(四)

这篇博客我们接上面一篇博客,回答上篇博客中,最后的connection对象是如何来的。


一、InputManagerService的registerInputChannel方法

我们先从InputManagerService的registerInputChannel方法分析:

[cpp] view plain copy
  1. public void registerInputChannel(InputChannel inputChannel,  
  2.         InputWindowHandle inputWindowHandle) {  
  3.     if (inputChannel == null) {  
  4.         throw new IllegalArgumentException("inputChannel must not be null.");  
  5.     }  
  6.   
  7.     nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);  
  8. }  

再来看看nativeRegisterInputChannel函数

[cpp] view plain copy
  1. static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,  
  2.         jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {  
  3.     NativeInputManager* im = reinterpret_cast(ptr);  
  4.   
  5.     ......  
  6.     sp inputWindowHandle =  
  7.             android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);  
  8.   
  9.     status_t status = im->registerInputChannel(  
  10.             env, inputChannel, inputWindowHandle, monitor);  
  11.     ......  
  12. }  

最后调用了NativeInputManager的registerInputChannel函数

[cpp] view plain copy
  1. status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,  
  2.         const sp& inputChannel,  
  3.         const sp& inputWindowHandle, bool monitor) {  
  4.     return mInputManager->getDispatcher()->registerInputChannel(  
  5.             inputChannel, inputWindowHandle, monitor);  
  6. }  

而这个函数,最终是调用了InputDispatcher的registerInputChannel函数:

[cpp] view plain copy
  1. status_t InputDispatcher::registerInputChannel(const sp& inputChannel,  
  2.         const sp& inputWindowHandle, bool monitor) {  
  3.   
  4.     { // acquire lock  
  5.         AutoMutex _l(mLock);  
  6.   
  7.         if (getConnectionIndexLocked(inputChannel) >= 0) {  
  8.             ALOGW("Attempted to register already registered input channel '%s'",  
  9.                     inputChannel->getName().string());  
  10.             return BAD_VALUE;  
  11.         }  
  12.   
  13.         sp connection = new Connection(inputChannel, inputWindowHandle, monitor);//新建了一个connection  
  14.   
  15.         int fd = inputChannel->getFd();  
  16.         mConnectionsByFd.add(fd, connection);//把connection加入列表中  
  17.   
  18.         if (monitor) {  
  19.             mMonitoringChannels.push(inputChannel);  
  20.         }  
  21.   
  22.         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);//加入epoll检测中  
  23.     } // release lock  
  24.   
  25.     // Wake the looper because some connections have changed.  
  26.     mLooper->wake();  
  27.     return OK;  
  28. }  

在这个函数中创建了一个Connection对象,并把这个对象加入列表中。如果有多个Connection,那么分发的消息是发给那个Connection呢,前面dispatchKeyLocked函数会调用函数findFocusedWindowTargetsLocked得到当前拥有焦点的窗口的InputChannel信息,然后再调用getConnectionIndexLocked函数得到mConnectionsByFd列表中和InputChannel关联的Connection对象的index。

[cpp] view plain copy
  1. ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) {  
  2.     ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());  
  3.     if (connectionIndex >= 0) {  
  4.         sp connection = mConnectionsByFd.valueAt(connectionIndex);  
  5.         if (connection->inputChannel.get() == inputChannel.get()) {  
  6.             return connectionIndex;  
  7.         }  
  8.     }  
  9.   
  10.     return -1;  
  11. }  

有了这个index也就得到了conection对象了,现在我们知道了上篇博客最后startDispatchCycleLocked函数中使用的Connection对象其实是和当前有焦点的窗口关联的对象。

下面我们继续分析它的inputPublisher成员的publishKeyEvent函数:

[cpp] view plain copy
  1. status_t InputPublisher::publishKeyEvent(  
  2.        
  3.     ......  
  4.     InputMessage msg;  
  5.     msg.header.type = InputMessage::TYPE_KEY;  
  6.     ......  
  7.     return mChannel->sendMessage(&msg);  
  8. }  

publishKeyEvent函数调用了mChannel的sendMessage函数,这个mChannel是创建Connection对象时的参数InputChannel。


这边的InputChannel是前面nativeRegisterInputChannel中的android_view_InputChannel_getInputChannel函数中获取。

[cpp] view plain copy
  1. static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,  
  2.         jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {  
  3.     NativeInputManager* im = reinterpret_cast(ptr);  
  4.   
  5.     sp inputChannel = android_view_InputChannel_getInputChannel(env,  
  6.             inputChannelObj);  
  7.     if (inputChannel == NULL) {  
  8.         throwInputChannelNotInitialized(env);  
  9.         return;  
  10.     }  
  11.   
  12.     sp inputWindowHandle =  
  13.             android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);  
  14.   
  15.     status_t status = im->registerInputChannel(  
  16.             env, inputChannel, inputWindowHandle, monitor);  
  17.     if (status) {  
  18.         String8 message;  
  19.         message.appendFormat("Failed to register input channel.  status=%d", status);  
  20.         jniThrowRuntimeException(env, message.string());  
  21.         return;  
  22.     }  
  23.   
  24.     if (! monitor) {  
  25.         android_view_InputChannel_setDisposeCallback(env, inputChannelObj,  
  26.                 handleInputChannelDisposed, im);  
  27.     }  
  28. }  
我们再来看下android_view_InputChannel_getInputChannel方法
[cpp] view plain copy
  1. sp android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {  
  2.     NativeInputChannel* nativeInputChannel =  
  3.             android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);  
  4.     return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;  
  5. }  


[cpp] view plain copy
  1. static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,  
  2.         jobject inputChannelObj) {  
  3.     jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);  
  4.     return reinterpret_cast(longPtr);  
  5. }  

最后NativeInputChannel对象的指针保存在Java层的InputChannel对象的mPtr中。

于是我们知道最后InputDispatcher发送按键消息到应用进程的对象,是java层的InputChannel对象对应的native层的NativeInputChannel对象的sendMessage函数发送消息。


二、InputChannel的从创建

接下来我们再来看看java层的InputChannel是什么时候创建的呢?

ViewRootImpl的setView中有这段代码:

[cpp] view plain copy
  1. if ((mWindowAttributes.inputFeatures  
  2.         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  3.     mInputChannel = new InputChannel();  
  4. }  
  5. try {  
  6.     mOrigWindowType = mWindowAttributes.type;  
  7.     mAttachInfo.mRecomputeGlobalAttributes = true;  
  8.     collectViewAttributes();  
  9.     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,  
  10.             getHostVisibility(), mDisplay.getDisplayId(),  
  11.             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,  
  12.             mAttachInfo.mOutsets, mInputChannel);  
  13. }   

setView方法中如果Window的属性能接受输入,而且还没有创建InputChannel,则会新创建一个InputChannel对象。这个对象会通过mWindowSession的addToDisplay方法传递到WindowManagerService中,最后再会调用WMS的addWindow方法,addWindow有下面这段代码:

[cpp] view plain copy
  1. if (outInputChannel != null && (attrs.inputFeatures  
  2.         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  3.     String name = win.makeInputChannelName();  
  4.     InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  5.     win.setInputChannel(inputChannels[0]);  
  6.     inputChannels[1].transferTo(outInputChannel);  
  7.   
  8.     mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
  9. }  
阿灾addWIndow方法中先调用了InputChannel的openInputChannelPair来返回一个InputChannel对象的数组,然后将inputChannel[0]设置到win中去。接着inputChannel[1]转换成和客户端传递过来的outInputChannel对象,最后调用了InputManagerService中的registerInputChannel方法。现在整个脉络都清晰了。


先来看下openInputChannelPair函数

[cpp] view plain copy
  1. public static InputChannel[] openInputChannelPair(String name) {  
  2.     if (name == null) {  
  3.         throw new IllegalArgumentException("name must not be null");  
  4.     }  
  5.   
  6.     if (DEBUG) {  
  7.         Slog.d(TAG, "Opening input channel pair '" + name + "'");  
  8.     }  
  9.     return nativeOpenInputChannelPair(name);  
  10. }  

调用了nativeOpenInputChannelPair函数:

[cpp] view plain copy
  1. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,  
  2.         jclass clazz, jstring nameObj) {  
  3.     const char* nameChars = env->GetStringUTFChars(nameObj, NULL);  
  4.     String8 name(nameChars);  
  5.     env->ReleaseStringUTFChars(nameObj, nameChars);  
  6.   
  7.     sp serverChannel;  
  8.     sp clientChannel;  
  9.     status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);//创建socketpair  
  10.   
  11.     if (result) {  
  12.         String8 message;  
  13.         message.appendFormat("Could not open input channel pair.  status=%d", result);  
  14.         jniThrowRuntimeException(env, message.string());  
  15.         return NULL;  
  16.     }  
  17.   
  18.     jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);  
  19.     if (env->ExceptionCheck()) {  
  20.         return NULL;  
  21.     }  
  22.   
  23.     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,  
  24.             new NativeInputChannel(serverChannel));  
  25.     if (env->ExceptionCheck()) {  
  26.         return NULL;  
  27.     }  
  28.   
  29.     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,  
  30.             new NativeInputChannel(clientChannel));  
  31.     if (env->ExceptionCheck()) {  
  32.         return NULL;  
  33.     }  
  34.   
  35.     env->SetObjectArrayElement(channelPair, 0, serverChannelObj);  
  36.     env->SetObjectArrayElement(channelPair, 1, clientChannelObj);  
  37.     return channelPair;  
  38. }  

上面函数现在InputChannel::openInputChannelPair创建了socketpair,我们来看下:

[cpp] view plain copy
  1. status_t InputChannel::openInputChannelPair(const String8& name,  
  2.         sp& outServerChannel, sp& outClientChannel) {  
  3.     int sockets[2];  
  4.     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {//创建socketpair  
  5.         status_t result = -errno;  
  6.         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",  
  7.                 name.string(), errno);  
  8.         outServerChannel.clear();  
  9.         outClientChannel.clear();  
  10.         return result;  
  11.     }  
  12.   
  13.     int bufferSize = SOCKET_BUFFER_SIZE;  
  14.     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  15.     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  16.     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  17.     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  18.   
  19.     String8 serverChannelName = name;  
  20.     serverChannelName.append(" (server)");  
  21.     outServerChannel = new InputChannel(serverChannelName, sockets[0]);//返回值  
  22.   
  23.     String8 clientChannelName = name;  
  24.     clientChannelName.append(" (client)");  
  25.     outClientChannel = new InputChannel(clientChannelName, sockets[1]);//返回值  
  26.     return OK;  
  27. }  

然后又调用了android_view_InputChannel_createInputChannel(env, new NativeInputChannel(serverChannel));

[cpp] view plain copy
  1. static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,  
  2.         NativeInputChannel* nativeInputChannel) {  
  3.     jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,  
  4.             gInputChannelClassInfo.ctor);//创建java层的InputChannel对象  
  5.     if (inputChannelObj) {  
  6.         android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);  
  7.     }  
  8.     return inputChannelObj;  
  9. }  

android_view_InputChannel_setNativeInputChannel函数

[cpp] view plain copy
  1. static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,  
  2.         NativeInputChannel* nativeInputChannel) {  
  3.     env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,  
  4.              reinterpret_cast(nativeInputChannel));  
  5. }  

android_view_InputChannel_setNativeInputChannel函数包native层的NativeInputChannel对象指针保存到了java层的InputChannel对象的mPtr成员变量中。

前面我们还看到WMS的addWindow方法会调用InputChannel[1]的transferTo方法:

[cpp] view plain copy
  1. public void transferTo(InputChannel outParameter) {  
  2.     if (outParameter == null) {  
  3.         throw new IllegalArgumentException("outParameter must not be null");  
  4.     }  
  5.       
  6.     nativeTransferTo(outParameter);  
  7. }  
android_view_InputChannel_nativeTransferTo函数的功能就是将调用对象的mPtr的值放到参数对象的mPtr中,并将调用对象的mPtr设置为NULL。
[cpp] view plain copy
  1. static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,  
  2.         jobject otherObj) {  
  3.     if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {  
  4.         jniThrowException(env, "java/lang/IllegalStateException",  
  5.                 "Other object already has a native input channel.");  
  6.         return;  
  7.     }  
  8.   
  9.     NativeInputChannel* nativeInputChannel =  
  10.             android_view_InputChannel_getNativeInputChannel(env, obj);  
  11.     android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);  
  12.     android_view_InputChannel_setNativeInputChannel(env, obj, NULL);  
  13. }  
这样最后WMS调用addWindow后,outChannel中的值就是sockpair的客户端。


三、应用进程接受按键消息

前面最后会调用InputChannel的sendMessage函数,最后实际是调用了sockpair的一个fd的send函数,这样另外一个fd也就是应用端的进程会有响应。

前面ViewRootImpl的setView函数调用了addToDisplay得到InputChannel对象后,创建了WindowInputEventReceiver对象。

[cpp] view plain copy
  1. mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,  
  2.         Looper.myLooper());  


我们先来看下InputEventReceiver的构造函数:

[cpp] view plain copy
  1. public InputEventReceiver(InputChannel inputChannel, Looper looper) {  
  2.     if (inputChannel == null) {  
  3.         throw new IllegalArgumentException("inputChannel must not be null");  
  4.     }  
  5.     if (looper == null) {  
  6.         throw new IllegalArgumentException("looper must not be null");  
  7.     }  
  8.   
  9.     mInputChannel = inputChannel;  
  10.     mMessageQueue = looper.getQueue();  
  11.     mReceiverPtr = nativeInit(new WeakReference(this),  
  12.             inputChannel, mMessageQueue);  
  13.   
  14.     mCloseGuard.open("dispose");  
  15. }  
nativeInit中新建了NativeInputEventReceiver对象,然后调用了initialize函数:
[cpp] view plain copy
  1. static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,  
  2.         jobject inputChannelObj, jobject messageQueueObj) {  
  3.     sp inputChannel = android_view_InputChannel_getInputChannel(env,  
  4.             inputChannelObj);  
  5.     if (inputChannel == NULL) {  
  6.         jniThrowRuntimeException(env, "InputChannel is not initialized.");  
  7.         return 0;  
  8.     }  
  9.   
  10.     sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
  11.     if (messageQueue == NULL) {  
  12.         jniThrowRuntimeException(env, "MessageQueue is not initialized.");  
  13.         return 0;  
  14.     }  
  15.   
  16.     sp receiver = new NativeInputEventReceiver(env,  
  17.             receiverWeak, inputChannel, messageQueue);  
  18.     status_t status = receiver->initialize();  
  19.     if (status) {  
  20.         String8 message;  
  21.         message.appendFormat("Failed to initialize input event receiver.  status=%d", status);  
  22.         jniThrowRuntimeException(env, message.string());  
  23.         return 0;  
  24.     }  
  25.   
  26.     receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object  
  27.     return reinterpret_cast(receiver.get());  
  28. }  

NativeInputEventReceiver::initialize函数

[cpp] view plain copy
  1. status_t NativeInputEventReceiver::initialize() {  
  2.     setFdEvents(ALOOPER_EVENT_INPUT);  
  3.     return OK;  
  4. }  

setFdEvents函数又调用的addFd函数,这个之前分析过就不分析了,是将这个fd加入到线程的epoll中,并且把this作为回调。

[cpp] view plain copy
  1. void NativeInputEventReceiver::setFdEvents(int events) {  
  2.     if (mFdEvents != events) {  
  3.         mFdEvents = events;  
  4.         int fd = mInputConsumer.getChannel()->getFd();  
  5.         if (events) {  
  6.             mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);  
  7.         } else {  
  8.             mMessageQueue->getLooper()->removeFd(fd);  
  9.         }  
  10.     }  
  11. }  
因此handleEvent是作为回调函数被epoll回调
[cpp] view plain copy
  1. int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {  
  2.     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {  
  3.         // This error typically occurs when the publisher has closed the input channel  
  4.         // as part of removing a window or finishing an IME session, in which case  
  5.         // the consumer will soon be disposed as well.  
  6.         if (kDebugDispatchCycle) {  
  7.             ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "  
  8.                     "events=0x%x", getInputChannelName(), events);  
  9.         }  
  10.         return 0; // remove the callback  
  11.     }  
  12.   
  13.     if (events & ALOOPER_EVENT_INPUT) {  
  14.         JNIEnv* env = AndroidRuntime::getJNIEnv();  
  15.         status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);  
  16.         mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");  
  17.         return status == OK || status == NO_MEMORY ? 1 : 0;  
  18.     }  

然后这个函数中调用了consumeEvents函数,有如下一段代码:

[cpp] view plain copy
  1. if (inputEventObj) {  
  2.     if (kDebugDispatchCycle) {  
  3.         ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());  
  4.     }  
  5.     env->CallVoidMethod(receiverObj.get(),  
  6.             gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);  
  7.     if (env->ExceptionCheck()) {  
  8.         ALOGE("Exception dispatching input event.");  
  9.         skipCallbacks = true;  
  10.     }  

这函数中又调用了java层的WindowInputEventReceiver的dispatchInputEvent函数,因为WindowInputEventReceiver没有dispatchInputEvent函数就调用了父类的dispatchInputEvent函数

[cpp] view plain copy
  1. @SuppressWarnings("unused")  
  2. private void dispatchInputEvent(int seq, InputEvent event) {  
  3.     mSeqMap.put(event.getSequenceNumber(), seq);  
  4.     onInputEvent(event);  
  5. }  

最后调用了ViewRootImpl中的WindowInputEventReceiver 的onInputEvent函数:

[cpp] view plain copy
  1. final class WindowInputEventReceiver extends InputEventReceiver {  
  2.     public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {  
  3.         super(inputChannel, looper);  
  4.     }  
  5.   
  6.     @Override  
  7.     public void onInputEvent(InputEvent event) {  
  8.         enqueueInputEvent(event, this, 0, true);  
  9.     }  
  10.   
  11.     @Override  
  12.     public void onBatchedInputEventPending() {  
  13.         if (mUnbufferedInputDispatch) {  
  14.             super.onBatchedInputEventPending();  
  15.         } else {  
  16.             scheduleConsumeBatchedInput();  
  17.         }  
  18.     }  
  19.   
  20.     @Override  
  21.     public void dispose() {  
  22.         unscheduleConsumeBatchedInput();  
  23.         super.dispose();  
  24.     }  
  25. }  

这样到应用进程的流程分析结束了,下面就是将上层应用进程是如何处理这按键消息的,这个要后续分析了。


转载地址

http://blog.csdn.net/kc58236582/article/details/50611522

你可能感兴趣的:(Android,基础业务分析)