Siarhei Vishniakou | 8588cc9 | 2018-12-12 18:17:58 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2019 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 "EventHub.h" |
| 18 | |
| 19 | #include <android-base/stringprintf.h> |
| 20 | #include <gtest/gtest.h> |
| 21 | #include <inttypes.h> |
| 22 | #include <linux/uinput.h> |
| 23 | #include <log/log.h> |
| 24 | #include <chrono> |
| 25 | |
| 26 | #define TAG "EventHub_test" |
| 27 | |
| 28 | using android::EventHub; |
| 29 | using android::EventHubInterface; |
| 30 | using android::InputDeviceIdentifier; |
| 31 | using android::RawEvent; |
| 32 | using android::sp; |
| 33 | using android::base::StringPrintf; |
| 34 | using std::chrono_literals::operator""ms; |
| 35 | |
| 36 | static constexpr bool DEBUG = false; |
| 37 | static const char* DEVICE_NAME = "EventHub Test Device"; |
| 38 | |
| 39 | static void dumpEvents(const std::vector<RawEvent>& events) { |
| 40 | for (const RawEvent& event : events) { |
| 41 | if (event.type >= EventHubInterface::FIRST_SYNTHETIC_EVENT) { |
| 42 | switch (event.type) { |
| 43 | case EventHubInterface::DEVICE_ADDED: |
| 44 | ALOGI("Device added: %i", event.deviceId); |
| 45 | break; |
| 46 | case EventHubInterface::DEVICE_REMOVED: |
| 47 | ALOGI("Device removed: %i", event.deviceId); |
| 48 | break; |
| 49 | case EventHubInterface::FINISHED_DEVICE_SCAN: |
| 50 | ALOGI("Finished device scan."); |
| 51 | break; |
| 52 | } |
| 53 | } else { |
| 54 | ALOGI("Device %" PRId32 " : time = %" PRId64 ", type %i, code %i, value %i", |
| 55 | event.deviceId, event.when, event.type, event.code, event.value); |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | // --- EventHubTest --- |
| 61 | class EventHubTest : public testing::Test { |
| 62 | protected: |
| 63 | std::unique_ptr<EventHubInterface> mEventHub; |
| 64 | // We are only going to emulate a single input device currently. |
| 65 | android::base::unique_fd mDeviceFd; |
| 66 | int32_t mDeviceId; |
| 67 | virtual void SetUp() override { |
| 68 | mEventHub = std::make_unique<EventHub>(); |
| 69 | consumeInitialDeviceAddedEvents(); |
| 70 | createDevice(); |
| 71 | mDeviceId = waitForDeviceCreation(); |
| 72 | } |
| 73 | virtual void TearDown() override { |
| 74 | mDeviceFd.reset(); |
| 75 | waitForDeviceClose(mDeviceId); |
| 76 | } |
| 77 | |
| 78 | void createDevice(); |
| 79 | /** |
| 80 | * Return the device id of the created device. |
| 81 | */ |
| 82 | int32_t waitForDeviceCreation(); |
| 83 | void waitForDeviceClose(int32_t deviceId); |
| 84 | void consumeInitialDeviceAddedEvents(); |
| 85 | void sendEvent(uint16_t type, uint16_t code, int32_t value); |
| 86 | std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms); |
| 87 | }; |
| 88 | |
| 89 | std::vector<RawEvent> EventHubTest::getEvents(std::chrono::milliseconds timeout) { |
| 90 | static constexpr size_t EVENT_BUFFER_SIZE = 256; |
| 91 | std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer; |
| 92 | std::vector<RawEvent> events; |
| 93 | |
| 94 | while (true) { |
| 95 | size_t count = |
| 96 | mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size()); |
| 97 | if (count == 0) { |
| 98 | break; |
| 99 | } |
| 100 | events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count); |
| 101 | } |
| 102 | if (DEBUG) { |
| 103 | dumpEvents(events); |
| 104 | } |
| 105 | return events; |
| 106 | } |
| 107 | |
| 108 | void EventHubTest::createDevice() { |
| 109 | mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK)); |
| 110 | if (mDeviceFd < 0) { |
| 111 | FAIL() << "Can't open /dev/uinput :" << strerror(errno); |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * Signal which type of events this input device supports. |
| 116 | * We will emulate a keyboard here. |
| 117 | */ |
| 118 | // enable key press/release event |
| 119 | if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) { |
| 120 | ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno); |
| 121 | } |
| 122 | |
| 123 | // enable set of KEY events |
| 124 | if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) { |
| 125 | ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno); |
| 126 | } |
| 127 | |
| 128 | // enable synchronization event |
| 129 | if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) { |
| 130 | ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno); |
| 131 | } |
| 132 | |
| 133 | struct uinput_user_dev keyboard = {}; |
| 134 | strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE); |
| 135 | keyboard.id.bustype = BUS_USB; |
| 136 | keyboard.id.vendor = 0x01; |
| 137 | keyboard.id.product = 0x01; |
| 138 | keyboard.id.version = 1; |
| 139 | |
| 140 | if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) { |
| 141 | FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: " |
| 142 | << strerror(errno); |
| 143 | } |
| 144 | |
| 145 | if (ioctl(mDeviceFd, UI_DEV_CREATE)) { |
| 146 | FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Since the test runs on a real platform, there will be existing devices |
| 152 | * in addition to the test devices being added. Therefore, when EventHub is first created, |
| 153 | * it will return a lot of "device added" type of events. |
| 154 | */ |
| 155 | void EventHubTest::consumeInitialDeviceAddedEvents() { |
| 156 | std::vector<RawEvent> events = getEvents(0ms); |
| 157 | std::set<int32_t /*deviceId*/> existingDevices; |
| 158 | // All of the events should be DEVICE_ADDED type, except the last one. |
| 159 | for (size_t i = 0; i < events.size() - 1; i++) { |
| 160 | const RawEvent& event = events[i]; |
| 161 | EXPECT_EQ(EventHubInterface::DEVICE_ADDED, event.type); |
| 162 | existingDevices.insert(event.deviceId); |
| 163 | } |
| 164 | // None of the existing system devices should be changing while this test is run. |
| 165 | // Check that the returned device ids are unique for all of the existing devices. |
| 166 | EXPECT_EQ(existingDevices.size(), events.size() - 1); |
| 167 | // The last event should be "finished device scan" |
| 168 | EXPECT_EQ(EventHubInterface::FINISHED_DEVICE_SCAN, events[events.size() - 1].type); |
| 169 | } |
| 170 | |
| 171 | int32_t EventHubTest::waitForDeviceCreation() { |
| 172 | // Wait a little longer than usual, to ensure input device has time to be created |
| 173 | std::vector<RawEvent> events = getEvents(20ms); |
| 174 | EXPECT_EQ(2U, events.size()); // Using "expect" because the function is non-void. |
| 175 | const RawEvent& deviceAddedEvent = events[0]; |
| 176 | EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type); |
| 177 | InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId); |
| 178 | const int32_t deviceId = deviceAddedEvent.deviceId; |
| 179 | EXPECT_EQ(identifier.name, DEVICE_NAME); |
| 180 | const RawEvent& finishedDeviceScanEvent = events[1]; |
| 181 | EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN), |
| 182 | finishedDeviceScanEvent.type); |
| 183 | return deviceId; |
| 184 | } |
| 185 | |
| 186 | void EventHubTest::waitForDeviceClose(int32_t deviceId) { |
| 187 | std::vector<RawEvent> events = getEvents(20ms); |
| 188 | ASSERT_EQ(2U, events.size()); |
| 189 | const RawEvent& deviceRemovedEvent = events[0]; |
| 190 | EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_REMOVED), deviceRemovedEvent.type); |
| 191 | EXPECT_EQ(deviceId, deviceRemovedEvent.deviceId); |
| 192 | const RawEvent& finishedDeviceScanEvent = events[1]; |
| 193 | EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN), |
| 194 | finishedDeviceScanEvent.type); |
| 195 | } |
| 196 | |
| 197 | void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) { |
| 198 | struct input_event event = {}; |
| 199 | event.type = type; |
| 200 | event.code = code; |
| 201 | event.value = value; |
| 202 | event.time = {}; // uinput ignores the timestamp |
| 203 | |
| 204 | if (write(mDeviceFd, &event, sizeof(input_event)) < 0) { |
| 205 | std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16 |
| 206 | " with value %" PRId32 " : %s", |
| 207 | type, code, value, strerror(errno)); |
| 208 | ALOGE("%s", msg.c_str()); |
| 209 | ADD_FAILURE() << msg.c_str(); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | /** |
| 214 | * Ensure that input_events are generated with monotonic clock. |
| 215 | * That means input_event should receive a timestamp that is in the future of the time |
| 216 | * before the event was sent. |
| 217 | * Input system uses CLOCK_MONOTONIC everywhere in the code base. |
| 218 | */ |
| 219 | TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) { |
| 220 | nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC); |
| 221 | // key press |
| 222 | sendEvent(EV_KEY, KEY_HOME, 1); |
| 223 | sendEvent(EV_SYN, SYN_REPORT, 0); |
| 224 | |
| 225 | // key release |
| 226 | sendEvent(EV_KEY, KEY_HOME, 0); |
| 227 | sendEvent(EV_SYN, SYN_REPORT, 0); |
| 228 | |
| 229 | std::vector<RawEvent> events = getEvents(); |
| 230 | ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events"; |
| 231 | for (const RawEvent& event : events) { |
| 232 | // Cannot use strict comparison because the events may happen too quickly |
| 233 | ASSERT_LE(lastEventTime, event.when) << "Event must have occurred after the key was sent"; |
| 234 | ASSERT_LT(std::chrono::nanoseconds(event.when - lastEventTime), 100ms) |
| 235 | << "Event times are too far apart"; |
| 236 | lastEventTime = event.when; // Ensure all returned events are monotonic |
| 237 | } |
| 238 | } |