| /* | 
 |  * Copyright (C) 2019 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "EventHub.h" | 
 |  | 
 | #include "UinputDevice.h" | 
 |  | 
 | #include <gtest/gtest.h> | 
 | #include <inttypes.h> | 
 | #include <linux/uinput.h> | 
 | #include <log/log.h> | 
 | #include <chrono> | 
 |  | 
 | #define TAG "EventHub_test" | 
 |  | 
 | using android::createUinputDevice; | 
 | using android::EventHub; | 
 | using android::EventHubInterface; | 
 | using android::InputDeviceIdentifier; | 
 | using android::RawEvent; | 
 | using android::sp; | 
 | using android::UinputHomeKey; | 
 | using std::chrono_literals::operator""ms; | 
 | using std::chrono_literals::operator""s; | 
 |  | 
 | static constexpr bool DEBUG = false; | 
 |  | 
 | static void dumpEvents(const std::vector<RawEvent>& events) { | 
 |     for (const RawEvent& event : events) { | 
 |         if (event.type >= EventHubInterface::FIRST_SYNTHETIC_EVENT) { | 
 |             switch (event.type) { | 
 |                 case EventHubInterface::DEVICE_ADDED: | 
 |                     ALOGI("Device added: %i", event.deviceId); | 
 |                     break; | 
 |                 case EventHubInterface::DEVICE_REMOVED: | 
 |                     ALOGI("Device removed: %i", event.deviceId); | 
 |                     break; | 
 |                 case EventHubInterface::FINISHED_DEVICE_SCAN: | 
 |                     ALOGI("Finished device scan."); | 
 |                     break; | 
 |             } | 
 |         } else { | 
 |             ALOGI("Device %" PRId32 " : time = %" PRId64 ", type %i, code %i, value %i", | 
 |                   event.deviceId, event.when, event.type, event.code, event.value); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | // --- EventHubTest --- | 
 | class EventHubTest : public testing::Test { | 
 | protected: | 
 |     std::unique_ptr<EventHubInterface> mEventHub; | 
 |     // We are only going to emulate a single input device currently. | 
 |     std::unique_ptr<UinputHomeKey> mKeyboard; | 
 |     int32_t mDeviceId; | 
 |  | 
 |     virtual void SetUp() override { | 
 |         mEventHub = std::make_unique<EventHub>(); | 
 |         consumeInitialDeviceAddedEvents(); | 
 |         mKeyboard = createUinputDevice<UinputHomeKey>(); | 
 |         ASSERT_NO_FATAL_FAILURE(mDeviceId = waitForDeviceCreation()); | 
 |     } | 
 |     virtual void TearDown() override { | 
 |         mKeyboard.reset(); | 
 |         waitForDeviceClose(mDeviceId); | 
 |         assertNoMoreEvents(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Return the device id of the created device. | 
 |      */ | 
 |     int32_t waitForDeviceCreation(); | 
 |     void waitForDeviceClose(int32_t deviceId); | 
 |     void consumeInitialDeviceAddedEvents(); | 
 |     void assertNoMoreEvents(); | 
 |     /** | 
 |      * Read events from the EventHub. | 
 |      * | 
 |      * If expectedEvents is set, wait for a significant period of time to try and ensure that | 
 |      * the expected number of events has been read. The number of returned events | 
 |      * may be smaller (if timeout has been reached) or larger than expectedEvents. | 
 |      * | 
 |      * If expectedEvents is not set, return all of the immediately available events. | 
 |      */ | 
 |     std::vector<RawEvent> getEvents(std::optional<size_t> expectedEvents = std::nullopt); | 
 | }; | 
 |  | 
 | std::vector<RawEvent> EventHubTest::getEvents(std::optional<size_t> expectedEvents) { | 
 |     static constexpr size_t EVENT_BUFFER_SIZE = 256; | 
 |     std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer; | 
 |     std::vector<RawEvent> events; | 
 |  | 
 |     while (true) { | 
 |         std::chrono::milliseconds timeout = 0s; | 
 |         if (expectedEvents) { | 
 |             timeout = 2s; | 
 |         } | 
 |         const size_t count = | 
 |                 mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size()); | 
 |         if (count == 0) { | 
 |             break; | 
 |         } | 
 |         events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count); | 
 |         if (expectedEvents && events.size() >= *expectedEvents) { | 
 |             break; | 
 |         } | 
 |     } | 
 |     if (DEBUG) { | 
 |         dumpEvents(events); | 
 |     } | 
 |     return events; | 
 | } | 
 |  | 
 | /** | 
 |  * Since the test runs on a real platform, there will be existing devices | 
 |  * in addition to the test devices being added. Therefore, when EventHub is first created, | 
 |  * it will return a lot of "device added" type of events. | 
 |  */ | 
 | void EventHubTest::consumeInitialDeviceAddedEvents() { | 
 |     std::vector<RawEvent> events = getEvents(); | 
 |     std::set<int32_t /*deviceId*/> existingDevices; | 
 |     // All of the events should be DEVICE_ADDED type, except the last one. | 
 |     for (size_t i = 0; i < events.size() - 1; i++) { | 
 |         const RawEvent& event = events[i]; | 
 |         EXPECT_EQ(EventHubInterface::DEVICE_ADDED, event.type); | 
 |         existingDevices.insert(event.deviceId); | 
 |     } | 
 |     // None of the existing system devices should be changing while this test is run. | 
 |     // Check that the returned device ids are unique for all of the existing devices. | 
 |     EXPECT_EQ(existingDevices.size(), events.size() - 1); | 
 |     // The last event should be "finished device scan" | 
 |     EXPECT_EQ(EventHubInterface::FINISHED_DEVICE_SCAN, events[events.size() - 1].type); | 
 | } | 
 |  | 
 | int32_t EventHubTest::waitForDeviceCreation() { | 
 |     // Wait a little longer than usual, to ensure input device has time to be created | 
 |     std::vector<RawEvent> events = getEvents(2); | 
 |     if (events.size() != 2) { | 
 |         ADD_FAILURE() << "Instead of 2 events, received " << events.size(); | 
 |         return 0; // this value is unused | 
 |     } | 
 |     const RawEvent& deviceAddedEvent = events[0]; | 
 |     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type); | 
 |     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId); | 
 |     const int32_t deviceId = deviceAddedEvent.deviceId; | 
 |     EXPECT_EQ(identifier.name, mKeyboard->getName()); | 
 |     const RawEvent& finishedDeviceScanEvent = events[1]; | 
 |     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN), | 
 |               finishedDeviceScanEvent.type); | 
 |     return deviceId; | 
 | } | 
 |  | 
 | void EventHubTest::waitForDeviceClose(int32_t deviceId) { | 
 |     std::vector<RawEvent> events = getEvents(2); | 
 |     ASSERT_EQ(2U, events.size()); | 
 |     const RawEvent& deviceRemovedEvent = events[0]; | 
 |     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_REMOVED), deviceRemovedEvent.type); | 
 |     EXPECT_EQ(deviceId, deviceRemovedEvent.deviceId); | 
 |     const RawEvent& finishedDeviceScanEvent = events[1]; | 
 |     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN), | 
 |               finishedDeviceScanEvent.type); | 
 | } | 
 |  | 
 | void EventHubTest::assertNoMoreEvents() { | 
 |     std::vector<RawEvent> events = getEvents(); | 
 |     ASSERT_TRUE(events.empty()); | 
 | } | 
 |  | 
 | /** | 
 |  * Ensure that input_events are generated with monotonic clock. | 
 |  * That means input_event should receive a timestamp that is in the future of the time | 
 |  * before the event was sent. | 
 |  * Input system uses CLOCK_MONOTONIC everywhere in the code base. | 
 |  */ | 
 | TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) { | 
 |     nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC); | 
 |     ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey()); | 
 |  | 
 |     std::vector<RawEvent> events = getEvents(4); | 
 |     ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events"; | 
 |     for (const RawEvent& event : events) { | 
 |         // Cannot use strict comparison because the events may happen too quickly | 
 |         ASSERT_LE(lastEventTime, event.when) << "Event must have occurred after the key was sent"; | 
 |         ASSERT_LT(std::chrono::nanoseconds(event.when - lastEventTime), 100ms) | 
 |                 << "Event times are too far apart"; | 
 |         lastEventTime = event.when; // Ensure all returned events are monotonic | 
 |     } | 
 | } |