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 
22 namespace android {
23 
24 // An arbitrary time value.
25 static const nsecs_t ARBITRARY_TIME = 1234;
26 
27 // An arbitrary device id.
28 static const int32_t DEVICE_ID = 1;
29 
30 // An arbitrary display id.
31 static const int32_t DISPLAY_ID = 0;
32 
33 // An arbitrary injector pid / uid pair that has permission to inject events.
34 static const int32_t INJECTOR_PID = 999;
35 static const int32_t INJECTOR_UID = 1001;
36 
37 
38 // --- FakeInputDispatcherPolicy ---
39 
40 class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
41     InputDispatcherConfiguration mConfig;
42 
43 protected:
~FakeInputDispatcherPolicy()44     virtual ~FakeInputDispatcherPolicy() {
45     }
46 
47 public:
FakeInputDispatcherPolicy()48     FakeInputDispatcherPolicy() {
49     }
50 
51 private:
notifyConfigurationChanged(nsecs_t when)52     virtual void notifyConfigurationChanged(nsecs_t when) {
53     }
54 
notifyANR(const sp<InputApplicationHandle> & inputApplicationHandle,const sp<InputWindowHandle> & inputWindowHandle,const String8 & reason)55     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
56             const sp<InputWindowHandle>& inputWindowHandle,
57             const String8& reason) {
58         return 0;
59     }
60 
notifyInputChannelBroken(const sp<InputWindowHandle> & inputWindowHandle)61     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
62     }
63 
getDispatcherConfiguration(InputDispatcherConfiguration * outConfig)64     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
65         *outConfig = mConfig;
66     }
67 
filterInputEvent(const InputEvent * inputEvent,uint32_t policyFlags)68     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
69         return true;
70     }
71 
interceptKeyBeforeQueueing(const KeyEvent * keyEvent,uint32_t & policyFlags)72     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
73     }
74 
interceptMotionBeforeQueueing(nsecs_t when,uint32_t & policyFlags)75     virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
76     }
77 
interceptKeyBeforeDispatching(const sp<InputWindowHandle> & inputWindowHandle,const KeyEvent * keyEvent,uint32_t policyFlags)78     virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
79             const KeyEvent* keyEvent, uint32_t policyFlags) {
80         return 0;
81     }
82 
dispatchUnhandledKey(const sp<InputWindowHandle> & inputWindowHandle,const KeyEvent * keyEvent,uint32_t policyFlags,KeyEvent * outFallbackKeyEvent)83     virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
84             const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
85         return false;
86     }
87 
notifySwitch(nsecs_t when,uint32_t switchValues,uint32_t switchMask,uint32_t policyFlags)88     virtual void notifySwitch(nsecs_t when,
89             uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) {
90     }
91 
pokeUserActivity(nsecs_t eventTime,int32_t eventType)92     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
93     }
94 
checkInjectEventsPermissionNonReentrant(int32_t injectorPid,int32_t injectorUid)95     virtual bool checkInjectEventsPermissionNonReentrant(
96             int32_t injectorPid, int32_t injectorUid) {
97         return false;
98     }
99 };
100 
101 
102 // --- InputDispatcherTest ---
103 
104 class InputDispatcherTest : public testing::Test {
105 protected:
106     sp<FakeInputDispatcherPolicy> mFakePolicy;
107     sp<InputDispatcher> mDispatcher;
108 
SetUp()109     virtual void SetUp() {
110         mFakePolicy = new FakeInputDispatcherPolicy();
111         mDispatcher = new InputDispatcher(mFakePolicy);
112     }
113 
TearDown()114     virtual void TearDown() {
115         mFakePolicy.clear();
116         mDispatcher.clear();
117     }
118 };
119 
120 
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesKeyEvents)121 TEST_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 
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesMotionEvents)143 TEST_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