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)52     virtual void notifyConfigurationChanged(nsecs_t) {
53     }
54 
notifyANR(const sp<InputApplicationHandle> &,const sp<InputWindowHandle> &,const String8 &)55     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&,
56             const sp<InputWindowHandle>&,
57             const String8&) {
58         return 0;
59     }
60 
notifyInputChannelBroken(const sp<InputWindowHandle> &)61     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>&) {
62     }
63 
getDispatcherConfiguration(InputDispatcherConfiguration * outConfig)64     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
65         *outConfig = mConfig;
66     }
67 
filterInputEvent(const InputEvent *,uint32_t)68     virtual bool filterInputEvent(const InputEvent*, uint32_t) {
69         return true;
70     }
71 
interceptKeyBeforeQueueing(const KeyEvent *,uint32_t &)72     virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) {
73     }
74 
interceptMotionBeforeQueueing(nsecs_t,uint32_t &)75     virtual void interceptMotionBeforeQueueing(nsecs_t, uint32_t&) {
76     }
77 
interceptKeyBeforeDispatching(const sp<InputWindowHandle> &,const KeyEvent *,uint32_t)78     virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>&,
79             const KeyEvent*, uint32_t) {
80         return 0;
81     }
82 
dispatchUnhandledKey(const sp<InputWindowHandle> &,const KeyEvent *,uint32_t,KeyEvent *)83     virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>&,
84             const KeyEvent*, uint32_t, KeyEvent*) {
85         return false;
86     }
87 
notifySwitch(nsecs_t,uint32_t,uint32_t,uint32_t)88     virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) {
89     }
90 
pokeUserActivity(nsecs_t,int32_t)91     virtual void pokeUserActivity(nsecs_t, int32_t) {
92     }
93 
checkInjectEventsPermissionNonReentrant(int32_t,int32_t)94     virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) {
95         return false;
96     }
97 };
98 
99 
100 // --- InputDispatcherTest ---
101 
102 class InputDispatcherTest : public testing::Test {
103 protected:
104     sp<FakeInputDispatcherPolicy> mFakePolicy;
105     sp<InputDispatcher> mDispatcher;
106 
SetUp()107     virtual void SetUp() {
108         mFakePolicy = new FakeInputDispatcherPolicy();
109         mDispatcher = new InputDispatcher(mFakePolicy);
110     }
111 
TearDown()112     virtual void TearDown() {
113         mFakePolicy.clear();
114         mDispatcher.clear();
115     }
116 };
117 
118 
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesKeyEvents)119 TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
120     KeyEvent event;
121 
122     // Rejects undefined key actions.
123     event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
124             /*action*/ -1, 0,
125             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
126     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
127             &event, DISPLAY_ID,
128             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
129             << "Should reject key events with undefined action.";
130 
131     // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
132     event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
133             AKEY_EVENT_ACTION_MULTIPLE, 0,
134             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
135     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
136             &event, DISPLAY_ID,
137             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
138             << "Should reject key events with ACTION_MULTIPLE.";
139 }
140 
TEST_F(InputDispatcherTest,InjectInputEvent_ValidatesMotionEvents)141 TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
142     MotionEvent event;
143     PointerProperties pointerProperties[MAX_POINTERS + 1];
144     PointerCoords pointerCoords[MAX_POINTERS + 1];
145     for (int i = 0; i <= MAX_POINTERS; i++) {
146         pointerProperties[i].clear();
147         pointerProperties[i].id = i;
148         pointerCoords[i].clear();
149     }
150 
151     // Rejects undefined motion actions.
152     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
153             /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
154             ARBITRARY_TIME, ARBITRARY_TIME,
155             /*pointerCount*/ 1, pointerProperties, pointerCoords);
156     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
157             &event, DISPLAY_ID,
158             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
159             << "Should reject motion events with undefined action.";
160 
161     // Rejects pointer down with invalid index.
162     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
163             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
164             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
165             ARBITRARY_TIME, ARBITRARY_TIME,
166             /*pointerCount*/ 1, pointerProperties, pointerCoords);
167     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
168             &event, DISPLAY_ID,
169             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
170             << "Should reject motion events with pointer down index too large.";
171 
172     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
173             AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
174             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
175             ARBITRARY_TIME, ARBITRARY_TIME,
176             /*pointerCount*/ 1, pointerProperties, pointerCoords);
177     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
178             &event, DISPLAY_ID,
179             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
180             << "Should reject motion events with pointer down index too small.";
181 
182     // Rejects pointer up with invalid index.
183     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
184             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
185             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
186             ARBITRARY_TIME, ARBITRARY_TIME,
187             /*pointerCount*/ 1, pointerProperties, pointerCoords);
188     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
189             &event, DISPLAY_ID,
190             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
191             << "Should reject motion events with pointer up index too large.";
192 
193     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
194             AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
195             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
196             ARBITRARY_TIME, ARBITRARY_TIME,
197             /*pointerCount*/ 1, pointerProperties, pointerCoords);
198     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
199             &event, DISPLAY_ID,
200             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
201             << "Should reject motion events with pointer up index too small.";
202 
203     // Rejects motion events with invalid number of pointers.
204     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
205             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
206             ARBITRARY_TIME, ARBITRARY_TIME,
207             /*pointerCount*/ 0, pointerProperties, pointerCoords);
208     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
209             &event, DISPLAY_ID,
210             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
211             << "Should reject motion events with 0 pointers.";
212 
213     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
214             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
215             ARBITRARY_TIME, ARBITRARY_TIME,
216             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
217     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
218             &event, DISPLAY_ID,
219             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
220             << "Should reject motion events with more than MAX_POINTERS pointers.";
221 
222     // Rejects motion events with invalid pointer ids.
223     pointerProperties[0].id = -1;
224     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
225             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
226             ARBITRARY_TIME, ARBITRARY_TIME,
227             /*pointerCount*/ 1, pointerProperties, pointerCoords);
228     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
229             &event, DISPLAY_ID,
230             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
231             << "Should reject motion events with pointer ids less than 0.";
232 
233     pointerProperties[0].id = MAX_POINTER_ID + 1;
234     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
235             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
236             ARBITRARY_TIME, ARBITRARY_TIME,
237             /*pointerCount*/ 1, pointerProperties, pointerCoords);
238     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
239             &event, DISPLAY_ID,
240             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
241             << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
242 
243     // Rejects motion events with duplicate pointer ids.
244     pointerProperties[0].id = 1;
245     pointerProperties[1].id = 1;
246     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
247             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
248             ARBITRARY_TIME, ARBITRARY_TIME,
249             /*pointerCount*/ 2, pointerProperties, pointerCoords);
250     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
251             &event, DISPLAY_ID,
252             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
253             << "Should reject motion events with duplicate pointer ids.";
254 }
255 
256 } // namespace android
257