Add InputChannel::waitForMessage and use it in EndToEndNativeInputTest
The EndToEndNativeInputTest::waitForEventAvailable(timeoutMs) is similar
in implementation to InputChannel::probablyHasInput(), but can stop
after a timeout.
Add InputChannel::waitForMessage(std::chrono::milliseconds timeout) for
use in tests and use it to replace the waitForEventAvailable().
The difference of the new method from probablyHasInput() is that the
latter does not get repeated (because it is not necessary to implement
the hint). Repeating happens only on EINTR to allow tests to return
before timeout expiration when there are problems with the channel
setup. In the end the implementations are rather different.
Bug: b/314973388
Test: atest frameworks/native/libs/gui/tests/EndToEndNativeInputTest.cpp
Test: atest InputPublisherAndConsumerTest
Change-Id: I806aad14e4fba223a5cbbe49cea862f9b8279f24
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 598f949..e63b8f0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -521,11 +521,11 @@
bool InputChannel::probablyHasInput() const {
struct pollfd pfds = {.fd = mFd, .events = POLLIN};
if (::poll(&pfds, /*nfds=*/1, /*timeout=*/0) <= 0) {
- // This can be a false negative because EAGAIN and ENOMEM are not handled. The latter should
- // be extremely rare. The EAGAIN is also unlikely because it happens only when the signal
- // arrives while the syscall is executed, and the syscall is quick. Hitting EAGAIN too often
+ // This can be a false negative because EINTR and ENOMEM are not handled. The latter should
+ // be extremely rare. The EINTR is also unlikely because it happens only when the signal
+ // arrives while the syscall is executed, and the syscall is quick. Hitting EINTR too often
// would be a sign of having too many signals, which is a bigger performance problem. A
- // common tradition is to repeat the syscall on each EAGAIN, but it is not necessary here.
+ // common tradition is to repeat the syscall on each EINTR, but it is not necessary here.
// In other words, the missing one liner is replaced by a multiline explanation.
return false;
}
@@ -534,6 +534,22 @@
return (pfds.revents & POLLIN) != 0;
}
+void InputChannel::waitForMessage(std::chrono::milliseconds timeout) const {
+ if (timeout < 0ms) {
+ LOG(FATAL) << "Timeout cannot be negative, received " << timeout.count();
+ }
+ struct pollfd pfds = {.fd = mFd, .events = POLLIN};
+ int ret;
+ std::chrono::time_point<std::chrono::steady_clock> stopTime =
+ std::chrono::steady_clock::now() + timeout;
+ std::chrono::milliseconds remaining = timeout;
+ do {
+ ret = ::poll(&pfds, /*nfds=*/1, /*timeout=*/remaining.count());
+ remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
+ stopTime - std::chrono::steady_clock::now());
+ } while (ret == -1 && errno == EINTR && remaining > 0ms);
+}
+
std::unique_ptr<InputChannel> InputChannel::dup() const {
base::unique_fd newFd(dupFd());
return InputChannel::create(getName(), std::move(newFd), getConnectionToken());