blob: fa149dba0553857c57b84f28d72cb19e930c861c [file] [log] [blame]
Siarhei Vishniakouf2652122021-03-05 21:39:46 +00001/*
2 * Copyright (C) 2021 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 "../dispatcher/LatencyTracker.h"
18
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000019#include <android-base/properties.h>
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000020#include <binder/Binder.h>
21#include <gtest/gtest.h>
22#include <inttypes.h>
23#include <log/log.h>
24
25#define TAG "LatencyTracker_test"
26
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000027using android::base::HwTimeoutMultiplier;
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000028using android::inputdispatcher::InputEventTimeline;
29using android::inputdispatcher::LatencyTracker;
30
31namespace android::inputdispatcher {
32
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000033const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
34 android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
35 HwTimeoutMultiplier());
36
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000037InputEventTimeline getTestTimeline() {
38 InputEventTimeline t(
Harry Cutts33476232023-01-30 19:57:29 +000039 /*isDown=*/true,
40 /*eventTime=*/2,
41 /*readTime=*/3);
42 ConnectionTimeline expectedCT(/*deliveryTime=*/6, /*consumeTime=*/7, /*finishTime=*/8);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000043 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
44 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
45 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10;
46 expectedCT.setGraphicsTimeline(std::move(graphicsTimeline));
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070047 t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT));
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000048 return t;
49}
50
51// --- LatencyTrackerTest ---
52class LatencyTrackerTest : public testing::Test, public InputEventTimelineProcessor {
53protected:
54 std::unique_ptr<LatencyTracker> mTracker;
55 sp<IBinder> connection1;
56 sp<IBinder> connection2;
57
58 void SetUp() override {
Siarhei Vishniakouaed7ad02022-08-03 15:04:33 -070059 connection1 = sp<BBinder>::make();
60 connection2 = sp<BBinder>::make();
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000061
62 mTracker = std::make_unique<LatencyTracker>(this);
63 }
64 void TearDown() override {}
65
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000066 void triggerEventReporting(nsecs_t lastEventTime);
67
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000068 void assertReceivedTimeline(const InputEventTimeline& timeline);
69 /**
70 * Timelines can be received in any order (order is not guaranteed). So if we are expecting more
71 * than 1 timeline, use this function to check that the set of received timelines matches
72 * what we expected.
73 */
74 void assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines);
75
76private:
77 void processTimeline(const InputEventTimeline& timeline) override {
78 mReceivedTimelines.push_back(timeline);
79 }
80 std::deque<InputEventTimeline> mReceivedTimelines;
81};
82
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000083/**
84 * Send an event that would trigger the reporting of all of the events that are at least as old as
85 * the provided 'lastEventTime'.
86 */
87void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
88 const nsecs_t triggerEventTime =
89 lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
Harry Cutts33476232023-01-30 19:57:29 +000090 mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/true, triggerEventTime,
91 /*readTime=*/3);
Siarhei Vishniakou363e7292021-07-09 03:22:42 +000092}
93
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000094void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
Siarhei Vishniakouf2652122021-03-05 21:39:46 +000095 ASSERT_FALSE(mReceivedTimelines.empty());
96 const InputEventTimeline& t = mReceivedTimelines.front();
97 ASSERT_EQ(timeline, t);
98 mReceivedTimelines.pop_front();
99}
100
101/**
102 * We are essentially comparing two multisets, but without constructing them.
103 * This comparison is inefficient, but it avoids having to construct a set, and also avoids the
104 * declaration of copy constructor for ConnectionTimeline.
105 * We ensure that collections A and B have the same size, that for every element in A, there is an
106 * equal element in B, and for every element in B there is an equal element in A.
107 */
108void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000109 ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
110 for (const InputEventTimeline& expectedTimeline : timelines) {
111 bool found = false;
112 for (const InputEventTimeline& receivedTimeline : mReceivedTimelines) {
113 if (receivedTimeline == expectedTimeline) {
114 found = true;
115 break;
116 }
117 }
118 ASSERT_TRUE(found) << "Could not find expected timeline with eventTime="
119 << expectedTimeline.eventTime;
120 }
121 for (const InputEventTimeline& receivedTimeline : mReceivedTimelines) {
122 bool found = false;
123 for (const InputEventTimeline& expectedTimeline : timelines) {
124 if (receivedTimeline == expectedTimeline) {
125 found = true;
126 break;
127 }
128 }
129 ASSERT_TRUE(found) << "Could not find received timeline with eventTime="
130 << receivedTimeline.eventTime;
131 }
132 mReceivedTimelines.clear();
133}
134
135/**
136 * Ensure that calling 'trackListener' in isolation only creates an inputflinger timeline, without
137 * any additional ConnectionTimeline's.
138 */
139TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
Harry Cutts33476232023-01-30 19:57:29 +0000140 mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/false, /*eventTime=*/2,
141 /*readTime=*/3);
142 triggerEventReporting(/*eventTime=*/2);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000143 assertReceivedTimeline(InputEventTimeline{false, 2, 3});
144}
145
146/**
147 * A single call to trackFinishedEvent should not cause a timeline to be reported.
148 */
149TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
Harry Cutts33476232023-01-30 19:57:29 +0000150 mTracker->trackFinishedEvent(/*inputEventId=*/1, connection1, /*deliveryTime=*/2,
151 /*consumeTime=*/3, /*finishTime=*/4);
152 triggerEventReporting(/*eventTime=*/4);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000153 assertReceivedTimelines({});
154}
155
156/**
157 * A single call to trackGraphicsLatency should not cause a timeline to be reported.
158 */
159TEST_F(LatencyTrackerTest, TrackGraphicsLatency_DoesNotTriggerReporting) {
160 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
161 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
162 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
Harry Cutts33476232023-01-30 19:57:29 +0000163 mTracker->trackGraphicsLatency(/*inputEventId=*/1, connection2, graphicsTimeline);
164 triggerEventReporting(/*eventTime=*/3);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000165 assertReceivedTimelines({});
166}
167
168TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) {
169 constexpr int32_t inputEventId = 1;
170 InputEventTimeline expected = getTestTimeline();
171
172 const auto& [connectionToken, expectedCT] = *expected.connectionTimelines.begin();
173
174 mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
175 mTracker->trackFinishedEvent(inputEventId, connectionToken, expectedCT.deliveryTime,
176 expectedCT.consumeTime, expectedCT.finishTime);
177 mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
178
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000179 triggerEventReporting(expected.eventTime);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000180 assertReceivedTimeline(expected);
181}
182
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000183/**
184 * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
185 * and that the tracker drops such events completely.
186 */
187TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
188 constexpr nsecs_t inputEventId = 1;
189 constexpr nsecs_t readTime = 3; // does not matter for this test
190 constexpr bool isDown = true; // does not matter for this test
191
192 // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
193 // are different.
Harry Cutts33476232023-01-30 19:57:29 +0000194 mTracker->trackListener(inputEventId, isDown, /*eventTime=*/1, readTime);
195 mTracker->trackListener(inputEventId, isDown, /*eventTime=*/2, readTime);
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000196
Harry Cutts33476232023-01-30 19:57:29 +0000197 triggerEventReporting(/*eventTime=*/2);
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000198 // Since we sent duplicate input events, the tracker should just delete all of them, because it
199 // does not have enough information to properly track them.
200 assertReceivedTimelines({});
201}
202
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000203TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
204 constexpr int32_t inputEventId1 = 1;
205 InputEventTimeline timeline1(
206 /*isDown*/ true,
207 /*eventTime*/ 2,
208 /*readTime*/ 3);
209 timeline1.connectionTimelines.emplace(connection1,
210 ConnectionTimeline(/*deliveryTime*/ 6, /*consumeTime*/ 7,
211 /*finishTime*/ 8));
212 ConnectionTimeline& connectionTimeline1 = timeline1.connectionTimelines.begin()->second;
213 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline1;
214 graphicsTimeline1[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
215 graphicsTimeline1[GraphicsTimeline::PRESENT_TIME] = 10;
216 connectionTimeline1.setGraphicsTimeline(std::move(graphicsTimeline1));
217
218 constexpr int32_t inputEventId2 = 10;
219 InputEventTimeline timeline2(
Harry Cutts33476232023-01-30 19:57:29 +0000220 /*isDown=*/false,
221 /*eventTime=*/20,
222 /*readTime=*/30);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000223 timeline2.connectionTimelines.emplace(connection2,
Harry Cutts33476232023-01-30 19:57:29 +0000224 ConnectionTimeline(/*deliveryTime=*/60,
225 /*consumeTime=*/70,
226 /*finishTime=*/80));
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000227 ConnectionTimeline& connectionTimeline2 = timeline2.connectionTimelines.begin()->second;
228 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline2;
229 graphicsTimeline2[GraphicsTimeline::GPU_COMPLETED_TIME] = 90;
230 graphicsTimeline2[GraphicsTimeline::PRESENT_TIME] = 100;
231 connectionTimeline2.setGraphicsTimeline(std::move(graphicsTimeline2));
232
233 // Start processing first event
234 mTracker->trackListener(inputEventId1, timeline1.isDown, timeline1.eventTime,
235 timeline1.readTime);
236 // Start processing second event
237 mTracker->trackListener(inputEventId2, timeline2.isDown, timeline2.eventTime,
238 timeline2.readTime);
239 mTracker->trackFinishedEvent(inputEventId1, connection1, connectionTimeline1.deliveryTime,
240 connectionTimeline1.consumeTime, connectionTimeline1.finishTime);
241
242 mTracker->trackFinishedEvent(inputEventId2, connection2, connectionTimeline2.deliveryTime,
243 connectionTimeline2.consumeTime, connectionTimeline2.finishTime);
244 mTracker->trackGraphicsLatency(inputEventId1, connection1,
245 connectionTimeline1.graphicsTimeline);
246 mTracker->trackGraphicsLatency(inputEventId2, connection2,
247 connectionTimeline2.graphicsTimeline);
248 // Now both events should be completed
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000249 triggerEventReporting(timeline2.eventTime);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000250 assertReceivedTimelines({timeline1, timeline2});
251}
252
253/**
254 * Check that LatencyTracker consistently tracks events even if there are many incomplete events.
255 */
256TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) {
257 InputEventTimeline timeline = getTestTimeline();
258 std::vector<InputEventTimeline> expectedTimelines;
259 const ConnectionTimeline& expectedCT = timeline.connectionTimelines.begin()->second;
260 const sp<IBinder>& token = timeline.connectionTimelines.begin()->first;
261
262 for (size_t i = 1; i <= 100; i++) {
Harry Cutts33476232023-01-30 19:57:29 +0000263 mTracker->trackListener(/*inputEventId=*/i, timeline.isDown, timeline.eventTime,
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000264 timeline.readTime);
265 expectedTimelines.push_back(
266 InputEventTimeline{timeline.isDown, timeline.eventTime, timeline.readTime});
267 }
268 // Now, complete the first event that was sent.
Harry Cutts33476232023-01-30 19:57:29 +0000269 mTracker->trackFinishedEvent(/*inputEventId=*/1, token, expectedCT.deliveryTime,
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000270 expectedCT.consumeTime, expectedCT.finishTime);
Harry Cutts33476232023-01-30 19:57:29 +0000271 mTracker->trackGraphicsLatency(/*inputEventId=*/1, token, expectedCT.graphicsTimeline);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000272
273 expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000274 triggerEventReporting(timeline.eventTime);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000275 assertReceivedTimelines(expectedTimelines);
276}
277
278/**
279 * For simplicity of the implementation, LatencyTracker only starts tracking an event when
280 * 'trackListener' is invoked.
281 * Both 'trackFinishedEvent' and 'trackGraphicsLatency' should not start a new event.
282 * If they are received before 'trackListener' (which should not be possible), they are ignored.
283 */
284TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) {
285 constexpr int32_t inputEventId = 1;
286 InputEventTimeline expected = getTestTimeline();
287 const ConnectionTimeline& expectedCT = expected.connectionTimelines.begin()->second;
288 mTracker->trackFinishedEvent(inputEventId, connection1, expectedCT.deliveryTime,
289 expectedCT.consumeTime, expectedCT.finishTime);
290 mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
291
292 mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
Siarhei Vishniakou363e7292021-07-09 03:22:42 +0000293 triggerEventReporting(expected.eventTime);
Siarhei Vishniakouf2652122021-03-05 21:39:46 +0000294 assertReceivedTimeline(
295 InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
296}
297
298} // namespace android::inputdispatcher