转载

Android输入系统(二)

在上一篇文章的最后,我们发现InputDispatcher是调用了InputChannel->sendMessage把键值发送出去,那么相应的,也有接收键值的地方。接收函数是InputChannel->receiveMessage。

在InputConsumer::consume内找到了receiveMessage,从类名能看出来发送端与接收端相当于生产者与消费者的关系。

status_t InputConsumer::consume(InputEventFactoryInterface* factory,         bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {             // Receive a fresh message.             status_t result = mChannel->receiveMessage(&mMsg); }

receiveMessage内调用的是socket的接收函数recv

status_t InputChannel::receiveMessage(InputMessage* msg) {     do {         nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);     } while (nRead == -1 && errno == EINTR); }

事件接收端NativeInputEventReceiver

那么究竟是谁来消费这些事件呢,我们在NativeInputEventReceiver里面找到了答案。

在NativeInputEventReceiver内有个事件处理函数handleEvent,该函数是looperCallback的虚函数,NativeInputEventReceiver作为looperCallback的子类,自然有义务实现handleEvent这个函数。handleEvent就可以监听I/O事件。一旦有I/O事件,如上述的socket send事件,handleEvent就会被启动,进行后续的处理。

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {         status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL); }

在consumeEvents内,我们能看到调用了InputConsume::consume来接收InputDispatcher发送过来的事件

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,         bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {     for (;;) {         status_t status = mInputConsumer.consume(&mInputEventFactory,                 consumeBatches, frameTime, &seq, &inputEvent);         } }

输入事件在consumeEvents内将会被处理完成,其中包含了四个主要步骤:

  1. 获取输入事件
  2. 把输入事件转换成java也能处理的格式
  3. 输入事件分发到相应窗口去处理
  4. 处理结果反馈

1. 获取输入事件已在上面阐述过

2. 输入事件转换

以Key为例,输入事件只是把事件内部的成员拆分,然后通过JNI调用java的构造函数来生成相应的java event对象,后面的事件处理都在java层

jobject inputEventObj;      switch (inputEvent->getType()) {      case AINPUT_EVENT_TYPE_KEY:   inputEventObj = android_view_KeyEvent_fromNative(env,    static_cast<KeyEvent*>(inputEvent));   break; // ---------------------------------------------------------------------------- jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {     jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz,      gKeyEventClassInfo.obtain,      nanoseconds_to_milliseconds(event->getDownTime()),      nanoseconds_to_milliseconds(event->getEventTime()),      event->getAction(),      event->getKeyCode(),      event->getRepeatCount(),      event->getMetaState(),      event->getDeviceId(),      event->getScanCode(),      event->getFlags(),      event->getSource(),      NULL);     if (env->ExceptionCheck()) {  ALOGE("An exception occurred while obtaining a key event.");  LOGE_EX(env);  env->ExceptionClear();  return NULL;     }     return eventObj; }     public static KeyEvent obtain(long downTime, long eventTime, int action,       int code, int repeat, int metaState,       int deviceId, int scancode, int flags, int source, String characters) {  KeyEvent ev = obtain();  ev.mDownTime = downTime;  ev.mEventTime = eventTime;  ev.mAction = action;  ev.mKeyCode = code;  ev.mRepeatCount = repeat;  ev.mMetaState = metaState;  ev.mDeviceId = deviceId;  ev.mScanCode = scancode;  ev.mFlags = flags;  ev.mSource = source;  ev.mCharacters = characters;  return ev;     } 

3.输入事件分发

这里是在java层的事件分发,最终目的是为了调用到窗口的onTouch这类回调函数。

env->CallVoidMethod(receiverObj.get(),                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);

通过上述的JNI调用,会调用到WindowInputEventReceiver的dispatchInputEvent方法

public void dispatchInputEvent(InputEvent event) {         Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);         msg.setAsynchronous(true);         mHandler.sendMessage(msg);     }

handleMessage收到消息后,会开始事件的处理。

public void handleMessage(Message msg){    case MSG_DISPATCH_INPUT_EVENT: {     InputEvent event = (InputEvent)msg.obj;     enqueueInputEvent(event, null, 0, true);    } break; }  void enqueueInputEvent(InputEvent event,    InputEventReceiver receiver, int flags, boolean processImmediately) {   QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);   // Always enqueue the input event in order, regardless of its time stamp.   // We do this because the application or the IME may inject key events   // in response to touch events and we want to ensure that the injected keys   // are processed in the order they were received and we cannot trust that   // the time stamp of injected events are monotonic.   QueuedInputEvent last = mPendingInputEventTail;   if (last == null) {    mPendingInputEventHead = q;    mPendingInputEventTail = q;   } else {    last.mNext = q;    mPendingInputEventTail = q;   }   mPendingInputEventCount += 1;   Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,     mPendingInputEventCount);   if (processImmediately) {    doProcessInputEvents();   } else {    scheduleProcessInputEvents();   }  } 

由于事件队列内会包含多个事件,因此在doProcessInputEvent时,需要分别对所有的事件都进行分发

