Android输入系统之InputChannel(上)

26 篇文章 1 订阅
8 篇文章 0 订阅

前面的“锤子快捷键”相关文章已经分析了输入事件的读取,处理,分发。我们知道事件的传递是以window为单位传递的,即server只负责将事件传递给某一个或者多个window,window然后再将事件传递给某一个具体的view。一个activity或者dialog对应一个window,但是事件只传递给合适的window,比如对于按键事件,就必须是获得焦点的window,也就是说只能传递给一个window,通常是最上面的程序。找到了合适的window,然后就是将事件添加到window的Connection的事件队列上。其实,到这为止输入事件还只是在server端,即system_server这个进程里,要想让程序获取到事件,肯定必须将事件信息传递到程序端的进程里。这个就是Connection的实现问题了,这个connection的真正逻辑是InputChannel, InputChannel其实就是linux unix socket的一种封装, unixsocket是linux的一种跨进程通信方式。系统创建InputChannel对即unix socket对,系统server端和程序client各只有其中一个,这样通过unix socket就可以给对方发送消息,而这里的事件就是通过这种方式从系统进程传递到程序进程的。整个系统框架图如下:



系统server端的InputChannel

系统InputChannel的整个处理逻辑如下:

Server端 InputChannel的创建

         Server端 InputChannel是在window被创建的时候创建的:

  1.     //addWindow会创建一个channel对,其实上就是unix socket对,其中一个unix socket  
  2.     //通过传入参数outInputChannel被传递到程序端,  
  3.     //另外一个unix socket保存在server的window中并注册到native的InputManager  
  4.     public int addWindow(Session session, IWindow client, int seq,  
  5.             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  6.             Rect outContentInsets, InputChannel outInputChannel) {  
  7.             //创建window的数据对象WindowState  
  8.             win = new WindowState(this, session, client, token,  
  9.                     attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);  
  10.             if (outInputChannel != null && (attrs.inputFeatures &   
  11.                 WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  12.                 String name = win.makeInputChannelName();  
  13.                 //创建channel对,即会返回两个InputChannel  
  14.                 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  15.                 //一个unix socket保存到window里  
  16.                 win.setInputChannel(inputChannels[0]);  
  17.                 //另外一个unix socket传递到程序端  
  18.                 inputChannels[1].transferTo(outInputChannel);  
  19.                 //这个函数很重要,这个会将server端的unix socket注册到native层  
  20.                 //的InputManager,  win.mInputChannel就是上面的inputChannels[0]  
  21.                 mInputManager.registerInputChannel(win.mInputChannel,   
  22.                        win.mInputWindowHandle);  
  23.             }  
  24.         }  
  25.         return res;  
  26. }  
  27.   
  28. public static InputChannel[] openInputChannelPair(String name) {  
  29.         return nativeOpenInputChannelPair(name);  
  30. }  
  31.   
  32. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,  
  33.         jclass clazz, jstring nameObj) {  
  34.     sp<InputChannel> serverChannel;  
  35.     sp<InputChannel> clientChannel;  
  36.      //创建input channel对  
  37.     status_t result = InputChannel::openInputChannelPair(name,   
  38.          serverChannel, clientChannel);  
  39.     jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);  
  40.     //创建inputChannel对应的java对象  
  41.     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,  
  42.             new NativeInputChannel(serverChannel));  
  43.     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,  
  44.             new NativeInputChannel(clientChannel));  
  45.     //将两个channel放到channel数组中  
  46.     env->SetObjectArrayElement(channelPair, 0, serverChannelObj);  
  47.     env->SetObjectArrayElement(channelPair, 1, clientChannelObj);  
  48.     return channelPair;  
  49. }  
  50. //InputTransport.cpp  
  51. status_t InputChannel::openInputChannelPair(const String8& name,  
  52.         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {  
  53.     int sockets[2];  
  54.     //很早的android 版本是使用双向管道实现的,而是现在是使用unix socket双通道  
  55.     //来通信  
  56.     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  
  57.         return result;  
  58.     }  
  59.   
  60.     int bufferSize = SOCKET_BUFFER_SIZE;  
  61.     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  62.     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  63.     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  64.     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  65.   
  66.     String8 serverChannelName = name;  
  67.     serverChannelName.append(" (server)");  
  68.     //创建InputChannel,并把通信文件句柄传入  
  69.     outServerChannel = new InputChannel(serverChannelName, sockets[0]);  
  70.   
  71.     String8 clientChannelName = name;  
  72.     clientChannelName.append(" (client)");  
  73.     //创建InputChannel,并把通信文件句柄传入  
  74.     outClientChannel = new InputChannel(clientChannelName, sockets[1]);  
  75.     return OK;  
  76. }  

