diff options
-rw-r--r-- | services/input/EventHub.cpp | 181 | ||||
-rw-r--r-- | services/input/EventHub.h | 18 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 95 | ||||
-rw-r--r-- | services/input/InputReader.h | 17 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 10 |
5 files changed, 183 insertions, 138 deletions
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 41993fd..7625adb 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -127,9 +127,11 @@ EventHub::EventHub(void) : mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), mOpeningDevices(0), mClosingDevices(0), mOpened(false), mNeedToSendFinishedDeviceScan(false), - mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { + mInputFdIndex(1) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); + memset(mSwitches, 0, sizeof(mSwitches)); + mNumCpus = sysconf(_SC_NPROCESSORS_ONLN); } EventHub::~EventHub(void) { @@ -445,17 +447,10 @@ EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { return NULL; } -bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) { - outEvent->deviceId = 0; - outEvent->type = 0; - outEvent->scanCode = 0; - outEvent->keyCode = 0; - outEvent->flags = 0; - outEvent->value = 0; - outEvent->when = 0; - - // Note that we only allow one caller to getEvent(), so don't need +size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { + // Note that we only allow one caller to getEvents(), so don't need // to do locking here... only when adding/removing devices. + assert(bufferSize >= 1); if (!mOpened) { mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR; @@ -463,99 +458,62 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) { mNeedToSendFinishedDeviceScan = true; } + struct input_event readBuffer[bufferSize]; + + RawEvent* event = buffer; + size_t capacity = bufferSize; for (;;) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + // Report any devices that had last been added/removed. - if (mClosingDevices != NULL) { + while (mClosingDevices) { Device* device = mClosingDevices; LOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_REMOVED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); + event->when = now; + event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + event->type = DEVICE_REMOVED; + event += 1; delete device; mNeedToSendFinishedDeviceScan = true; - return true; + if (--capacity == 0) { + break; + } } - if (mOpeningDevices != NULL) { + while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; LOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_ADDED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); + event->when = now; + event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + event->type = DEVICE_ADDED; + event += 1; mNeedToSendFinishedDeviceScan = true; - return true; + if (--capacity == 0) { + break; + } } if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; - outEvent->type = FINISHED_DEVICE_SCAN; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; + event->when = now; + event->type = FINISHED_DEVICE_SCAN; + event += 1; + if (--capacity == 0) { + break; + } } // Grab the next input event. + // mInputFdIndex is initially 1 because index 0 is used for inotify. bool deviceWasRemoved = false; - for (;;) { - // Consume buffered input events, if any. - if (mInputBufferIndex < mInputBufferCount) { - const struct input_event& iev = mInputBufferData[mInputBufferIndex++]; - const Device* device = mDevices[mInputFdIndex]; - - LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = iev.type; - outEvent->scanCode = iev.code; - outEvent->flags = 0; - if (iev.type == EV_KEY) { - outEvent->keyCode = AKEYCODE_UNKNOWN; - if (device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, - &outEvent->keyCode, &outEvent->flags); - LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", - iev.code, outEvent->keyCode, outEvent->flags, err); - } - } else { - outEvent->keyCode = iev.code; - } - outEvent->value = iev.value; - - // Use an event timestamp in the same timebase as - // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis() - // as expected by the rest of the system. - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; - } - - // Finish reading all events from devices identified in previous poll(). - // This code assumes that mInputDeviceIndex is initially 0 and that the - // revents member of pollfd is initialized to 0 when the device is first added. - // Since mFds[0] is used for inotify, we process regular events starting at index 1. - mInputFdIndex += 1; - if (mInputFdIndex >= mFds.size()) { - break; - } - + while (mInputFdIndex < mFds.size()) { const struct pollfd& pfd = mFds[mInputFdIndex]; if (pfd.revents & POLLIN) { - int32_t readSize = read(pfd.fd, mInputBufferData, - sizeof(struct input_event) * INPUT_BUFFER_SIZE); + int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize < 0) { if (errno == ENODEV) { deviceWasRemoved = true; @@ -566,11 +524,43 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) { } } else if ((readSize % sizeof(struct input_event)) != 0) { LOGE("could not get event (wrong size: %d)", readSize); + } else if (readSize == 0) { // eof + deviceWasRemoved = true; + break; } else { - mInputBufferCount = size_t(readSize) / sizeof(struct input_event); - mInputBufferIndex = 0; + const Device* device = mDevices[mInputFdIndex]; + int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + + size_t count = size_t(readSize) / sizeof(struct input_event); + for (size_t i = 0; i < count; i++) { + const struct input_event& iev = readBuffer[i]; + LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d", + device->path.string(), + (int) iev.time.tv_sec, (int) iev.time.tv_usec, + iev.type, iev.code, iev.value); + + event->when = now; + event->deviceId = deviceId; + event->type = iev.type; + event->scanCode = iev.code; + event->value = iev.value; + event->keyCode = AKEYCODE_UNKNOWN; + event->flags = 0; + if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, + &event->keyCode, &event->flags); + LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", + iev.code, event->keyCode, event->flags, err); + } + event += 1; + } + capacity -= count; + if (capacity == 0) { + break; + } } } + mInputFdIndex += 1; } // Handle the case where a device has been removed but INotify has not yet noticed. @@ -586,10 +576,16 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) { if(mFds[0].revents & POLLIN) { readNotify(mFds[0].fd); mFds.editItemAt(0).revents = 0; + mInputFdIndex = mFds.size(); continue; // report added or removed devices immediately } #endif + // Return now if we have collected any events, otherwise poll. + if (event != buffer) { + break; + } + // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during poll(). This works due to some // subtle choreography. When a device driver has pending (unread) events, it acquires @@ -608,19 +604,36 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); if (pollResult == 0) { - // Timed out. - return false; + break; // timed out } if (pollResult < 0) { + // Sleep after errors to avoid locking up the system. + // Hopefully the error is transient. if (errno != EINTR) { LOGW("poll failed (errno=%d)\n", errno); usleep(100000); } + } else { + // On an SMP system, it is possible for the framework to read input events + // faster than the kernel input device driver can produce a complete packet. + // Because poll() wakes up as soon as the first input event becomes available, + // the framework will often end up reading one event at a time until the + // packet is complete. Instead of one call to read() returning 71 events, + // it could take 71 calls to read() each returning 1 event. + // + // Sleep for a short period of time after waking up from the poll() to give + // the kernel time to finish writing the entire packet of input events. + if (mNumCpus > 1) { + usleep(250); + } } // Prepare to process all of the FDs we just polled. - mInputFdIndex = 0; + mInputFdIndex = 1; } + + // All done, return the number of events we read. + return event - buffer; } /* diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 1d287ac..4d26a95 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -157,6 +157,8 @@ public: // Sent when all added/removed devices from the most recent scan have been reported. // This event is always sent at least once. FINISHED_DEVICE_SCAN = 0x30000000, + + FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, }; virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; @@ -181,7 +183,7 @@ public: virtual void addExcludedDevice(const char* deviceName) = 0; /* - * Wait for the next event to become available and return it. + * Wait for events to become available and returns them. * After returning, the EventHub holds onto a wake lock until the next call to getEvent. * This ensures that the device will not go to sleep while the event is being processed. * If the device needs to remain awake longer than that, then the caller is responsible @@ -190,9 +192,9 @@ public: * The timeout is advisory only. If the device is asleep, it will not wake just to * service the timeout. * - * Returns true if an event was obtained, false if the timeout expired. + * Returns the number of events obtained, or 0 if the timeout expired. */ - virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) = 0; + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; /* * Query current input state. @@ -249,7 +251,7 @@ public: virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; - virtual bool getEvent(int timeoutMillis, RawEvent* outEvent); + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual bool hasLed(int32_t deviceId, int32_t led) const; virtual void setLedState(int32_t deviceId, int32_t led, bool on); @@ -336,11 +338,11 @@ private: // device ids that report particular switches. int32_t mSwitches[SW_MAX + 1]; - static const int INPUT_BUFFER_SIZE = 64; - struct input_event mInputBufferData[INPUT_BUFFER_SIZE]; - size_t mInputBufferIndex; - size_t mInputBufferCount; + // The index of the next file descriptor that needs to be read. size_t mInputFdIndex; + + // Set to the number of CPUs. + int32_t mNumCpus; }; }; // namespace android diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 182bd50..94753bf 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -250,15 +250,11 @@ void InputReader::loopOnce() { timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } - RawEvent rawEvent; - if (mEventHub->getEvent(timeoutMillis, &rawEvent)) { -#if DEBUG_RAW_EVENTS - LOGD("Input event: device=%d type=0x%04x scancode=0x%04x keycode=0x%04x value=0x%04x", - rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode, - rawEvent.value); -#endif - process(&rawEvent); - } else { + size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); + if (count) { + processEvents(mEventBuffer, count); + } + if (!count || timeoutMillis == 0) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); #if DEBUG_RAW_EVENTS LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); @@ -268,23 +264,41 @@ void InputReader::loopOnce() { } } -void InputReader::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDevice(rawEvent->deviceId); - break; - - case EventHubInterface::DEVICE_REMOVED: - removeDevice(rawEvent->deviceId); - break; - - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChanged(rawEvent->when); - break; - - default: - consumeEvent(rawEvent); - break; +void InputReader::processEvents(const RawEvent* rawEvents, size_t count) { + for (const RawEvent* rawEvent = rawEvents; count;) { + int32_t type = rawEvent->type; + size_t batchSize = 1; + if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { + int32_t deviceId = rawEvent->deviceId; + while (batchSize < count) { + if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT + || rawEvent[batchSize].deviceId != deviceId) { + break; + } + batchSize += 1; + } +#if DEBUG_RAW_EVENTS + LOGD("BatchSize: %d Count: %d", batchSize, count); +#endif + processEventsForDevice(deviceId, rawEvent, batchSize); + } else { + switch (rawEvent->type) { + case EventHubInterface::DEVICE_ADDED: + addDevice(rawEvent->deviceId); + break; + case EventHubInterface::DEVICE_REMOVED: + removeDevice(rawEvent->deviceId); + break; + case EventHubInterface::FINISHED_DEVICE_SCAN: + handleConfigurationChanged(rawEvent->when); + break; + default: + assert(false); // can't happen + break; + } + } + count -= batchSize; + rawEvent += batchSize; } } @@ -405,9 +419,8 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui return device; } -void InputReader::consumeEvent(const RawEvent* rawEvent) { - int32_t deviceId = rawEvent->deviceId; - +void InputReader::processEventsForDevice(int32_t deviceId, + const RawEvent* rawEvents, size_t count) { { // acquire device registry reader lock RWLock::AutoRLock _rl(mDeviceRegistryLock); @@ -423,7 +436,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { return; } - device->process(rawEvent); + device->process(rawEvents, count); } // release device registry reader lock } @@ -785,11 +798,25 @@ void InputDevice::reset() { } } -void InputDevice::process(const RawEvent* rawEvent) { +void InputDevice::process(const RawEvent* rawEvents, size_t count) { + // Process all of the events in order for each mapper. + // We cannot simply ask each mapper to process them in bulk because mappers may + // have side-effects that must be interleaved. For example, joystick movement events and + // gamepad button presses are handled by different mappers but they should be dispatched + // in the order received. size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); + for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { +#if DEBUG_RAW_EVENTS + LOGD("Input event: device=%d type=0x%04x scancode=0x%04x " + "keycode=0x%04x value=0x%04x flags=0x%08x", + rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode, + rawEvent->value, rawEvent->flags); +#endif + + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->process(rawEvent); + } } } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index fdb4cfc..cf9b13d 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -216,6 +216,10 @@ private: virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } + // The event queue. + static const int EVENT_BUFFER_SIZE = 256; + RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; + // This reader/writer lock guards the list of input devices. // The writer lock must be held whenever the list of input devices is modified // and then promptly released. @@ -228,16 +232,15 @@ private: KeyedVector<int32_t, InputDevice*> mDevices; // low-level input event decoding and device management - void process(const RawEvent* rawEvent); + void processEvents(const RawEvent* rawEvents, size_t count); void addDevice(int32_t deviceId); void removeDevice(int32_t deviceId); - void configureExcludedDevices(); - - void consumeEvent(const RawEvent* rawEvent); + void processEventsForDevice(int32_t deviceId, const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); void handleConfigurationChanged(nsecs_t when); + void configureExcludedDevices(); // state management for all devices Mutex mStateLock; @@ -251,12 +254,12 @@ private: InputConfiguration mInputConfiguration; void updateInputConfiguration(); - nsecs_t mDisableVirtualKeysTimeout; + nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread virtual void disableVirtualKeysUntil(nsecs_t time); virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); - nsecs_t mNextTimeout; + nsecs_t mNextTimeout; // only accessed by reader thread virtual void requestTimeoutAtTime(nsecs_t when); // state queries @@ -301,7 +304,7 @@ public: void addMapper(InputMapper* mapper); void configure(); void reset(); - void process(const RawEvent* rawEvent); + void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 4d92207..60549c6 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -622,14 +622,14 @@ private: mExcludedDevices.add(String8(deviceName)); } - virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) { + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { if (mEvents.empty()) { - return false; + return 0; } - *outEvent = *mEvents.begin(); + *buffer = *mEvents.begin(); mEvents.erase(mEvents.begin()); - return true; + return 1; } virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { @@ -1445,7 +1445,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe // Event handling. RawEvent event; - mDevice->process(&event); + mDevice->process(&event, 1); ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); |