Pass latency information from app to input
Once the app learns about the frame's timeline, it will tell
inputdispatcher about it. We are adding a new callback similar to
'finishInputEvent', called 'reportLatencyInfo'.
This will tell inputdispatcher about the queue time and the present time
of each frame that was caused by input.
InputDispatcher will then be able to reconstruct the input event
timeline and report the end-to-end latency metrics.
In a separate CL, we will add LatencyTracker, which will eventually
receive this data.
Using the event id and the provided queue time and present time, we will
be able to reconstruct the end-to-end latency inside LatencyTracker.
Bug: 167947340
Test: atest inputflinger_tests libinput_tests
Change-Id: I181532a01b34eecd186bc3c74db289fc59c5955c
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 397a9d7..de7acf9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3290,15 +3290,21 @@
bool gotOne = false;
status_t status = OK;
for (;;) {
- Result<InputPublisher::Finished> result =
- connection->inputPublisher.receiveFinishedSignal();
+ Result<InputPublisher::ConsumerResponse> result =
+ connection->inputPublisher.receiveConsumerResponse();
if (!result.ok()) {
status = result.error().code();
break;
}
- const InputPublisher::Finished& finished = *result;
- d->finishDispatchCycleLocked(currentTime, connection, finished.seq,
- finished.handled, finished.consumeTime);
+
+ if (std::holds_alternative<InputPublisher::Finished>(*result)) {
+ const InputPublisher::Finished& finish =
+ std::get<InputPublisher::Finished>(*result);
+ d->finishDispatchCycleLocked(currentTime, connection, finish.seq,
+ finish.handled, finish.consumeTime);
+ } else if (std::holds_alternative<InputPublisher::Timeline>(*result)) {
+ // TODO(b/167947340): Report this data to LatencyTracker
+ }
gotOne = true;
}
if (gotOne) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index cedda6e..d1bd38e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -740,6 +740,11 @@
ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
}
+ void sendTimeline(int32_t inputEventId, std::array<nsecs_t, GraphicsTimeline::SIZE> timeline) {
+ const status_t status = mConsumer->sendTimeline(inputEventId, timeline);
+ ASSERT_EQ(OK, status);
+ }
+
void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
std::optional<int32_t> expectedDisplayId,
std::optional<int32_t> expectedFlags) {
@@ -1052,6 +1057,11 @@
mInputReceiver->finishEvent(sequenceNum);
}
+ void sendTimeline(int32_t inputEventId, std::array<nsecs_t, GraphicsTimeline::SIZE> timeline) {
+ ASSERT_NE(mInputReceiver, nullptr) << "Invalid receive event on window with no receiver";
+ mInputReceiver->sendTimeline(inputEventId, timeline);
+ }
+
InputEvent* consume() {
if (mInputReceiver == nullptr) {
return nullptr;
@@ -1954,6 +1964,21 @@
secondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
+ graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
+
+ window->sendTimeline(1 /*inputEventId*/, graphicsTimeline);
+ window->assertNoEvents();
+ mDispatcher->waitForIdle();
+}
+
class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,