diff options
Diffstat (limited to 'libs/ui/InputDispatcher.cpp')
| -rw-r--r-- | libs/ui/InputDispatcher.cpp | 393 | 
1 files changed, 272 insertions, 121 deletions
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 0ccde0d31252..f058271bda13 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -19,6 +19,9 @@  // Log debug messages about the dispatch cycle.  #define DEBUG_DISPATCH_CYCLE 1 +// Log debug messages about registrations. +#define DEBUG_REGISTRATION 1 +  // Log debug messages about performance statistics.  #define DEBUG_PERFORMANCE_STATISTICS 1 @@ -42,7 +45,7 @@ static inline bool isMovementKey(int32_t keyCode) {  // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) : +InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :      mPolicy(policy) {      mPollLoop = new PollLoop(); @@ -55,6 +58,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy)      mInboundQueue.tail.eventTime = LONG_LONG_MAX;      mKeyRepeatState.lastKeyEntry = NULL; + +    mCurrentInputTargetsValid = false;  }  InputDispatcher::~InputDispatcher() { @@ -72,8 +77,9 @@ InputDispatcher::~InputDispatcher() {  }  void InputDispatcher::dispatchOnce() { -    bool allowKeyRepeat = mPolicy->allowKeyRepeat(); +    nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); +    bool skipPoll = false;      nsecs_t currentTime;      nsecs_t nextWakeupTime = LONG_LONG_MAX;      { // acquire lock @@ -84,7 +90,7 @@ void InputDispatcher::dispatchOnce() {          // is not a key.  This is to ensure that we abort a key repeat if the device is just coming          // out of sleep.          // XXX we should handle resetting input state coming out of sleep more generally elsewhere -        if (! allowKeyRepeat) { +        if (keyRepeatTimeout < 0) {              resetKeyRepeatLocked();          } @@ -121,8 +127,8 @@ void InputDispatcher::dispatchOnce() {              if (mInboundQueue.isEmpty()) {                  if (mKeyRepeatState.lastKeyEntry) {                      if (currentTime >= mKeyRepeatState.nextRepeatTime) { -                        processKeyRepeatLocked(currentTime); -                        return; // dispatched once +                        processKeyRepeatLockedInterruptible(currentTime, keyRepeatTimeout); +                        skipPoll = true;                      } else {                          if (mKeyRepeatState.nextRepeatTime < nextWakeupTime) {                              nextWakeupTime = mKeyRepeatState.nextRepeatTime; @@ -130,31 +136,30 @@ void InputDispatcher::dispatchOnce() {                      }                  }              } else { -                // Inbound queue has at least one entry.  Dequeue it and begin dispatching. -                // Note that we do not hold the lock for this process because dispatching may -                // involve making many callbacks. -                EventEntry* entry = mInboundQueue.dequeueAtHead(); +                // Inbound queue has at least one entry. +                // Start processing it but leave it on the queue until later so that the +                // input reader can keep appending samples onto a motion event between the +                // time we started processing it and the time we finally enqueue dispatch +                // entries for it. +                EventEntry* entry = mInboundQueue.head.next;                  switch (entry->type) {                  case EventEntry::TYPE_CONFIGURATION_CHANGED: {                      ConfigurationChangedEntry* typedEntry =                              static_cast<ConfigurationChangedEntry*>(entry); -                    processConfigurationChangedLocked(currentTime, typedEntry); -                    mAllocator.releaseConfigurationChangedEntry(typedEntry); +                    processConfigurationChangedLockedInterruptible(currentTime, typedEntry);                      break;                  }                  case EventEntry::TYPE_KEY: {                      KeyEntry* typedEntry = static_cast<KeyEntry*>(entry); -                    processKeyLocked(currentTime, typedEntry); -                    mAllocator.releaseKeyEntry(typedEntry); +                    processKeyLockedInterruptible(currentTime, typedEntry, keyRepeatTimeout);                      break;                  }                  case EventEntry::TYPE_MOTION: {                      MotionEntry* typedEntry = static_cast<MotionEntry*>(entry); -                    processMotionLocked(currentTime, typedEntry); -                    mAllocator.releaseMotionEntry(typedEntry); +                    processMotionLockedInterruptible(currentTime, typedEntry);                      break;                  } @@ -162,30 +167,67 @@ void InputDispatcher::dispatchOnce() {                      assert(false);                      break;                  } -                return; // dispatched once + +                // Dequeue and release the event entry that we just processed. +                mInboundQueue.dequeue(entry); +                mAllocator.releaseEventEntry(entry); +                skipPoll = true;              }          } + +        // Run any deferred commands. +        skipPoll |= runCommandsLockedInterruptible();      } // release lock +    // If we dispatched anything, don't poll just now.  Wait for the next iteration. +    // Contents may have shifted during flight. +    if (skipPoll) { +        return; +    } +      // Wait for callback or timeout or wake.      nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime);      int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0;      mPollLoop->pollOnce(timeoutMillis);  } -void InputDispatcher::processConfigurationChangedLocked(nsecs_t currentTime, -        ConfigurationChangedEntry* entry) { +bool InputDispatcher::runCommandsLockedInterruptible() { +    if (mCommandQueue.isEmpty()) { +        return false; +    } + +    do { +        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); + +        Command command = commandEntry->command; +        (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' + +        mAllocator.releaseCommandEntry(commandEntry); +    } while (! mCommandQueue.isEmpty()); +    return true; +} + +InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { +    CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command); +    mCommandQueue.enqueueAtTail(commandEntry); +    return commandEntry; +} + +void InputDispatcher::processConfigurationChangedLockedInterruptible( +        nsecs_t currentTime, ConfigurationChangedEntry* entry) {  #if DEBUG_OUTBOUND_EVENT_DETAILS -    LOGD("processConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, " -            "keyboardConfig=%d, navigationConfig=%d", entry->eventTime, -            entry->touchScreenConfig, entry->keyboardConfig, entry->navigationConfig); +    LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime);  #endif -    mPolicy->notifyConfigurationChanged(entry->eventTime, entry->touchScreenConfig, -            entry->keyboardConfig, entry->navigationConfig); +    mLock.unlock(); + +    mPolicy->notifyConfigurationChanged(entry->eventTime); + +    mLock.lock();  } -void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) { +void InputDispatcher::processKeyLockedInterruptible( +        nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) {  #if DEBUG_OUTBOUND_EVENT_DETAILS      LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "              "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", @@ -209,7 +251,7 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {          } else {              // Not a repeat.  Save key down state in case we do see a repeat later.              resetKeyRepeatLocked(); -            mKeyRepeatState.nextRepeatTime = entry->eventTime + mPolicy->getKeyRepeatTimeout(); +            mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout;          }          mKeyRepeatState.lastKeyEntry = entry;          entry->refCount += 1; @@ -217,10 +259,11 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {          resetKeyRepeatLocked();      } -    identifyInputTargetsAndDispatchKeyLocked(currentTime, entry); +    identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);  } -void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) { +void InputDispatcher::processKeyRepeatLockedInterruptible( +        nsecs_t currentTime, nsecs_t keyRepeatTimeout) {      // TODO Old WindowManagerServer code sniffs the input queue for following key up      //      events and drops the repeat if one is found.  We should do something similar.      //      One good place to do it is in notifyKey as soon as the key up enters the @@ -252,7 +295,7 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {      entry->downTime = currentTime;      entry->policyFlags = 0; -    mKeyRepeatState.nextRepeatTime = currentTime + mPolicy->getKeyRepeatTimeout(); +    mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;  #if DEBUG_OUTBOUND_EVENT_DETAILS      LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, " @@ -263,10 +306,11 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {              entry->repeatCount, entry->downTime);  #endif -    identifyInputTargetsAndDispatchKeyLocked(currentTime, entry); +    identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);  } -void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entry) { +void InputDispatcher::processMotionLockedInterruptible( +        nsecs_t currentTime, MotionEntry* entry) {  #if DEBUG_OUTBOUND_EVENT_DETAILS      LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "              "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", @@ -296,15 +340,19 @@ void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entr      }  #endif -    identifyInputTargetsAndDispatchMotionLocked(currentTime, entry); +    identifyInputTargetsAndDispatchMotionLockedInterruptible(currentTime, entry);  } -void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked( +void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(          nsecs_t currentTime, KeyEntry* entry) {  #if DEBUG_DISPATCH_CYCLE      LOGD("identifyInputTargetsAndDispatchKey");  #endif +    entry->dispatchInProgress = true; +    mCurrentInputTargetsValid = false; +    mLock.unlock(); +      mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags,              entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,              entry->downTime, entry->eventTime); @@ -313,15 +361,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked(      mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags,              mCurrentInputTargets); +    mLock.lock(); +    mCurrentInputTargetsValid = true; +      dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);  } -void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked( +void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(          nsecs_t currentTime, MotionEntry* entry) {  #if DEBUG_DISPATCH_CYCLE      LOGD("identifyInputTargetsAndDispatchMotion");  #endif +    entry->dispatchInProgress = true; +    mCurrentInputTargetsValid = false; +    mLock.unlock(); +      mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,              entry->edgeFlags, entry->metaState,              entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y, @@ -333,17 +388,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked(      mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags,              mCurrentInputTargets); +    mLock.lock(); +    mCurrentInputTargetsValid = true; +      dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);  }  void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,          EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {  #if DEBUG_DISPATCH_CYCLE -    LOGD("dispatchEventToCurrentInputTargets, " +    LOGD("dispatchEventToCurrentInputTargets - "              "resumeWithAppendedMotionSample=%s",              resumeWithAppendedMotionSample ? "true" : "false");  #endif +    assert(eventEntry->dispatchInProgress); // should already have been set to true +      for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {          const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i); @@ -365,7 +425,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection          EventEntry* eventEntry, const InputTarget* inputTarget,          bool resumeWithAppendedMotionSample) {  #if DEBUG_DISPATCH_CYCLE -    LOGD("channel '%s' ~ prepareDispatchCycle, flags=%d, timeout=%lldns, " +    LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "              "xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s",              connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout,              inputTarget->xOffset, inputTarget->yOffset, @@ -377,7 +437,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection      // not responding.      if (connection->status != Connection::STATUS_NORMAL) {          LOGV("channel '%s' ~ Dropping event because the channel status is %s", -                connection->status == Connection::STATUS_BROKEN ? "BROKEN" : "NOT RESPONDING"); +                connection->getStatusLabel());          return;      } @@ -631,14 +691,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Connection*  void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {  #if DEBUG_DISPATCH_CYCLE -    LOGD("channel '%s' ~ finishDispatchCycle: %01.1fms since event, " +    LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "              "%01.1fms since dispatch",              connection->getInputChannelName(),              connection->getEventLatencyMillis(currentTime),              connection->getDispatchLatencyMillis(currentTime));  #endif -    if (connection->status == Connection::STATUS_BROKEN) { +    if (connection->status == Connection::STATUS_BROKEN +            || connection->status == Connection::STATUS_ZOMBIE) {          return;      } @@ -722,34 +783,37 @@ bool InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime, Connection  bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,          bool broken) {  #if DEBUG_DISPATCH_CYCLE -    LOGD("channel '%s' ~ abortDispatchCycle, broken=%s", +    LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",              connection->getInputChannelName(), broken ? "true" : "false");  #endif -    if (connection->status == Connection::STATUS_BROKEN) { -        return false; -    } -      // Clear the pending timeout.      connection->nextTimeoutTime = LONG_LONG_MAX;      // Clear the outbound queue. -    while (! connection->outboundQueue.isEmpty()) { -        DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead(); -        mAllocator.releaseDispatchEntry(dispatchEntry); -    } +    bool deactivated = ! connection->outboundQueue.isEmpty(); +    if (deactivated) { +        do { +            DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead(); +            mAllocator.releaseDispatchEntry(dispatchEntry); +        } while (! connection->outboundQueue.isEmpty()); -    // Outbound queue is empty, deactivate the connection. -    deactivateConnectionLocked(connection); +        deactivateConnectionLocked(connection); +    }      // Handle the case where the connection appears to be unrecoverably broken. +    // Ignore already broken or zombie connections.      if (broken) { -        connection->status = Connection::STATUS_BROKEN; +        if (connection->status == Connection::STATUS_NORMAL +                || connection->status == Connection::STATUS_NOT_RESPONDING) { +            connection->status = Connection::STATUS_BROKEN; -        // Notify other system components. -        onDispatchCycleBrokenLocked(currentTime, connection); +            // Notify other system components. +            onDispatchCycleBrokenLocked(currentTime, connection); +        }      } -    return true; /*deactivated*/ + +    return deactivated;  }  bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) { @@ -772,6 +836,7 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat              LOGE("channel '%s' ~ Consumer closed input channel or an error occurred.  "                      "events=0x%x", connection->getInputChannelName(), events);              d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); +            d->runCommandsLockedInterruptible();              return false; // remove the callback          } @@ -786,20 +851,19 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat              LOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",                      connection->getInputChannelName(), status);              d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); +            d->runCommandsLockedInterruptible();              return false; // remove the callback          }          d->finishDispatchCycleLocked(currentTime, connection.get()); +        d->runCommandsLockedInterruptible();          return true;      } // release lock  } -void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touchScreenConfig, -        int32_t keyboardConfig, int32_t navigationConfig) { +void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) {  #if DEBUG_INBOUND_EVENT_DETAILS -    LOGD("notifyConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, " -            "keyboardConfig=%d, navigationConfig=%d", eventTime, -            touchScreenConfig, keyboardConfig, navigationConfig); +    LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime);  #endif      bool wasEmpty; @@ -808,9 +872,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc          ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry();          newEntry->eventTime = eventTime; -        newEntry->touchScreenConfig = touchScreenConfig; -        newEntry->keyboardConfig = keyboardConfig; -        newEntry->navigationConfig = navigationConfig;          wasEmpty = mInboundQueue.isEmpty();          mInboundQueue.enqueueAtTail(newEntry); @@ -821,16 +882,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc      }  } -void InputDispatcher::notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) { -#if DEBUG_INBOUND_EVENT_DETAILS -    LOGD("notifyLidSwitchChanged - eventTime=%lld, open=%s", eventTime, -            lidOpen ? "true" : "false"); -#endif - -    // Send lid switch notification immediately and synchronously. -    mPolicy->notifyLidSwitchChanged(eventTime, lidOpen); -} -  void InputDispatcher::notifyAppSwitchComing(nsecs_t eventTime) {  #if DEBUG_INBOUND_EVENT_DETAILS      LOGD("notifyAppSwitchComing - eventTime=%lld", eventTime); @@ -949,13 +1000,25 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t                  }                  // The last motion event is a move and is compatible for appending. -                // Do the batching magic and exit. +                // Do the batching magic.                  mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords);  #if DEBUG_BATCHING                  LOGD("Appended motion sample onto batch for most recent "                          "motion event for this device in the inbound queue.");  #endif -                return; // done + +                // Sanity check for special case because dispatch is interruptible. +                // The dispatch logic is partially interruptible and releases its lock while +                // identifying targets.  However, as soon as the targets have been identified, +                // the dispatcher proceeds to write a dispatch entry into all relevant outbound +                // queues and then promptly removes the motion entry from the queue. +                // +                // Consequently, we should never observe the case where the inbound queue contains +                // an in-progress motion entry unless the current input targets are invalid +                // (currently being computed).  Check for this! +                assert(! (motionEntry->dispatchInProgress && mCurrentInputTargetsValid)); + +                return; // done!              }              // STREAMING CASE @@ -977,34 +1040,38 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t              // Note: This code crucially depends on the invariant that an outbound queue always              //       contains at most one synchronous event and it is always last (but it might              //       not be first!). -            for (size_t i = 0; i < mActiveConnections.size(); i++) { -                Connection* connection = mActiveConnections.itemAt(i); -                if (! connection->outboundQueue.isEmpty()) { -                    DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev; -                    if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) { -                        if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) { -                            goto NoBatchingOrStreaming; -                        } - -                        MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>( -                                dispatchEntry->eventEntry); -                        if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE -                                || syncedMotionEntry->deviceId != deviceId -                                || syncedMotionEntry->pointerCount != pointerCount) { -                            goto NoBatchingOrStreaming; +            if (mCurrentInputTargetsValid) { +                for (size_t i = 0; i < mActiveConnections.size(); i++) { +                    Connection* connection = mActiveConnections.itemAt(i); +                    if (! connection->outboundQueue.isEmpty()) { +                        DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev; +                        if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) { +                            if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) { +                                goto NoBatchingOrStreaming; +                            } + +                            MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>( +                                    dispatchEntry->eventEntry); +                            if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE +                                    || syncedMotionEntry->deviceId != deviceId +                                    || syncedMotionEntry->pointerCount != pointerCount) { +                                goto NoBatchingOrStreaming; +                            } + +                            // Found synced move entry.  Append sample and resume dispatch. +                            mAllocator.appendMotionSample(syncedMotionEntry, eventTime, +                                    pointerCount, pointerCoords); +    #if DEBUG_BATCHING +                            LOGD("Appended motion sample onto batch for most recent synchronously " +                                    "dispatched motion event for this device in the outbound queues."); +    #endif +                            nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); +                            dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry, +                                    true /*resumeWithAppendedMotionSample*/); + +                            runCommandsLockedInterruptible(); +                            return; // done!                          } - -                        // Found synced move entry.  Append sample and resume dispatch. -                        mAllocator.appendMotionSample(syncedMotionEntry, eventTime, -                                pointerCount, pointerCoords); -#if DEBUG_BATCHING -                        LOGD("Appended motion sample onto batch for most recent synchronously " -                                "dispatched motion event for this device in the outbound queues."); -#endif -                        nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); -                        dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry, -                                true /*resumeWithAppendedMotionSample*/); -                        return; // done!                      }                  }              } @@ -1049,6 +1116,10 @@ void InputDispatcher::resetKeyRepeatLocked() {  }  status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) { +#if DEBUG_REGISTRATION +    LOGD("channel '%s' - Registered", inputChannel->getName().string()); +#endif +      int receiveFd;      { // acquire lock          AutoMutex _l(mLock); @@ -1069,6 +1140,8 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan          }          mConnectionsByReceiveFd.add(receiveFd, connection); + +        runCommandsLockedInterruptible();      } // release lock      mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this); @@ -1076,6 +1149,10 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan  }  status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { +#if DEBUG_REGISTRATION +    LOGD("channel '%s' - Unregistered", inputChannel->getName().string()); +#endif +      int32_t receiveFd;      { // acquire lock          AutoMutex _l(mLock); @@ -1095,6 +1172,8 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh          nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);          abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); + +        runCommandsLockedInterruptible();      } // release lock      mPollLoop->removeCallback(receiveFd); @@ -1123,11 +1202,12 @@ void InputDispatcher::deactivateConnectionLocked(Connection* connection) {      }  } -void InputDispatcher::onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleStartedLocked( +        nsecs_t currentTime, Connection* connection) {  } -void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, -        Connection* connection, bool recoveredFromANR) { +void InputDispatcher::onDispatchCycleFinishedLocked( +        nsecs_t currentTime, Connection* connection, bool recoveredFromANR) {      if (recoveredFromANR) {          LOGI("channel '%s' ~ Recovered from ANR.  %01.1fms since event, "                  "%01.1fms since dispatch, %01.1fms since ANR", @@ -1136,26 +1216,65 @@ void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,                  connection->getDispatchLatencyMillis(currentTime),                  connection->getANRLatencyMillis(currentTime)); -        // TODO tell framework +        CommandEntry* commandEntry = postCommandLocked( +                & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible); +        commandEntry->inputChannel = connection->inputChannel;      }  } -void InputDispatcher::onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleANRLocked( +        nsecs_t currentTime, Connection* connection) {      LOGI("channel '%s' ~ Not responding!  %01.1fms since event, %01.1fms since dispatch",              connection->getInputChannelName(),              connection->getEventLatencyMillis(currentTime),              connection->getDispatchLatencyMillis(currentTime)); -    // TODO tell framework +    CommandEntry* commandEntry = postCommandLocked( +            & InputDispatcher::doNotifyInputChannelANRLockedInterruptible); +    commandEntry->inputChannel = connection->inputChannel;  } -void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleBrokenLocked( +        nsecs_t currentTime, Connection* connection) {      LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",              connection->getInputChannelName()); -    // TODO tell framework +    CommandEntry* commandEntry = postCommandLocked( +            & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); +    commandEntry->inputChannel = connection->inputChannel;  } +void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( +        CommandEntry* commandEntry) { +    mLock.unlock(); + +    mPolicy->notifyInputChannelBroken(commandEntry->inputChannel); +    commandEntry->inputChannel.clear(); + +    mLock.lock(); +} + +void InputDispatcher::doNotifyInputChannelANRLockedInterruptible( +        CommandEntry* commandEntry) { +    mLock.unlock(); + +    mPolicy->notifyInputChannelANR(commandEntry->inputChannel); +    commandEntry->inputChannel.clear(); + +    mLock.lock(); +} + +void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible( +        CommandEntry* commandEntry) { +    mLock.unlock(); + +    mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel); +    commandEntry->inputChannel.clear(); + +    mLock.lock(); +} + +  // --- InputDispatcher::Allocator ---  InputDispatcher::Allocator::Allocator() { @@ -1166,6 +1285,7 @@ InputDispatcher::Allocator::obtainConfigurationChangedEntry() {      ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();      entry->refCount = 1;      entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED; +    entry->dispatchInProgress = false;      return entry;  } @@ -1173,6 +1293,7 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry() {      KeyEntry* entry = mKeyEntryPool.alloc();      entry->refCount = 1;      entry->type = EventEntry::TYPE_KEY; +    entry->dispatchInProgress = false;      return entry;  } @@ -1181,6 +1302,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry() {      entry->refCount = 1;      entry->type = EventEntry::TYPE_MOTION;      entry->firstSample.next = NULL; +    entry->dispatchInProgress = false;      return entry;  } @@ -1192,6 +1314,12 @@ InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry(      return entry;  } +InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) { +    CommandEntry* entry = mCommandEntryPool.alloc(); +    entry->command = command; +    return entry; +} +  void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) {      switch (entry->type) {      case EventEntry::TYPE_CONFIGURATION_CHANGED: @@ -1231,7 +1359,11 @@ void InputDispatcher::Allocator::releaseKeyEntry(KeyEntry* entry) {  void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) {      entry->refCount -= 1;      if (entry->refCount == 0) { -        freeMotionSampleList(entry->firstSample.next); +        for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) { +            MotionSample* next = sample->next; +            mMotionSamplePool.free(sample); +            sample = next; +        }          mMotionEntryPool.free(entry);      } else {          assert(entry->refCount > 0); @@ -1243,6 +1375,10 @@ void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) {      mDispatchEntryPool.free(entry);  } +void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) { +    mCommandEntryPool.free(entry); +} +  void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,          nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) {      MotionSample* sample = mMotionSamplePool.alloc(); @@ -1256,18 +1392,6 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,      motionEntry->lastSample = sample;  } -void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) { -    mMotionSamplePool.free(sample); -} - -void InputDispatcher::Allocator::freeMotionSampleList(MotionSample* head) { -    while (head) { -        MotionSample* next = head->next; -        mMotionSamplePool.free(head); -        head = next; -    } -} -  // --- InputDispatcher::Connection ---  InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : @@ -1284,6 +1408,25 @@ status_t InputDispatcher::Connection::initialize() {      return inputPublisher.initialize();  } +const char* InputDispatcher::Connection::getStatusLabel() const { +    switch (status) { +    case STATUS_NORMAL: +        return "NORMAL"; + +    case STATUS_BROKEN: +        return "BROKEN"; + +    case STATUS_NOT_RESPONDING: +        return "NOT_RESPONDING"; + +    case STATUS_ZOMBIE: +        return "ZOMBIE"; + +    default: +        return "UNKNOWN"; +    } +} +  InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(          const EventEntry* eventEntry) const {      for (DispatchEntry* dispatchEntry = outboundQueue.tail.prev; @@ -1295,6 +1438,14 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchE      return NULL;  } +// --- InputDispatcher::CommandEntry --- + +InputDispatcher::CommandEntry::CommandEntry() { +} + +InputDispatcher::CommandEntry::~CommandEntry() { +} +  // --- InputDispatcherThread ---  |