Server端 InputChannel事件监听器安装

         InputDispatcher要能够发送事件数据,必须的要让其知道对应的window的InputChannel,这个通过注册实现的。

  1. public void registerInputChannel(InputChannel inputChannel,  
  2.             InputWindowHandle inputWindowHandle) {          
  3.         nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);  
  4. }  
  5.   
  6. status_t NativeInputManager::registerInputChannel(JNIEnv* env,  
  7.         const sp<InputChannel>& inputChannel,  
  8.         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {  
  9.     //调用InputDispatcher的函数  
  10.     return mInputManager->getDispatcher()->registerInputChannel(  
  11.             inputChannel, inputWindowHandle, monitor);  
  12. }  
  13.   
  14. status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,  
  15.         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {  
  16.     { // acquire lock  
  17.         AutoMutex _l(mLock);  
  18.         //这个将inputChannel封装为Connection  
  19.         sp<Connection> connection = new Connection(inputChannel,   
  20. inputWindowHandle, monitor);  
  21.             //这个就是unix socket文件句柄  
  22.         int fd = inputChannel->getFd();  
  23.         //将connection保存到映射表中  
  24.         mConnectionsByFd.add(fd, connection);  
  25.         //监听该unix socket文件,当unix socket有数据时即client发送消息过来了,  
  26.         //函数handleReceiveCallback就会被执行  
  27.         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);  
  28.     } // release lock  
  29.   
  30.     // Wake the looper because some connections have changed.  
  31.     mLooper->wake();  
  32.     return OK;  
  33. }  

Server端的InputChannel事件数据发送

    在上几篇文章“锤子快捷键配置”中,已经讲到了事件分发,并最后将事件放到了connection的事件队列中,InputChannel事件发送就是从开始的
  1. void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,  
  2.         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {  
  3.     bool wasEmpty = connection->outboundQueue.isEmpty();  
  4.     // Enqueue dispatch entries for the requested modes.  
  5.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  6.             InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);  
  7.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  8.             InputTarget::FLAG_DISPATCH_AS_OUTSIDE);  
  9.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  10.             InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);  
  11.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  12.             InputTarget::FLAG_DISPATCH_AS_IS);  
  13.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  14.             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);  
  15.     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,  
  16.             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);  
  17.   
  18.     // 原来是空,现在不空,则立刻分发事件  
  19.     if (wasEmpty && !connection->outboundQueue.isEmpty()) {  
  20.         startDispatchCycleLocked(currentTime, connection);  
  21.     }  
  22. }   
  23.   
  24. void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,  
  25.         const sp<Connection>& connection) {  
  26.     //遍历所有发送队列中的事件  
  27.     while (connection->status == Connection::STATUS_NORMAL  
  28.             && !connection->outboundQueue.isEmpty()) {  
  29.         //获取最早的需要发送的事件  
  30.         DispatchEntry* dispatchEntry = connection->outboundQueue.head;  
  31.         EventEntry* eventEntry = dispatchEntry->eventEntry;  
  32.         switch (eventEntry->type) {  
  33.         case EventEntry::TYPE_KEY: {  
  34.             KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);  
  35.               
  36.             //真正发送事件.  
  37.             status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,  
  38.                     keyEntry->deviceId, keyEntry->source,  
  39.                     dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,  
  40.                     keyEntry->keyCode, keyEntry->scanCode,  
  41.                     keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,  
  42.                     keyEntry->eventTime);  
  43.             break;  
  44.         }  
  45.   
  46.         // Check the result.  
  47.         if (status) {  
  48.             if (status == WOULD_BLOCK) {  
  49.                 if (connection->waitQueue.isEmpty()) {  
  50.                 } else {  
  51.                     connection->inputPublisherBlocked = true;  
  52.                 }  
  53.             }  
  54.             //发送成功,返回执行下一次循环  
  55.             return;  
  56.         }  
  57.   
  58.         // 事件发送失败,重新放进待发送队列  
  59.         connection->outboundQueue.dequeue(dispatchEntry);  
  60.         connection->waitQueue.enqueueAtTail(dispatchEntry);  
  61.     }  
  62. }  
  63.   
  64. status_t InputPublisher::publishKeyEvent(  
  65.         uint32_t seq,  
  66.         int32_t deviceId,  
  67.         int32_t source,  
  68.         int32_t action,  
  69.         int32_t flags,  
  70.         int32_t keyCode,  
  71.         int32_t scanCode,  
  72.         int32_t metaState,  
  73.         int32_t repeatCount,  
  74.         nsecs_t downTime,  
  75.         nsecs_t eventTime) {  
  76.     InputMessage msg;  
  77.     //将输入事件转化为unix socket通信的格式  
  78.     msg.header.type = InputMessage::TYPE_KEY;  
  79.     msg.body.key.seq = seq;  
  80.     msg.body.key.deviceId = deviceId;  
  81.     msg.body.key.source = source;  
  82.     msg.body.key.action = action;  
  83.     msg.body.key.flags = flags;  
  84.     msg.body.key.keyCode = keyCode;  
  85.     msg.body.key.scanCode = scanCode;  
  86.     msg.body.key.metaState = metaState;  
  87.     msg.body.key.repeatCount = repeatCount;  
  88.     msg.body.key.downTime = downTime;  
  89. msg.body.key.eventTime = eventTime;  
  90.     //调用unix socket消息发送机制  
  91.     return mChannel->sendMessage(&msg);  
  92. }  
  93.   
  94. status_t InputChannel::sendMessage(const InputMessage* msg) {  
  95.     size_t msgLength = msg->size();  
  96.     ssize_t nWrite;  
  97. do {  
  98.     //通过unix socket将事件数据发送到程序端  
  99.         nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);  
  100.     } while (nWrite == -1 && errno == EINTR);  
  101.     return OK;  
  102. }  

