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 injector pid / uid pair that has permission to inject events.
31static const int32_t INJECTOR_PID = 999;
32static const int32_t INJECTOR_UID = 1001;
33
34
35// --- FakeInputDispatcherPolicy ---
36
37class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
38    InputDispatcherConfiguration mConfig;
39
40protected:
41    virtual ~FakeInputDispatcherPolicy() {
42    }
43
44public:
45    FakeInputDispatcherPolicy() {
46    }
47
48private:
49    virtual void notifyConfigurationChanged(nsecs_t when) {
50    }
51
52    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
53            const sp<InputWindowHandle>& inputWindowHandle,
54            const String8& reason) {
55        return 0;
56    }
57
58    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
59    }
60
61    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
62        *outConfig = mConfig;
63    }
64
65    virtual bool isKeyRepeatEnabled() {
66        return true;
67    }
68
69    virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
70        return true;
71    }
72
73    virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
74    }
75
76    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
77    }
78
79    virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
80            const KeyEvent* keyEvent, uint32_t policyFlags) {
81        return 0;
82    }
83
84    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
85            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
86        return false;
87    }
88
89    virtual void notifySwitch(nsecs_t when,
90            uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) {
91    }
92
93    virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
94    }
95
96    virtual bool checkInjectEventsPermissionNonReentrant(
97            int32_t injectorPid, int32_t injectorUid) {
98        return false;
99    }
100};
101
102
103// --- InputDispatcherTest ---
104
105class InputDispatcherTest : public testing::Test {
106protected:
107    sp<FakeInputDispatcherPolicy> mFakePolicy;
108    sp<InputDispatcher> mDispatcher;
109
110    virtual void SetUp() {
111        mFakePolicy = new FakeInputDispatcherPolicy();
112        mDispatcher = new InputDispatcher(mFakePolicy);
113    }
114
115    virtual void TearDown() {
116        mFakePolicy.clear();
117        mDispatcher.clear();
118    }
119};
120
121
122TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
123    KeyEvent event;
124
125    // Rejects undefined key actions.
126    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
127            /*action*/ -1, 0,
128            AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
129    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
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(&event,
138            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
139            << "Should reject key events with ACTION_MULTIPLE.";
140}
141
142TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
143    MotionEvent event;
144    PointerProperties pointerProperties[MAX_POINTERS + 1];
145    PointerCoords pointerCoords[MAX_POINTERS + 1];
146    for (int i = 0; i <= MAX_POINTERS; i++) {
147        pointerProperties[i].clear();
148        pointerProperties[i].id = i;
149        pointerCoords[i].clear();
150    }
151
152    // Rejects undefined motion actions.
153    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
154            /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
155            ARBITRARY_TIME, ARBITRARY_TIME,
156            /*pointerCount*/ 1, pointerProperties, pointerCoords);
157    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
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, 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(&event,
168            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
169            << "Should reject motion events with pointer down index too large.";
170
171    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
172            AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
173            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
174            ARBITRARY_TIME, ARBITRARY_TIME,
175            /*pointerCount*/ 1, pointerProperties, pointerCoords);
176    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
177            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
178            << "Should reject motion events with pointer down index too small.";
179
180    // Rejects pointer up with invalid index.
181    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
182            AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
183            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
184            ARBITRARY_TIME, ARBITRARY_TIME,
185            /*pointerCount*/ 1, pointerProperties, pointerCoords);
186    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
187            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
188            << "Should reject motion events with pointer up index too large.";
189
190    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
191            AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
192            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
193            ARBITRARY_TIME, ARBITRARY_TIME,
194            /*pointerCount*/ 1, pointerProperties, pointerCoords);
195    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
196            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
197            << "Should reject motion events with pointer up index too small.";
198
199    // Rejects motion events with invalid number of pointers.
200    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
201            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
202            ARBITRARY_TIME, ARBITRARY_TIME,
203            /*pointerCount*/ 0, pointerProperties, pointerCoords);
204    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
205            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
206            << "Should reject motion events with 0 pointers.";
207
208    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
209            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
210            ARBITRARY_TIME, ARBITRARY_TIME,
211            /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
212    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
213            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
214            << "Should reject motion events with more than MAX_POINTERS pointers.";
215
216    // Rejects motion events with invalid pointer ids.
217    pointerProperties[0].id = -1;
218    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
219            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
220            ARBITRARY_TIME, ARBITRARY_TIME,
221            /*pointerCount*/ 1, pointerProperties, pointerCoords);
222    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
223            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
224            << "Should reject motion events with pointer ids less than 0.";
225
226    pointerProperties[0].id = MAX_POINTER_ID + 1;
227    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
228            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
229            ARBITRARY_TIME, ARBITRARY_TIME,
230            /*pointerCount*/ 1, pointerProperties, pointerCoords);
231    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
232            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
233            << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
234
235    // Rejects motion events with duplicate pointer ids.
236    pointerProperties[0].id = 1;
237    pointerProperties[1].id = 1;
238    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
239            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
240            ARBITRARY_TIME, ARBITRARY_TIME,
241            /*pointerCount*/ 2, pointerProperties, pointerCoords);
242    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
243            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
244            << "Should reject motion events with duplicate pointer ids.";
245}
246
247} // namespace android
248