Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5b5e45e authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Wait longer for expected input events

Sometimes, a device can be slow. That means, some events take a long
time to process, especially if they involve kernel processing these from
userspace and sending them back to userspace.

When the input device is being added or removed, we are currently not
waiting long enough to be notified. The test currently fails because the
input device added notification never arrived.

It turns out there are 2 cases where we are currently waiting for an
input event from eventhub:
1) When we know how many events we expect, and we don't care how long
they will take. We are willing to wait for a long time, because we know
they will come eventually. When we got the expected number of events, we
can stop waiting for more
2) When we have no idea how many events to expect, and we don't want to
wait - we just need to take all immediately available.

To account for the 2 (and only the 2 cases above), refactor
EventHub_test to wait for a specific number of events instead of a
timeout. If no expected number of events is provided, read all
immediately available ones without a limit.

This change also makes the test ~ 50% faster, because we are now
stopping the wait after we have received the expected number of events.

Bug: 149155998
Test: /data/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter=*EventHubTest* --gtest_repeat=1000
Change-Id: I732c14c09567e9231bcc83141368b1614805f9ac
parent 34560b6d
Loading
Loading
Loading
Loading
+36 −9
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ 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;

@@ -70,11 +71,12 @@ protected:
        mEventHub = std::make_unique<EventHub>();
        consumeInitialDeviceAddedEvents();
        mKeyboard = createUinputDevice<UinputHomeKey>();
        mDeviceId = waitForDeviceCreation();
        ASSERT_NO_FATAL_FAILURE(mDeviceId = waitForDeviceCreation());
    }
    virtual void TearDown() override {
        mKeyboard.reset();
        waitForDeviceClose(mDeviceId);
        assertNoMoreEvents();
    }

    /**
@@ -83,21 +85,38 @@ protected:
    int32_t waitForDeviceCreation();
    void waitForDeviceClose(int32_t deviceId);
    void consumeInitialDeviceAddedEvents();
    std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
    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::chrono::milliseconds timeout) {
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) {
        size_t count =
        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);
@@ -111,7 +130,7 @@ std::vector<RawEvent> EventHubTest::getEvents(std::chrono::milliseconds timeout)
 * it will return a lot of "device added" type of events.
 */
void EventHubTest::consumeInitialDeviceAddedEvents() {
    std::vector<RawEvent> events = getEvents(0ms);
    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++) {
@@ -128,8 +147,11 @@ void EventHubTest::consumeInitialDeviceAddedEvents() {

int32_t EventHubTest::waitForDeviceCreation() {
    // Wait a little longer than usual, to ensure input device has time to be created
    std::vector<RawEvent> events = getEvents(20ms);
    EXPECT_EQ(2U, events.size()); // Using "expect" because the function is non-void.
    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);
@@ -142,7 +164,7 @@ int32_t EventHubTest::waitForDeviceCreation() {
}

void EventHubTest::waitForDeviceClose(int32_t deviceId) {
    std::vector<RawEvent> events = getEvents(20ms);
    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);
@@ -152,6 +174,11 @@ void EventHubTest::waitForDeviceClose(int32_t deviceId) {
              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
@@ -162,7 +189,7 @@ TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) {
    nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
    ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey());

    std::vector<RawEvent> events = getEvents();
    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
+27 −29
Original line number Diff line number Diff line
@@ -44,9 +44,7 @@ void UinputDevice::init() {
    device.id.product = 0x01;
    device.id.version = 1;

    // Using EXPECT instead of ASSERT to allow the device creation to continue even when
    // some failures are reported when configuring the device.
    EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
    ASSERT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));

    if (write(mDeviceFd, &device, sizeof(device)) < 0) {
        FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
@@ -70,7 +68,7 @@ void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
                                             " with value %" PRId32 " : %s",
                                             type, code, value, strerror(errno));
        ALOGE("%s", msg.c_str());
        ADD_FAILURE() << msg.c_str();
        FAIL() << msg.c_str();
    }
}

@@ -82,41 +80,41 @@ UinputKeyboard::UinputKeyboard(std::initializer_list<int> keys)
void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
    // enable key press/release event
    if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) {
        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
        FAIL() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
    }

    // enable set of KEY events
    std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) {
        if (ioctl(fd, UI_SET_KEYBIT, key)) {
            ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
            FAIL() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
        }
    });

    // enable synchronization event
    if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) {
        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
        FAIL() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
    }
}

void UinputKeyboard::pressKey(int key) {
    if (mKeys.find(key) == mKeys.end()) {
        ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key;
        FAIL() << mName << ": Cannot inject key press: Key not found: " << key;
    }
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_KEY, key, 1);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

void UinputKeyboard::releaseKey(int key) {
    if (mKeys.find(key) == mKeys.end()) {
        ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key;
        FAIL() << mName << ": Cannot inject key release: Key not found: " << key;
    }
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_KEY, key, 0);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

void UinputKeyboard::pressAndReleaseKey(int key) {
    EXPECT_NO_FATAL_FAILURE(pressKey(key));
    EXPECT_NO_FATAL_FAILURE(releaseKey(key));
    pressKey(key);
    releaseKey(key);
}

// --- UinputHomeKey ---
@@ -124,7 +122,7 @@ void UinputKeyboard::pressAndReleaseKey(int key) {
UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}

void UinputHomeKey::pressAndReleaseHomeKey() {
    EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
    pressAndReleaseKey(KEY_HOME);
}

// --- UinputTouchScreen ---
@@ -158,35 +156,35 @@ void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) {
}

void UinputTouchScreen::sendSlot(int32_t slot) {
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_SLOT, slot));
    injectEvent(EV_ABS, ABS_MT_SLOT, slot);
}

void UinputTouchScreen::sendTrackingId(int32_t trackingId) {
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId));
    injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId);
}

void UinputTouchScreen::sendDown(const Point& point) {
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 1));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_KEY, BTN_TOUCH, 1);
    injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
    injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

void UinputTouchScreen::sendMove(const Point& point) {
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
    injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

void UinputTouchScreen::sendUp() {
    sendTrackingId(0xffffffff);
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 0));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_KEY, BTN_TOUCH, 0);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

void UinputTouchScreen::sendToolType(int32_t toolType) {
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType));
    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
    injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType);
    injectEvent(EV_SYN, SYN_REPORT, 0);
}

// Get the center x, y base on the range definition.