void doProcessInputEvents() {  // Deliver all pending input events in the queue.  while (mPendingInputEventHead != null) {   QueuedInputEvent q = mPendingInputEventHead;   mPendingInputEventHead = q.mNext;   if (mPendingInputEventHead == null) {    mPendingInputEventTail = null;   }   q.mNext = null;   mPendingInputEventCount -= 1;   deliverInputEvent(q);  } } 

deliverInputEvent会调用到InputState的deliver方法

public final void deliver(QueuedInputEvent q) {             if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {                 forward(q);             } else if (shouldDropInputEvent(q)) {                 finish(q, false);             } else {                 apply(q, onProcess(q));             }         }

由于一开始我们的事件还没有完成,因此不会带上FLAG_FINISHED,而且我们的事件时一般事件,并不会被丢弃,因此会走apply分支。

首先会调用onProcess处理事件

protected int onProcess(QueuedInputEvent q) {  if (q.mEvent instanceof KeyEvent) {   return processKeyEvent(q);  } else {   // If delivering a new non-key event, make sure the window is   // now allowed to start updating.   handleDispatchDoneAnimating();   final int source = q.mEvent.getSource();   if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {    return processPointerEvent(q);   } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {    return processTrackballEvent(q);   } else {    return processGenericMotionEvent(q);   }  } } 

以Key为例,我们会调用到processKeyEvent

private int processKeyEvent(QueuedInputEvent q) {              // Deliver the key to the view hierarchy.             if (mView.dispatchKeyEvent(event)) {                 return FINISH_HANDLED;             }         }

然后调用了View类的dispatchKeyEvent方法,最终会调用到onKey这个回调函数

public boolean dispatchKeyEvent(KeyEvent event) {  // Give any attached key listener a first crack at the event.  //noinspection SimplifiableIfStatement  ListenerInfo li = mListenerInfo;  if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED    && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {   return true;  } } 

4. 处理结果反馈

然后还剩下apply这个方法需要分析。如果onProcess正常处理完成后,会返回FINISH_HANDLED,否则返回FINISHED_NOT_NHANDLED。

protected void apply(QueuedInputEvent q, int result) {   if (result == FORWARD) {    forward(q);   } else if (result == FINISH_HANDLED) {    finish(q, true);   } else if (result == FINISH_NOT_HANDLED) {    finish(q, false);   } else {    throw new IllegalArgumentException("Invalid result: " + result);   }  }  protected void finish(QueuedInputEvent q, boolean handled) {   q.mFlags |= QueuedInputEvent.FLAG_FINISHED;   if (handled) {    q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;   }   forward(q);  }  protected void forward(QueuedInputEvent q) {   onDeliverToNext(q);  }  protected void onDeliverToNext(QueuedInputEvent q) {   if (mNext != null) {    mNext.deliver(q);   } else {    finishInputEvent(q);   }  } private void finishInputEvent(QueuedInputEvent q) {  if (q.mReceiver != null) {   boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;   q.mReceiver.finishInputEvent(q.mEvent, handled);  } else {   q.mEvent.recycleIfNeededAfterDispatch();  }  recycleQueuedInputEvent(q); } 

mReceiver.finishInputEvent就是NativeInputEvent的finishInputEvent

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {  status_t status = mInputConsumer.sendFinishedSignal(seq, handled); } status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {   while (!status && chainIndex-- > 0) {    status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);   } } status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {  InputMessage msg;  msg.header.type = InputMessage::TYPE_FINISHED;  msg.body.finished.seq = seq;  msg.body.finished.handled = handled;  return mChannel->sendMessage(&msg); } 

最后也是调用sendMessage把消息反馈给InputDispatcher。

到这里,上层的处理已经完成,接下来就是InputDispatcher的反馈处理。

InputDispatcher反馈处理

反馈处理在handleReceiveCallback中进行,其中包含两个部分:

  1. 接收反馈消息
  2. 处理反馈消息
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {    for (;;) {     uint32_t seq;     bool handled;     status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);     if (status) {      break;     }     d->finishDispatchCycleLocked(currentTime, connection, seq, handled);     gotOne = true;    } } 

1. 接收反馈消息

接收反馈消息是调用的inputPublisher的receiveFinishedSignal方法,内部还是调用了mChannel->receiveMessage

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {      status_t result = mChannel->receiveMessage(&msg);  }

2. 处理反馈消息

处理反馈消息是调用了finishDispatchCycleLocked。

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,         const sp<Connection>& connection, uint32_t seq, bool handled) {      // Notify other system components and prepare to start the next dispatch cycle.     onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); }
void InputDispatcher::onDispatchCycleFinishedLocked(         nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {     CommandEntry* commandEntry = postCommandLocked(             & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);  }

postCommandLocked其实也是发送消息给InputDispatcherThread,那么在分发线程下一次处理消息的时候会首先处理doDispatchCycleFinishedLockedInterruptible。

doDispatchCycleFinishedLockedInterruptible是实际上反馈进行处理的地方,其中包含了下面几个处理步骤:

  1. 从waitQueue中取出所反馈的事件
  2. 事件是否处理超时,如果是则做超时处理
  3. 从waitQueue中删除所反馈的事件
  4. 立刻展开下一次的outboundQueue事件监听
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(   CommandEntry* commandEntry) {  // Handle post-event policy actions.  DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);   if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {    String8 msg;    msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ",      connection->getWindowName(), eventDuration * 0.000001f);    dispatchEntry->eventEntry->appendDescription(msg);    ALOGI("%s", msg.string());   }   if (dispatchEntry == connection->findWaitQueueEntry(seq)) {    connection->waitQueue.dequeue(dispatchEntry);   }   // Start the next dispatch cycle for this connection.   startDispatchCycleLocked(now(), connection);  } } 

Android输入系统(二)

正文到此结束
Loading...