2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "InputHub_test"
18 //#define LOG_NDEBUG 0
20 #include <linux/input.h>
26 #include <gtest/gtest.h>
28 #include <utils/Log.h>
29 #include <utils/StopWatch.h>
30 #include <utils/Timers.h>
33 #include "TestHelpers.h"
35 // # of milliseconds to fudge stopwatch measurements
36 #define TIMING_TOLERANCE_MS 25
37 #define NO_TIMEOUT (-1)
42 using namespace std::literals::chrono_literals;
44 using InputCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t)>;
45 using DeviceCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>)>;
47 static const InputCbFunc kNoopInputCb = [](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t){};
48 static const DeviceCbFunc kNoopDeviceCb = [](std::shared_ptr<InputDeviceNode>){};
50 class TestInputCallback : public InputCallbackInterface {
53 mInputCb(kNoopInputCb), mDeviceAddedCb(kNoopDeviceCb), mDeviceRemovedCb(kNoopDeviceCb) {}
54 virtual ~TestInputCallback() = default;
56 void setInputCallback(InputCbFunc cb) { mInputCb = cb; }
57 void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
58 void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
60 virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
61 nsecs_t event_time) override {
62 mInputCb(node, event, event_time);
64 virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) override {
67 virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) override {
68 mDeviceRemovedCb(node);
73 DeviceCbFunc mDeviceAddedCb;
74 DeviceCbFunc mDeviceRemovedCb;
77 class InputHubTest : public ::testing::Test {
79 virtual void SetUp() {
80 mCallback = std::make_shared<TestInputCallback>();
81 mInputHub = std::make_shared<InputHub>(mCallback);
84 std::shared_ptr<TestInputCallback> mCallback;
85 std::shared_ptr<InputHub> mInputHub;
88 TEST_F(InputHubTest, testWake) {
89 // Call wake() after 100ms.
90 auto f = delay_async(100ms, [&]() { EXPECT_EQ(OK, mInputHub->wake()); });
92 StopWatch stopWatch("poll");
93 EXPECT_EQ(OK, mInputHub->poll());
94 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
96 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
99 TEST_F(InputHubTest, DISABLED_testDeviceAdded) {
100 auto tempDir = std::make_shared<TempDir>();
101 std::string pathname;
102 // Expect that this callback will run and set handle and pathname.
103 mCallback->setDeviceAddedCallback(
104 [&](std::shared_ptr<InputDeviceNode> node) {
105 pathname = node->getPath();
108 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
110 // Create a new file in tempDir after 100ms.
111 std::unique_ptr<TempFile> tempFile;
112 std::mutex tempFileMutex;
113 auto f = delay_async(100ms,
115 std::lock_guard<std::mutex> lock(tempFileMutex);
116 tempFile.reset(tempDir->newTempFile());
119 StopWatch stopWatch("poll");
120 EXPECT_EQ(OK, mInputHub->poll());
121 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
124 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
125 std::lock_guard<std::mutex> lock(tempFileMutex);
126 EXPECT_EQ(tempFile->getName(), pathname);
129 TEST_F(InputHubTest, DISABLED_testDeviceRemoved) {
130 // Create a temp dir and file. Save its name and handle (to be filled in
131 // once InputHub scans the dir).
132 auto tempDir = std::make_unique<TempDir>();
133 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
134 std::string tempFileName(deviceFile->getName());
136 std::shared_ptr<InputDeviceNode> tempNode;
137 // Expect that these callbacks will run for the above device file.
138 mCallback->setDeviceAddedCallback(
139 [&](std::shared_ptr<InputDeviceNode> node) {
142 mCallback->setDeviceRemovedCallback(
143 [&](std::shared_ptr<InputDeviceNode> node) {
144 EXPECT_EQ(tempNode, node);
147 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
148 // Ensure that tempDir was scanned to find the device.
149 ASSERT_TRUE(tempNode != nullptr);
151 auto f = delay_async(100ms, [&]() { deviceFile.reset(); });
153 StopWatch stopWatch("poll");
154 EXPECT_EQ(OK, mInputHub->poll());
155 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
157 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
160 TEST_F(InputHubTest, DISABLED_testInputEvent) {
161 // Create a temp dir and file. Save its name and handle (to be filled in
162 // once InputHub scans the dir.)
163 auto tempDir = std::make_unique<TempDir>();
164 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
165 std::string tempFileName(deviceFile->getName());
167 // Send a key event corresponding to HOME.
168 struct input_event iev;
174 auto inputDelayMs = 100ms;
175 auto f = delay_async(inputDelayMs, [&] {
176 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile->getFd(), &iev, sizeof(iev)));
178 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
179 << deviceFile->getFd() << ". errno: " << errno;
182 // Expect this callback to run when the input event is read.
183 nsecs_t expectedWhen = systemTime(CLOCK_MONOTONIC) + ms2ns(inputDelayMs.count());
184 mCallback->setInputCallback(
185 [&](std::shared_ptr<InputDeviceNode> node, InputEvent& event, nsecs_t event_time) {
186 EXPECT_NEAR(expectedWhen, event_time, ms2ns(TIMING_TOLERANCE_MS));
187 EXPECT_EQ(s2ns(1), event.when);
188 EXPECT_EQ(tempFileName, node->getPath());
189 EXPECT_EQ(EV_KEY, event.type);
190 EXPECT_EQ(KEY_HOME, event.code);
191 EXPECT_EQ(0x01, event.value);
193 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
195 StopWatch stopWatch("poll");
196 EXPECT_EQ(OK, mInputHub->poll());
197 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
199 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
202 TEST_F(InputHubTest, DISABLED_testCallbackOrder) {
203 // Create two "devices": one to receive input and the other to go away.
204 auto tempDir = std::make_unique<TempDir>();
205 auto deviceFile1 = std::unique_ptr<TempFile>(tempDir->newTempFile());
206 auto deviceFile2 = std::unique_ptr<TempFile>(tempDir->newTempFile());
207 std::string tempFileName(deviceFile2->getName());
209 bool inputCallbackFinished = false, deviceCallbackFinished = false;
211 // Setup the callback for input events. Should run before the device
213 mCallback->setInputCallback(
214 [&](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t) {
215 ASSERT_FALSE(deviceCallbackFinished);
216 inputCallbackFinished = true;
219 // Setup the callback for device removal. Should run after the input
221 mCallback->setDeviceRemovedCallback(
222 [&](std::shared_ptr<InputDeviceNode> node) {
223 ASSERT_TRUE(inputCallbackFinished)
224 << "input callback did not run before device changed callback";
225 // Make sure the correct device was removed.
226 EXPECT_EQ(tempFileName, node->getPath());
227 deviceCallbackFinished = true;
229 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
231 auto f = delay_async(100ms,
233 // Delete the second device file first.
236 // Then inject an input event into the first device.
237 struct input_event iev;
243 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile1->getFd(), &iev, sizeof(iev)));
245 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
246 << deviceFile1->getFd() << ". errno: " << errno;
249 StopWatch stopWatch("poll");
250 EXPECT_EQ(OK, mInputHub->poll());
251 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
253 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
254 EXPECT_TRUE(inputCallbackFinished);
255 EXPECT_TRUE(deviceCallbackFinished);
259 } // namespace android