OSDN Git Service

am 5dc18299: Merge "LE low power scan feature"
[android-x86/hardware-libhardware.git] / tests / input / evdev / InputHub_test.cpp
1 /*
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"
33 #include "TestHelpers.h"
34
35 // # of milliseconds to fudge stopwatch measurements
36 #define TIMING_TOLERANCE_MS 25
37 #define NO_TIMEOUT (-1)
38
39 namespace android {
40 namespace tests {
41
42 using namespace std::literals::chrono_literals;
43
44 using InputCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t)>;
45 using DeviceCbFunc = std::function<void(std::shared_ptr<InputDeviceNode>)>;
46
47 static const InputCbFunc kNoopInputCb = [](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t){};
48 static const DeviceCbFunc kNoopDeviceCb = [](std::shared_ptr<InputDeviceNode>){};
49
50 class TestInputCallback : public InputCallbackInterface {
51 public:
52     TestInputCallback() :
53         mInputCb(kNoopInputCb), mDeviceAddedCb(kNoopDeviceCb), mDeviceRemovedCb(kNoopDeviceCb) {}
54     virtual ~TestInputCallback() = default;
55
56     void setInputCallback(InputCbFunc cb) { mInputCb = cb; }
57     void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
58     void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
59
60     virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
61             nsecs_t event_time) override {
62         mInputCb(node, event, event_time);
63     }
64     virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) override {
65         mDeviceAddedCb(node);
66     }
67     virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) override {
68         mDeviceRemovedCb(node);
69     }
70
71 private:
72     InputCbFunc mInputCb;
73     DeviceCbFunc mDeviceAddedCb;
74     DeviceCbFunc mDeviceRemovedCb;
75 };
76
77 class InputHubTest : public ::testing::Test {
78  protected:
79      virtual void SetUp() {
80          mCallback = std::make_shared<TestInputCallback>();
81          mInputHub = std::make_shared<InputHub>(mCallback);
82      }
83
84      std::shared_ptr<TestInputCallback> mCallback;
85      std::shared_ptr<InputHub> mInputHub;
86 };
87
88 TEST_F(InputHubTest, testWake) {
89     // Call wake() after 100ms.
90     auto f = delay_async(100ms, [&]() { EXPECT_EQ(OK, mInputHub->wake()); });
91
92     StopWatch stopWatch("poll");
93     EXPECT_EQ(OK, mInputHub->poll());
94     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
95
96     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
97 }
98
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();
106             });
107
108     ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
109
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,
114             [&]() {
115                 std::lock_guard<std::mutex> lock(tempFileMutex);
116                 tempFile.reset(tempDir->newTempFile());
117             });
118
119     StopWatch stopWatch("poll");
120     EXPECT_EQ(OK, mInputHub->poll());
121     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
122
123
124     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
125     std::lock_guard<std::mutex> lock(tempFileMutex);
126     EXPECT_EQ(tempFile->getName(), pathname);
127 }
128
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());
135
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) {
140                 tempNode = node;
141             });
142     mCallback->setDeviceRemovedCallback(
143             [&](std::shared_ptr<InputDeviceNode> node) {
144                 EXPECT_EQ(tempNode, node);
145             });
146
147     ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
148     // Ensure that tempDir was scanned to find the device.
149     ASSERT_TRUE(tempNode != nullptr);
150
151     auto f = delay_async(100ms, [&]() { deviceFile.reset(); });
152
153     StopWatch stopWatch("poll");
154     EXPECT_EQ(OK, mInputHub->poll());
155     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
156
157     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
158 }
159
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());
166
167     // Send a key event corresponding to HOME.
168     struct input_event iev;
169     iev.time = { 1, 0 };
170     iev.type = EV_KEY;
171     iev.code = KEY_HOME;
172     iev.value = 0x01;
173
174     auto inputDelayMs = 100ms;
175     auto f = delay_async(inputDelayMs, [&] {
176                 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile->getFd(), &iev, sizeof(iev)));
177
178                 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
179                     << deviceFile->getFd() << ". errno: " << errno;
180             });
181
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);
192             });
193     ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
194
195     StopWatch stopWatch("poll");
196     EXPECT_EQ(OK, mInputHub->poll());
197     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
198
199     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
200 }
201
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());
208
209     bool inputCallbackFinished = false, deviceCallbackFinished = false;
210
211     // Setup the callback for input events. Should run before the device
212     // callback.
213     mCallback->setInputCallback(
214             [&](std::shared_ptr<InputDeviceNode>, InputEvent&, nsecs_t) {
215                 ASSERT_FALSE(deviceCallbackFinished);
216                 inputCallbackFinished = true;
217             });
218
219     // Setup the callback for device removal. Should run after the input
220     // callback.
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;
228             });
229     ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
230
231     auto f = delay_async(100ms,
232             [&]() {
233                 // Delete the second device file first.
234                 deviceFile2.reset();
235
236                 // Then inject an input event into the first device.
237                 struct input_event iev;
238                 iev.time = { 1, 0 };
239                 iev.type = EV_KEY;
240                 iev.code = KEY_HOME;
241                 iev.value = 0x01;
242
243                 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile1->getFd(), &iev, sizeof(iev)));
244
245                 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
246                     << deviceFile1->getFd() << ". errno: " << errno;
247             });
248
249     StopWatch stopWatch("poll");
250     EXPECT_EQ(OK, mInputHub->poll());
251     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
252
253     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
254     EXPECT_TRUE(inputCallbackFinished);
255     EXPECT_TRUE(deviceCallbackFinished);
256 }
257
258 }  // namespace tests
259 }  // namespace android