1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "../InputDispatcher.h" 18 19#include <gtest/gtest.h> 20#include <linux/input.h> 21 22namespace android { 23 24// An arbitrary time value. 25static const nsecs_t ARBITRARY_TIME = 1234; 26 27// An arbitrary device id. 28static const int32_t DEVICE_ID = 1; 29 30// An arbitrary display id. 31static const int32_t DISPLAY_ID = 0; 32 33// An arbitrary injector pid / uid pair that has permission to inject events. 34static const int32_t INJECTOR_PID = 999; 35static const int32_t INJECTOR_UID = 1001; 36 37 38// --- FakeInputDispatcherPolicy --- 39 40class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { 41 InputDispatcherConfiguration mConfig; 42 43protected: 44 virtual ~FakeInputDispatcherPolicy() { 45 } 46 47public: 48 FakeInputDispatcherPolicy() { 49 } 50 51private: 52 virtual void notifyConfigurationChanged(nsecs_t when) { 53 } 54 55 virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, 56 const sp<InputWindowHandle>& inputWindowHandle, 57 const String8& reason) { 58 return 0; 59 } 60 61 virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { 62 } 63 64 virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { 65 *outConfig = mConfig; 66 } 67 68 virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) { 69 return true; 70 } 71 72 virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { 73 } 74 75 virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { 76 } 77 78 virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, 79 const KeyEvent* keyEvent, uint32_t policyFlags) { 80 return 0; 81 } 82 83 virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, 84 const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { 85 return false; 86 } 87 88 virtual void notifySwitch(nsecs_t when, 89 uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) { 90 } 91 92 virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) { 93 } 94 95 virtual bool checkInjectEventsPermissionNonReentrant( 96 int32_t injectorPid, int32_t injectorUid) { 97 return false; 98 } 99}; 100 101 102// --- InputDispatcherTest --- 103 104class InputDispatcherTest : public testing::Test { 105protected: 106 sp<FakeInputDispatcherPolicy> mFakePolicy; 107 sp<InputDispatcher> mDispatcher; 108 109 virtual void SetUp() { 110 mFakePolicy = new FakeInputDispatcherPolicy(); 111 mDispatcher = new InputDispatcher(mFakePolicy); 112 } 113 114 virtual void TearDown() { 115 mFakePolicy.clear(); 116 mDispatcher.clear(); 117 } 118}; 119 120 121TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { 122 KeyEvent event; 123 124 // Rejects undefined key actions. 125 event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, 126 /*action*/ -1, 0, 127 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); 128 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 129 &event, DISPLAY_ID, 130 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 131 << "Should reject key events with undefined action."; 132 133 // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. 134 event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, 135 AKEY_EVENT_ACTION_MULTIPLE, 0, 136 AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); 137 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 138 &event, DISPLAY_ID, 139 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 140 << "Should reject key events with ACTION_MULTIPLE."; 141} 142 143TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 144 MotionEvent event; 145 PointerProperties pointerProperties[MAX_POINTERS + 1]; 146 PointerCoords pointerCoords[MAX_POINTERS + 1]; 147 for (int i = 0; i <= MAX_POINTERS; i++) { 148 pointerProperties[i].clear(); 149 pointerProperties[i].id = i; 150 pointerCoords[i].clear(); 151 } 152 153 // Rejects undefined motion actions. 154 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 155 /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 156 ARBITRARY_TIME, ARBITRARY_TIME, 157 /*pointerCount*/ 1, pointerProperties, pointerCoords); 158 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 159 &event, DISPLAY_ID, 160 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 161 << "Should reject motion events with undefined action."; 162 163 // Rejects pointer down with invalid index. 164 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 165 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 166 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 167 ARBITRARY_TIME, ARBITRARY_TIME, 168 /*pointerCount*/ 1, pointerProperties, pointerCoords); 169 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 170 &event, DISPLAY_ID, 171 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 172 << "Should reject motion events with pointer down index too large."; 173 174 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 175 AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 176 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 177 ARBITRARY_TIME, ARBITRARY_TIME, 178 /*pointerCount*/ 1, pointerProperties, pointerCoords); 179 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 180 &event, DISPLAY_ID, 181 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 182 << "Should reject motion events with pointer down index too small."; 183 184 // Rejects pointer up with invalid index. 185 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 186 AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 187 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 188 ARBITRARY_TIME, ARBITRARY_TIME, 189 /*pointerCount*/ 1, pointerProperties, pointerCoords); 190 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 191 &event, DISPLAY_ID, 192 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 193 << "Should reject motion events with pointer up index too large."; 194 195 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 196 AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 197 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 198 ARBITRARY_TIME, ARBITRARY_TIME, 199 /*pointerCount*/ 1, pointerProperties, pointerCoords); 200 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 201 &event, DISPLAY_ID, 202 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 203 << "Should reject motion events with pointer up index too small."; 204 205 // Rejects motion events with invalid number of pointers. 206 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 207 AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 208 ARBITRARY_TIME, ARBITRARY_TIME, 209 /*pointerCount*/ 0, pointerProperties, pointerCoords); 210 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 211 &event, DISPLAY_ID, 212 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 213 << "Should reject motion events with 0 pointers."; 214 215 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 216 AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 217 ARBITRARY_TIME, ARBITRARY_TIME, 218 /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); 219 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 220 &event, DISPLAY_ID, 221 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 222 << "Should reject motion events with more than MAX_POINTERS pointers."; 223 224 // Rejects motion events with invalid pointer ids. 225 pointerProperties[0].id = -1; 226 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 227 AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 228 ARBITRARY_TIME, ARBITRARY_TIME, 229 /*pointerCount*/ 1, pointerProperties, pointerCoords); 230 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 231 &event, DISPLAY_ID, 232 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 233 << "Should reject motion events with pointer ids less than 0."; 234 235 pointerProperties[0].id = MAX_POINTER_ID + 1; 236 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 237 AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 238 ARBITRARY_TIME, ARBITRARY_TIME, 239 /*pointerCount*/ 1, pointerProperties, pointerCoords); 240 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 241 &event, DISPLAY_ID, 242 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 243 << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; 244 245 // Rejects motion events with duplicate pointer ids. 246 pointerProperties[0].id = 1; 247 pointerProperties[1].id = 1; 248 event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, 249 AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, 250 ARBITRARY_TIME, ARBITRARY_TIME, 251 /*pointerCount*/ 2, pointerProperties, pointerCoords); 252 ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( 253 &event, DISPLAY_ID, 254 INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) 255 << "Should reject motion events with duplicate pointer ids."; 256} 257 258} // namespace android 259