android_frameworks_base/services/input/tests/InputDispatcher_test.cpp
Jeff Brown 928e054931 Prevent events from getting backlogged.
This change implements two heuristics.

1. When events are older than 10 seconds, they are dropped.

2. If the application is currently busy processing an event and
   the user touches a window belonging to a different application
   then we drop the currently queued events so the other application
   can start processing the gesture immediately.

Note that the system takes care of synthesizing cancelation events
automatically for any events that it drops.

Added some new handle types to allow the native dispatcher to
indirectly refer to the WindowManager's window state and app window
token.  This was done to enable the dispatcher to identify the
application to which each window belongs but it also eliminates
some lookup tables and linear searches through the window list
on each key press.

Bug: 3224911
Change-Id: I9dae8dfe23d195d76865f97011fe2f1d351e2940
2011-01-10 17:23:05 -08:00

231 lines
9.1 KiB
C++

//
// Copyright 2010 The Android Open Source Project
//
#include "../InputDispatcher.h"
#include <gtest/gtest.h>
#include <linux/input.h>
namespace android {
// An arbitrary time value.
static const nsecs_t ARBITRARY_TIME = 1234;
// An arbitrary device id.
static const int32_t DEVICE_ID = 1;
// An arbitrary injector pid / uid pair that has permission to inject events.
static const int32_t INJECTOR_PID = 999;
static const int32_t INJECTOR_UID = 1001;
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
protected:
virtual ~FakeInputDispatcherPolicy() {
}
public:
FakeInputDispatcherPolicy() {
}
private:
virtual void notifyConfigurationChanged(nsecs_t when) {
}
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle) {
return 0;
}
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
}
virtual nsecs_t getKeyRepeatTimeout() {
return 500 * 1000000LL;
}
virtual nsecs_t getKeyRepeatDelay() {
return 50 * 1000000LL;
}
virtual int32_t getMaxEventsPerSecond() {
return 60;
}
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
}
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
}
virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
const KeyEvent* keyEvent, uint32_t policyFlags) {
return false;
}
virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
return false;
}
virtual void notifySwitch(nsecs_t when,
int32_t switchCode, int32_t switchValue, uint32_t policyFlags) {
}
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
}
virtual bool checkInjectEventsPermissionNonReentrant(
int32_t injectorPid, int32_t injectorUid) {
return false;
}
};
// --- InputDispatcherTest ---
class InputDispatcherTest : public testing::Test {
protected:
sp<FakeInputDispatcherPolicy> mFakePolicy;
sp<InputDispatcher> mDispatcher;
virtual void SetUp() {
mFakePolicy = new FakeInputDispatcherPolicy();
mDispatcher = new InputDispatcher(mFakePolicy);
}
virtual void TearDown() {
mFakePolicy.clear();
mDispatcher.clear();
}
};
TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
KeyEvent event;
// Rejects undefined key actions.
event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
/*action*/ -1, 0,
AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
AKEY_EVENT_ACTION_MULTIPLE, 0,
AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
MotionEvent event;
int32_t pointerIds[MAX_POINTERS + 1];
PointerCoords pointerCoords[MAX_POINTERS + 1];
for (int i = 0; i <= MAX_POINTERS; i++) {
pointerIds[i] = i;
}
// Rejects undefined motion actions.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
/*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
pointerIds[0] = -1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerIds[0] = MAX_POINTER_ID + 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
pointerIds[0] = 1;
pointerIds[1] = 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerIds, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
} // namespace android