summaryrefslogtreecommitdiffstats
path: root/core/jni/android_view_InputEventReceiver.cpp
diff options
context:
space:
mode:
authorMichael Wright <michaelwr@google.com>2013-10-25 14:50:36 -0700
committerMichael Wright <michaelwr@google.com>2013-10-26 12:18:00 -0700
commit62ce65d6edbc2c34c63b0e2f2fef9cb08e28c783 (patch)
tree7b6584c178d38fe7392e0057e5f3b8b7fb271311 /core/jni/android_view_InputEventReceiver.cpp
parent7c2a2ef2ee71d65ac43acf3dad95df1629dfc674 (diff)
downloadframeworks_base-62ce65d6edbc2c34c63b0e2f2fef9cb08e28c783.zip
frameworks_base-62ce65d6edbc2c34c63b0e2f2fef9cb08e28c783.tar.gz
frameworks_base-62ce65d6edbc2c34c63b0e2f2fef9cb08e28c783.tar.bz2
Speculatively schedule input consumption
With the new tuned vsync offset, vsyncs are likely to occur shortly after the input is received, meaning we will empty the input queue, and thus won't schedule input consumption until more input is received. If an application then speculatively posts draw commands to the main looper faster than 60 hz, it will eventually end up blocking in eglSwapBuffers. Since we're blocking in eglSwapBuffers, we won't even schedule consumption until after the current frame (8-16ms), and it's entirely likely we won't actually get around to consuming input until after the next frame (another 16 ms of latency). This means we can often go 16-32ms without processing any input events, causing very noticeable amounts of jank. Rather than waiting for the next input event to schedule input consumption, speculatively schedule it every frame as long as we've consumed some motion batch during this frame. Bug: 11398045 Change-Id: I25e46308e00e9f9de00a1d8906f6b0e0f2e845b4
Diffstat (limited to 'core/jni/android_view_InputEventReceiver.cpp')
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp30
1 files changed, 21 insertions, 9 deletions
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index b254de7..92a3e62 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -56,7 +56,8 @@ public:
status_t initialize();
void dispose();
status_t finishInputEvent(uint32_t seq, bool handled);
- status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime);
+ status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime,
+ bool* outConsumedBatch);
protected:
virtual ~NativeInputEventReceiver();
@@ -167,7 +168,7 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
+ status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
@@ -214,7 +215,7 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
- bool consumeBatches, nsecs_t frameTime) {
+ bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
getInputChannelName(), consumeBatches ? "true" : "false", frameTime);
@@ -223,6 +224,9 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
if (consumeBatches) {
mBatchedInputEventPending = false;
}
+ if (outConsumedBatch) {
+ *outConsumedBatch = false;
+ }
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
@@ -285,13 +289,17 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
static_cast<KeyEvent*>(inputEvent));
break;
- case AINPUT_EVENT_TYPE_MOTION:
+ case AINPUT_EVENT_TYPE_MOTION: {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
#endif
- inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
- static_cast<MotionEvent*>(inputEvent));
+ MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
+ if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
+ *outConsumedBatch = true;
+ }
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
+ }
default:
assert(false); // InputConsumer should prevent this from ever happening
@@ -370,16 +378,20 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
}
}
-static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr,
+static bool nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr,
jlong frameTimeNanos) {
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
- status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos);
+ bool consumedBatch;
+ status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
+ &consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
String8 message;
message.appendFormat("Failed to consume batched input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
+ return false;
}
+ return consumedBatch;
}
@@ -392,7 +404,7 @@ static JNINativeMethod gMethods[] = {
(void*)nativeDispose },
{ "nativeFinishInputEvent", "(IIZ)V",
(void*)nativeFinishInputEvent },
- { "nativeConsumeBatchedInputEvents", "(IJ)V",
+ { "nativeConsumeBatchedInputEvents", "(IJ)Z",
(void*)nativeConsumeBatchedInputEvents },
};