diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ui/EventHub.cpp | 9 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 82 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 160 | ||||
-rw-r--r-- | libs/utils/ObbFile.cpp | 32 |
4 files changed, 199 insertions, 84 deletions
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index a3c34d0..891661d 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -581,7 +581,6 @@ int EventHub::open_device(const char *deviceName) if (strcmp(name, test) == 0) { LOGI("ignoring event id %s driver %s\n", deviceName, test); close(fd); - fd = -1; return -1; } } @@ -813,6 +812,14 @@ int EventHub::open_device(const char *deviceName) device->id, name, propName, keylayoutFilename); } + // If the device isn't recognized as something we handle, don't monitor it. + if (device->classes == 0) { + LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid); + close(fd); + delete device; + return -1; + } + LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 13030b5..ce616a4 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -28,6 +28,9 @@ // Log debug messages about input event injection. #define DEBUG_INJECTION 0 +// Log debug messages about input event throttling. +#define DEBUG_THROTTLING 0 + #include <cutils/log.h> #include <ui/InputDispatcher.h> @@ -66,6 +69,15 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; + int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); + mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; + mThrottleState.lastDeviceId = -1; + +#if DEBUG_THROTTLING + mThrottleState.originalSampleCount = 0; + LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); +#endif + mCurrentInputTargetsValid = false; } @@ -144,12 +156,60 @@ void InputDispatcher::dispatchOnce() { } } else { // Inbound queue has at least one entry. - // Start processing it but leave it on the queue until later so that the + EventEntry* entry = mInboundQueue.head.next; + + // Consider throttling the entry if it is a move event and there are no + // other events behind it in the queue. Due to movement batching, additional + // samples may be appended to this event by the time the throttling timeout + // expires. + // TODO Make this smarter and consider throttling per device independently. + if (entry->type == EventEntry::TYPE_MOTION) { + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + int32_t deviceId = motionEntry->deviceId; + uint32_t source = motionEntry->source; + if (motionEntry->next == & mInboundQueue.tail + && motionEntry->action == AMOTION_EVENT_ACTION_MOVE + && deviceId == mThrottleState.lastDeviceId + && source == mThrottleState.lastSource) { + nsecs_t nextTime = mThrottleState.lastEventTime + + mThrottleState.minTimeBetweenEvents; + if (currentTime < nextTime) { + // Throttle it! +#if DEBUG_THROTTLING + LOGD("Throttling - Delaying motion event for " + "device 0x%x, source 0x%08x by up to %0.3fms.", + deviceId, source, (nextTime - currentTime) * 0.000001); +#endif + if (nextTime < nextWakeupTime) { + nextWakeupTime = nextTime; + } + if (mThrottleState.originalSampleCount == 0) { + mThrottleState.originalSampleCount = + motionEntry->countSamples(); + } + goto Throttle; + } + } + +#if DEBUG_THROTTLING + if (mThrottleState.originalSampleCount != 0) { + uint32_t count = motionEntry->countSamples(); + LOGD("Throttling - Motion event sample count grew by %d from %d to %d.", + count - mThrottleState.originalSampleCount, + mThrottleState.originalSampleCount, count); + mThrottleState.originalSampleCount = 0; + } +#endif + + mThrottleState.lastEventTime = currentTime; + mThrottleState.lastDeviceId = deviceId; + mThrottleState.lastSource = source; + } + + // Start processing the entry 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 = @@ -179,6 +239,8 @@ void InputDispatcher::dispatchOnce() { mInboundQueue.dequeue(entry); mAllocator.releaseEventEntry(entry); skipPoll = true; + + Throttle: ; } } @@ -192,8 +254,8 @@ void InputDispatcher::dispatchOnce() { return; } - // Wait for callback or timeout or wake. - nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime); + // Wait for callback or timeout or wake. (make sure we round up, not down) + nsecs_t timeout = (nextWakeupTime - currentTime + 999999LL) / 1000000LL; int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0; mPollLoop->pollOnce(timeoutMillis); } @@ -1708,6 +1770,16 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, motionEntry->lastSample = sample; } +// --- InputDispatcher::MotionEntry --- + +uint32_t InputDispatcher::MotionEntry::countSamples() const { + uint32_t count = 1; + for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { + count += 1; + } + return count; +} + // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 5f5a4ac..6f042ec 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -945,7 +945,6 @@ void TrackballInputMapper::reset() { mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; mAccumulator.btnMouse = false; sync(when); - mAccumulator.clear(); } InputMapper::reset(); @@ -958,9 +957,9 @@ void TrackballInputMapper::process(const RawEvent* rawEvent) { case BTN_MOUSE: mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE; mAccumulator.btnMouse = rawEvent->value != 0; - + // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and + // we need to ensure that we report the up/down promptly. sync(rawEvent->when); - mAccumulator.clear(); break; } break; @@ -981,10 +980,7 @@ void TrackballInputMapper::process(const RawEvent* rawEvent) { case EV_SYN: switch (rawEvent->scanCode) { case SYN_REPORT: - if (mAccumulator.isDirty()) { - sync(rawEvent->when); - mAccumulator.clear(); - } + sync(rawEvent->when); break; } break; @@ -992,13 +988,17 @@ void TrackballInputMapper::process(const RawEvent* rawEvent) { } void TrackballInputMapper::sync(nsecs_t when) { + uint32_t fields = mAccumulator.fields; + if (fields == 0) { + return; // no new state changes, so nothing to do + } + int motionEventAction; PointerCoords pointerCoords; nsecs_t downTime; { // acquire lock AutoMutex _l(mLock); - uint32_t fields = mAccumulator.fields; bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; if (downChanged) { @@ -1061,6 +1061,8 @@ void TrackballInputMapper::sync(nsecs_t when) { } // release lock applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime); + + mAccumulator.clear(); } void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, @@ -2380,8 +2382,8 @@ void SingleTouchInputMapper::initialize() { mDown = false; mX = 0; mY = 0; - mPressure = 0; - mSize = 0; + mPressure = 1; // default to 1 for devices that don't report pressure + mSize = 0; // default to 0 for devices that don't report size } void SingleTouchInputMapper::reset() { @@ -2397,9 +2399,9 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { case BTN_TOUCH: mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH; mAccumulator.btnTouch = rawEvent->value != 0; - - sync(rawEvent->when); - mAccumulator.clear(); + // Don't sync immediately. Wait until the next SYN_REPORT since we might + // not have received valid position information yet. This logic assumes that + // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet. break; } break; @@ -2428,10 +2430,7 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { case EV_SYN: switch (rawEvent->scanCode) { case SYN_REPORT: - if (mAccumulator.isDirty()) { - sync(rawEvent->when); - mAccumulator.clear(); - } + sync(rawEvent->when); break; } break; @@ -2439,9 +2438,10 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { } void SingleTouchInputMapper::sync(nsecs_t when) { - /* Update device state */ - uint32_t fields = mAccumulator.fields; + if (fields == 0) { + return; // no new state changes, so nothing to do + } if (fields & Accumulator::FIELD_BTN_TOUCH) { mDown = mAccumulator.btnTouch; @@ -2472,8 +2472,8 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].y = mY; mCurrentTouch.pointers[0].pressure = mPressure; mCurrentTouch.pointers[0].size = mSize; - mCurrentTouch.pointers[0].touchMajor = mPressure; - mCurrentTouch.pointers[0].touchMinor = mPressure; + mCurrentTouch.pointers[0].touchMajor = mSize; + mCurrentTouch.pointers[0].touchMinor = mSize; mCurrentTouch.pointers[0].toolMajor = mSize; mCurrentTouch.pointers[0].toolMinor = mSize; mCurrentTouch.pointers[0].orientation = 0; @@ -2482,6 +2482,8 @@ void SingleTouchInputMapper::sync(nsecs_t when) { } syncTouch(when, true); + + mAccumulator.clear(); } void SingleTouchInputMapper::configureAxes() { @@ -2494,8 +2496,8 @@ void SingleTouchInputMapper::configureAxes() { getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure); getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size); - mAxes.touchMajor = mAxes.pressure; - mAxes.touchMinor = mAxes.pressure; + mAxes.touchMajor = mAxes.size; + mAxes.touchMinor = mAxes.size; mAxes.toolMajor = mAxes.size; mAxes.toolMinor = mAxes.size; } @@ -2585,10 +2587,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { } case SYN_REPORT: - if (mAccumulator.isDirty()) { - sync(rawEvent->when); - mAccumulator.clear(); - } + sync(rawEvent->when); break; } break; @@ -2598,11 +2597,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { void MultiTouchInputMapper::sync(nsecs_t when) { static const uint32_t REQUIRED_FIELDS = Accumulator::FIELD_ABS_MT_POSITION_X - | Accumulator::FIELD_ABS_MT_POSITION_Y - | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR - | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR; - - /* Update device state */ + | Accumulator::FIELD_ABS_MT_POSITION_Y; uint32_t inCount = mAccumulator.pointerCount; uint32_t outCount = 0; @@ -2611,53 +2606,76 @@ void MultiTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.clear(); for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) { - uint32_t fields = mAccumulator.pointers[inIndex].fields; + const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex]; + uint32_t fields = inPointer.fields; if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) { -#if DEBUG_POINTERS - LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d", - inIndex, fields); + // Some drivers send empty MT sync packets without X / Y to indicate a pointer up. + // Drop this finger. continue; -#endif } - if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) { - // Pointer is not down. Drop it. - continue; + PointerData& outPointer = mCurrentTouch.pointers[outCount]; + outPointer.x = inPointer.absMTPositionX; + outPointer.y = inPointer.absMTPositionY; + + if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) { + int32_t value = inPointer.absMTTouchMajor; + if (value <= 0) { + // Some devices send sync packets with X / Y but with a 0 touch major to indicate + // a pointer up. Drop this finger. + continue; + } + outPointer.touchMajor = inPointer.absMTTouchMajor; + } else { + outPointer.touchMajor = 0; } - mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX; - mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY; + if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) { + outPointer.touchMinor = inPointer.absMTTouchMinor; + } else { + outPointer.touchMinor = outPointer.touchMajor; + } + + if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) { + outPointer.toolMajor = inPointer.absMTWidthMajor; + } else { + outPointer.toolMajor = outPointer.touchMajor; + } - mCurrentTouch.pointers[outCount].touchMajor = - mAccumulator.pointers[inIndex].absMTTouchMajor; - mCurrentTouch.pointers[outCount].touchMinor = - (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0 - ? mAccumulator.pointers[inIndex].absMTTouchMinor - : mAccumulator.pointers[inIndex].absMTTouchMajor; + if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) { + outPointer.toolMinor = inPointer.absMTWidthMinor; + } else { + outPointer.toolMinor = outPointer.toolMajor; + } - mCurrentTouch.pointers[outCount].toolMajor = - mAccumulator.pointers[inIndex].absMTWidthMajor; - mCurrentTouch.pointers[outCount].toolMinor = - (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0 - ? mAccumulator.pointers[inIndex].absMTWidthMinor - : mAccumulator.pointers[inIndex].absMTWidthMajor; + if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) { + outPointer.orientation = inPointer.absMTOrientation; + } else { + outPointer.orientation = 0; + } - mCurrentTouch.pointers[outCount].orientation = - (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0 - ? mAccumulator.pointers[inIndex].absMTOrientation : 0; + if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { + outPointer.pressure = inPointer.absMTPressure; + } else { + // Derive an approximation of pressure. + // FIXME Traditionally we have just passed a normalized value based on + // ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not + // very meaningful, particularly on large displays. We should probably let + // pressure = touch_major / tool_major but it is unclear whether that will + // break applications. + outPointer.pressure = outPointer.touchMajor; + } - // Derive an approximation of pressure and size. - // FIXME assignment of pressure may be incorrect, probably better to let - // pressure = touch / width. Later on we pass width to MotionEvent as a size, which - // isn't quite right either. Should be using touch for that. - mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor; - mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor; + // Size is an alias for a normalized tool width. + // FIXME Normalized tool width doesn't actually make much sense since it literally + // means the approaching contact major axis is divided by its full range as + // reported by the driver. On a large display this could produce very small values. + outPointer.size = outPointer.toolMajor; if (havePointerIds) { - if (fields & Accumulator:: - FIELD_ABS_MT_TRACKING_ID) { - uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId); + if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { + uint32_t id = uint32_t(inPointer.absMTTrackingId); if (id > MAX_POINTER_ID) { #if DEBUG_POINTERS @@ -2668,7 +2686,7 @@ void MultiTouchInputMapper::sync(nsecs_t when) { havePointerIds = false; } else { - mCurrentTouch.pointers[outCount].id = id; + outPointer.id = id; mCurrentTouch.idToIndex[id] = outCount; mCurrentTouch.idBits.markBit(id); } @@ -2683,6 +2701,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointerCount = outCount; syncTouch(when, havePointerIds); + + mAccumulator.clear(); } void MultiTouchInputMapper::configureAxes() { @@ -2697,6 +2717,7 @@ void MultiTouchInputMapper::configureAxes() { getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor); getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor); getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure); if (! mAxes.touchMinor.valid) { mAxes.touchMinor = mAxes.touchMajor; @@ -2706,7 +2727,10 @@ void MultiTouchInputMapper::configureAxes() { mAxes.toolMinor = mAxes.toolMajor; } - mAxes.pressure = mAxes.touchMajor; + if (! mAxes.pressure.valid) { + mAxes.pressure = mAxes.touchMajor; + } + mAxes.size = mAxes.toolMajor; } diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp index adedf0c..e170ab8 100644 --- a/libs/utils/ObbFile.cpp +++ b/libs/utils/ObbFile.cpp @@ -29,12 +29,13 @@ #define kFooterTagSize 8 /* last two 32-bit integers */ -#define kFooterMinSize 21 /* 32-bit signature version - * 32-bit package version - * 32-bit package name size - * 1-character package name - * 32-bit footer size - * 32-bit footer marker +#define kFooterMinSize 25 /* 32-bit signature version (4 bytes) + * 32-bit package version (4 bytes) + * 32-bit flags (4 bytes) + * 32-bit package name size (4-bytes) + * >=1-character package name (1 byte) + * 32-bit footer size (4 bytes) + * 32-bit footer marker (4 bytes) */ #define kMaxBufSize 32768 /* Maximum file read buffer */ @@ -45,8 +46,9 @@ /* offsets in version 1 of the header */ #define kPackageVersionOffset 4 -#define kPackageNameLenOffset 8 -#define kPackageNameOffset 12 +#define kFlagsOffset 8 +#define kPackageNameLenOffset 12 +#define kPackageNameOffset 16 /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of @@ -78,7 +80,10 @@ typedef off64_t my_off64_t; namespace android { ObbFile::ObbFile() : - mVersion(-1) { + mPackageName(""), + mVersion(-1), + mFlags(0) +{ } ObbFile::~ObbFile() { @@ -199,6 +204,7 @@ bool ObbFile::parseObbFile(int fd) } mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset); + mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset); uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset); if (packageNameLen <= 0 @@ -268,6 +274,12 @@ bool ObbFile::writeTo(int fd) return false; } + put4LE(intBuf, mFlags); + if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { + LOGW("couldn't write package version"); + return false; + } + size_t packageNameLen = mPackageName.size(); put4LE(intBuf, packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { @@ -280,7 +292,7 @@ bool ObbFile::writeTo(int fd) return false; } - put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen); + put4LE(intBuf, kPackageNameOffset + packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { LOGW("couldn't write footer size: %s", strerror(errno)); return false; |