blob: 5864a95fa3e9b5f8fe9f7dd644e5c03a72daaafb [file] [log] [blame]
Tim Kilbourn73475a42015-02-13 10:35:20 -08001/*
2 * Copyright (C) 2015 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#define LOG_TAG "InputHub_test"
18//#define LOG_NDEBUG 0
19
20#include <linux/input.h>
21
22#include <chrono>
23#include <memory>
24#include <mutex>
25
26#include <gtest/gtest.h>
27
28#include <utils/Log.h>
29#include <utils/StopWatch.h>
30#include <utils/Timers.h>
31
32#include "InputHub.h"
Tim Kilbourn3186e7b2015-04-16 15:32:08 -070033#include "InputHub-internal.h"
Tim Kilbourn73475a42015-02-13 10:35:20 -080034#include "TestHelpers.h"
35
36// # of milliseconds to fudge stopwatch measurements
37#define TIMING_TOLERANCE_MS 25
38#define NO_TIMEOUT (-1)
39
40namespace android {
41namespace tests {
42
43using namespace std::literals::chrono_literals;
44
Tim Kilbournc929d252015-04-29 13:50:17 -070045using InputCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t)>;
46using DeviceCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&)>;
Tim Kilbourn73475a42015-02-13 10:35:20 -080047
Tim Kilbournc929d252015-04-29 13:50:17 -070048static const InputCbFunc kNoopInputCb = [](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t){};
49static const DeviceCbFunc kNoopDeviceCb = [](const std::shared_ptr<InputDeviceNode>&){};
Tim Kilbourn73475a42015-02-13 10:35:20 -080050
51class TestInputCallback : public InputCallbackInterface {
52public:
53 TestInputCallback() :
54 mInputCb(kNoopInputCb), mDeviceAddedCb(kNoopDeviceCb), mDeviceRemovedCb(kNoopDeviceCb) {}
55 virtual ~TestInputCallback() = default;
56
57 void setInputCallback(InputCbFunc cb) { mInputCb = cb; }
58 void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
59 void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
60
Tim Kilbournc929d252015-04-29 13:50:17 -070061 virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
Tim Kilbourn73475a42015-02-13 10:35:20 -080062 nsecs_t event_time) override {
63 mInputCb(node, event, event_time);
64 }
Tim Kilbournc929d252015-04-29 13:50:17 -070065 virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) override {
Tim Kilbourn73475a42015-02-13 10:35:20 -080066 mDeviceAddedCb(node);
67 }
Tim Kilbournc929d252015-04-29 13:50:17 -070068 virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override {
Tim Kilbourn73475a42015-02-13 10:35:20 -080069 mDeviceRemovedCb(node);
70 }
71
72private:
73 InputCbFunc mInputCb;
74 DeviceCbFunc mDeviceAddedCb;
75 DeviceCbFunc mDeviceRemovedCb;
76};
77
78class InputHubTest : public ::testing::Test {
79 protected:
80 virtual void SetUp() {
81 mCallback = std::make_shared<TestInputCallback>();
82 mInputHub = std::make_shared<InputHub>(mCallback);
83 }
84
85 std::shared_ptr<TestInputCallback> mCallback;
86 std::shared_ptr<InputHub> mInputHub;
87};
88
89TEST_F(InputHubTest, testWake) {
90 // Call wake() after 100ms.
91 auto f = delay_async(100ms, [&]() { EXPECT_EQ(OK, mInputHub->wake()); });
92
93 StopWatch stopWatch("poll");
94 EXPECT_EQ(OK, mInputHub->poll());
95 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
96
97 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
98}
99
100TEST_F(InputHubTest, DISABLED_testDeviceAdded) {
101 auto tempDir = std::make_shared<TempDir>();
102 std::string pathname;
103 // Expect that this callback will run and set handle and pathname.
104 mCallback->setDeviceAddedCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700105 [&](const std::shared_ptr<InputDeviceNode>& node) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800106 pathname = node->getPath();
107 });
108
109 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
110
111 // Create a new file in tempDir after 100ms.
112 std::unique_ptr<TempFile> tempFile;
113 std::mutex tempFileMutex;
114 auto f = delay_async(100ms,
115 [&]() {
116 std::lock_guard<std::mutex> lock(tempFileMutex);
117 tempFile.reset(tempDir->newTempFile());
118 });
119
120 StopWatch stopWatch("poll");
121 EXPECT_EQ(OK, mInputHub->poll());
122 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
123
124
125 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
126 std::lock_guard<std::mutex> lock(tempFileMutex);
127 EXPECT_EQ(tempFile->getName(), pathname);
128}
129
130TEST_F(InputHubTest, DISABLED_testDeviceRemoved) {
131 // Create a temp dir and file. Save its name and handle (to be filled in
132 // once InputHub scans the dir).
133 auto tempDir = std::make_unique<TempDir>();
134 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
135 std::string tempFileName(deviceFile->getName());
136
137 std::shared_ptr<InputDeviceNode> tempNode;
138 // Expect that these callbacks will run for the above device file.
139 mCallback->setDeviceAddedCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700140 [&](const std::shared_ptr<InputDeviceNode>& node) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800141 tempNode = node;
142 });
143 mCallback->setDeviceRemovedCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700144 [&](const std::shared_ptr<InputDeviceNode>& node) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800145 EXPECT_EQ(tempNode, node);
146 });
147
148 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
149 // Ensure that tempDir was scanned to find the device.
150 ASSERT_TRUE(tempNode != nullptr);
151
152 auto f = delay_async(100ms, [&]() { deviceFile.reset(); });
153
154 StopWatch stopWatch("poll");
155 EXPECT_EQ(OK, mInputHub->poll());
156 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
157
158 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
159}
160
161TEST_F(InputHubTest, DISABLED_testInputEvent) {
162 // Create a temp dir and file. Save its name and handle (to be filled in
163 // once InputHub scans the dir.)
164 auto tempDir = std::make_unique<TempDir>();
165 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
166 std::string tempFileName(deviceFile->getName());
167
168 // Send a key event corresponding to HOME.
169 struct input_event iev;
170 iev.time = { 1, 0 };
171 iev.type = EV_KEY;
172 iev.code = KEY_HOME;
173 iev.value = 0x01;
174
175 auto inputDelayMs = 100ms;
176 auto f = delay_async(inputDelayMs, [&] {
177 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile->getFd(), &iev, sizeof(iev)));
178
179 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
180 << deviceFile->getFd() << ". errno: " << errno;
181 });
182
183 // Expect this callback to run when the input event is read.
184 nsecs_t expectedWhen = systemTime(CLOCK_MONOTONIC) + ms2ns(inputDelayMs.count());
185 mCallback->setInputCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700186 [&](const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
187 nsecs_t event_time) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800188 EXPECT_NEAR(expectedWhen, event_time, ms2ns(TIMING_TOLERANCE_MS));
189 EXPECT_EQ(s2ns(1), event.when);
190 EXPECT_EQ(tempFileName, node->getPath());
191 EXPECT_EQ(EV_KEY, event.type);
192 EXPECT_EQ(KEY_HOME, event.code);
193 EXPECT_EQ(0x01, event.value);
194 });
195 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
196
197 StopWatch stopWatch("poll");
198 EXPECT_EQ(OK, mInputHub->poll());
199 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
200
201 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
202}
203
204TEST_F(InputHubTest, DISABLED_testCallbackOrder) {
205 // Create two "devices": one to receive input and the other to go away.
206 auto tempDir = std::make_unique<TempDir>();
207 auto deviceFile1 = std::unique_ptr<TempFile>(tempDir->newTempFile());
208 auto deviceFile2 = std::unique_ptr<TempFile>(tempDir->newTempFile());
209 std::string tempFileName(deviceFile2->getName());
210
211 bool inputCallbackFinished = false, deviceCallbackFinished = false;
212
213 // Setup the callback for input events. Should run before the device
214 // callback.
215 mCallback->setInputCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700216 [&](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800217 ASSERT_FALSE(deviceCallbackFinished);
218 inputCallbackFinished = true;
219 });
220
221 // Setup the callback for device removal. Should run after the input
222 // callback.
223 mCallback->setDeviceRemovedCallback(
Tim Kilbournc929d252015-04-29 13:50:17 -0700224 [&](const std::shared_ptr<InputDeviceNode>& node) {
Tim Kilbourn73475a42015-02-13 10:35:20 -0800225 ASSERT_TRUE(inputCallbackFinished)
226 << "input callback did not run before device changed callback";
227 // Make sure the correct device was removed.
228 EXPECT_EQ(tempFileName, node->getPath());
229 deviceCallbackFinished = true;
230 });
231 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
232
233 auto f = delay_async(100ms,
234 [&]() {
235 // Delete the second device file first.
236 deviceFile2.reset();
237
238 // Then inject an input event into the first device.
239 struct input_event iev;
240 iev.time = { 1, 0 };
241 iev.type = EV_KEY;
242 iev.code = KEY_HOME;
243 iev.value = 0x01;
244
245 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile1->getFd(), &iev, sizeof(iev)));
246
247 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
248 << deviceFile1->getFd() << ". errno: " << errno;
249 });
250
251 StopWatch stopWatch("poll");
252 EXPECT_EQ(OK, mInputHub->poll());
253 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
254
255 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
256 EXPECT_TRUE(inputCallbackFinished);
257 EXPECT_TRUE(deviceCallbackFinished);
258}
259
Tim Kilbourn3186e7b2015-04-16 15:32:08 -0700260using internal::testBitInRange;
261
262TEST(BitInRange, testInvalidRange) {
263 uint8_t arr[2] = { 0xff, 0xff };
264 EXPECT_FALSE(testBitInRange(arr, 0, 0));
265 EXPECT_FALSE(testBitInRange(arr, 1, 0));
266}
267
268TEST(BitInRange, testNoBits) {
269 uint8_t arr[1];
270 arr[0] = 0;
271 EXPECT_FALSE(testBitInRange(arr, 0, 8));
272}
273
274TEST(BitInRange, testOneBit) {
275 uint8_t arr[1];
276 for (int i = 0; i < 8; ++i) {
277 arr[0] = 1 << i;
278 EXPECT_TRUE(testBitInRange(arr, 0, 8));
279 }
280}
281
282TEST(BitInRange, testZeroStart) {
283 uint8_t arr[1] = { 0x10 };
284 for (int i = 0; i < 5; ++i) {
285 EXPECT_FALSE(testBitInRange(arr, 0, i));
286 }
287 for (int i = 5; i <= 8; ++i) {
288 EXPECT_TRUE(testBitInRange(arr, 0, i));
289 }
290}
291
292TEST(BitInRange, testByteBoundaryEnd) {
293 uint8_t arr[1] = { 0x10 };
294 for (int i = 0; i < 5; ++i) {
295 EXPECT_TRUE(testBitInRange(arr, i, 8));
296 }
297 for (int i = 5; i <= 8; ++i) {
298 EXPECT_FALSE(testBitInRange(arr, i, 8));
299 }
300}
301
302TEST(BitInRange, testMultiByteArray) {
303 // bits set: 11 and 16
304 uint8_t arr[3] = { 0x00, 0x08, 0x01 };
305 for (int start = 0; start < 24; ++start) {
306 for (int end = start + 1; end <= 24; ++end) {
307 if (start > 16 || end <= 11 || (start > 11 && end <= 16)) {
308 EXPECT_FALSE(testBitInRange(arr, start, end))
309 << "range = (" << start << ", " << end << ")";
310 } else {
311 EXPECT_TRUE(testBitInRange(arr, start, end))
312 << "range = (" << start << ", " << end << ")";
313 }
314 }
315 }
316}
317
Tim Kilbourn73475a42015-02-13 10:35:20 -0800318} // namespace tests
319} // namespace android