程序client端的InputChannel

client的InputChannel相关的处理逻辑如下:

 Client 端的InputChannel创建

         Client接受事件,肯定必须先获得inputChannel,这个是在addWindow时系统返回回来的。

         

  1. public void setView(View view, WindowManager.LayoutParams attrs,   
  2. View panelParentView) {  
  3.         synchronized (this) {  
  4.                 if ((mWindowAttributes.inputFeatures&  
  5.                    WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  6.                     mInputChannel = new InputChannel();  
  7.                 }  
  8.                 try {  
  9.                     //该函数会返回一个InputChannel  
  10.                     res = mWindowSession.addToDisplay(mWindow, mSeq,  
  11.                             mWindowAttributes,  
  12.                             getHostVisibility(), mDisplay.getDisplayId(),  
  13.                             mAttachInfo.mContentInsets, mInputChannel);  
  14.                 }  
  15.                 if (mInputChannel != null) {  
  16.                     if (mInputQueueCallback != null) {  
  17.                         mInputQueue = new InputQueue();  
  18.                         mInputQueueCallback.onInputQueueCreated(mInputQueue);  
  19.                     }  
  20.                     //为InputChannel注册监听器  
  21.                     mInputEventReceiver = new WindowInputEventReceiver(  
  22.                          mInputChannel,  
  23.                          Looper.myLooper());  
  24.                 }<pre name="code" class="java" style="font-size: 14px;">          }  
}

Client端的 InputChannel监听器安装

         InputChannel监听器安装在WindowInputEventReceiver初始化的时候

         

  1. final class WindowInputEventReceiver extends InputEventReceiver {  
  2.         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {  
  3.             super(inputChannel, looper);  
  4.         }  
  5. }  
  6. public InputEventReceiver(InputChannel inputChannel, Looper looper) {  
  7.         mInputChannel = inputChannel;  
  8.         mMessageQueue = looper.getQueue();  
  9.         mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),  
  10.                 inputChannel, mMessageQueue);  
  11.   
  12.         mCloseGuard.open("dispose");  
  13.  }  
  14.   
  15. static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,  
  16.         jobject inputChannelObj, jobject messageQueueObj) {  
  17.     //获取native层的InputChannel  
  18.     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,  
  19.             inputChannelObj);  
  20.     //获取java层InputEventReceiver对象的native层的消息队列  
  21.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
  22.         //创建native对应的InputEventReceiver对象  
  23.     sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,  
  24.             receiverWeak, inputChannel, messageQueue);  
  25.     //这个是真正安装监听的函数  
  26.     status_t status = receiver->initialize();  
  27.     return reinterpret_cast<jint>(receiver.get());  
  28. }  
  29.   
  30.   
  31. status_t NativeInputEventReceiver::initialize() {  
  32.     //安装监听器  
  33.     setFdEvents(ALOOPER_EVENT_INPUT);  
  34.     return OK;  
  35. }  
  36.   
  37. void NativeInputEventReceiver::setFdEvents(int events) {  
  38.     if (mFdEvents != events) {  
  39.         mFdEvents = events;  
  40.         int fd = mInputConsumer.getChannel()->getFd();  
  41.         if (events) {  
  42.            //用looper监听inputChannel对应的unix socket文件句柄  
  43.             mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {  
  49.     return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);  
  50. }  
  51.   
  52. int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {  
  53.     { // acquire lock  
  54.         AutoMutex _l(mLock);  
  55.         //将监听参数封装  
  56.         Request request;  
  57.         request.fd = fd;  
  58.         request.ident = ident;  
  59.         //这个很重要,当被监听的文件发生变化时就会调用该callback函数  
  60.         request.callback = callback;  
  61.         request.data = data;  
  62.   
  63.         ssize_t requestIndex = mRequests.indexOfKey(fd);  
  64.         if (requestIndex < 0) {  
  65.             //epoll该文件,也就是讲unix socket文件添加到监听文件列表中  
  66.             int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);  
  67.             mRequests.add(fd, request);  
  68.         }  
  69.     } // release lock  
  70.     return 1;  
  71. }  

Client端的InputChannel中的事件接收

         从上面可以看出,Java的InputEventReceiver层的native层的NativeInputEventReceiver负责监听事件,当有事件时,就会调用它。

           

  1. int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {  
  2.     int result = 0;  
  3.     for (;;) {  
  4.         while (mResponseIndex < mResponses.size()) {  
  5.             const Response& response = mResponses.itemAt(mResponseIndex++);  
  6.             int ident = response.request.ident;  
  7.             if (ident >= 0) {  
  8.                 int fd = response.request.fd;  
  9.                 int events = response.events;  
  10.                 void* data = response.request.data;  
  11.                 if (outFd != NULL) *outFd = fd;  
  12.                 if (outEvents != NULL) *outEvents = events;  
  13.                 if (outData != NULL) *outData = data;  
  14.                 return ident;  
  15.             }  
  16.         }  
  17.         result = pollInner(timeoutMillis);  
  18.     }  
  19. }  
  20.   
  21. int Looper::pollInner(int timeoutMillis) {  
  22.     struct epoll_event eventItems[EPOLL_MAX_EVENTS];  
  23.     //等待消息  
  24.     int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);  
  25.     for (int i = 0; i < eventCount; i++) {  
  26.         int fd = eventItems[i].data.fd;  
  27.         uint32_t epollEvents = eventItems[i].events;  
  28.         if (fd == mWakeReadPipeFd) {  
  29.             if (epollEvents & EPOLLIN) {  
  30.                 awoken();  
  31.             }  
  32.         } else {  
  33.             ssize_t requestIndex = mRequests.indexOfKey(fd);  
  34.             if (requestIndex >= 0) {  
  35.                 int events = 0;  
  36.                 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;  
  37.                 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;  
  38.                 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;  
  39.                 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;  
  40.                 //将事件放到事件队列上  
  41.                 pushResponse(events, mRequests.valueAt(requestIndex));  
  42.             }  
  43.         }  
  44.     }  
  45. Done: ;  
  46.     //处理前面加入的response事件  
  47.     for (size_t i = 0; i < mResponses.size(); i++) {  
  48.         Response& response = mResponses.editItemAt(i);  
  49.         if (response.request.ident == ALOOPER_POLL_CALLBACK) {  
  50.             int fd = response.request.fd;  
  51.             int events = response.events;  
  52.             void* data = response.request.data;  
  53.             // 下面的callback就是 NativeInputEventRecieverd  
  54.             int callbackResult = response.request.callback->handleEvent(fd, events, data);  
  55.             if (callbackResult == 0) {  
  56.                 removeFd(fd);  
  57.             }  
  58.             response.request.callback.clear();  
  59.             result = ALOOPER_POLL_CALLBACK;  
  60.         }  
  61.     }  
  62.     return result;  
  63. }  
  64.   
  65.   
  66. int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {  
  67.   
  68. if (events & ALOOPER_EVENT_INPUT) {  
  69.         JNIEnv* env = AndroidRuntime::getJNIEnv();  
  70.         //处理事件  
  71.         status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);  
  72.         mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");  
  73.         return status == OK || status == NO_MEMORY ? 1 : 0;  
  74. }  
  75.     return 1;  
  76. }  
  77.   
  78. status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,  
  79.         bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {  
  80.     for (;;) {  
  81.         uint32_t seq;  
  82.         InputEvent* inputEvent;  
  83.         //从buffer中还原出事件  
  84.         status_t status = mInputConsumer.consume(&mInputEventFactory,  
  85.                 consumeBatches, frameTime, &seq, &inputEvent);  
  86.         if (!skipCallbacks) {  
  87.             jobject inputEventObj;  
  88.             switch (inputEvent->getType()) {  
  89.             case AINPUT_EVENT_TYPE_KEY:  
  90.                 //转换为java层的InputEvent  
  91.                 inputEventObj = android_view_KeyEvent_fromNative(env,  
  92.                         static_cast<KeyEvent*>(inputEvent));  
  93.                 break;  
  94.             }  
  95.             if (inputEventObj) {  
  96.                 //这个就会调用到java层的函数InputEventReceiver->dispatchInputEvent  
  97.                 env->CallVoidMethod(receiverObj.get(),  
  98.                         gInputEventReceiverClassInfo.dispatchInputEvent, seq,  
  99.  inputEventObj);  
  100.             }  
  101.         }  
  102.     }  
  103. }  
            

Client端对输入事件的处理

          到此为止,事件开始传递到了JAVA层了,然后就是JAVA层开始对事件进行处理,我们通常接触的事件处理也是在java层实现的,这个将在下一篇介绍。


/********************************

* 本文来自博客  “爱踢门”

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值